Skip to content

Commit 5475d24

Browse files
committed
Merge pull request #1068 from hashicorp/f-node-drain-self
Add -self flag to node-drain
2 parents ba55c83 + e6e3225 commit 5475d24

File tree

5 files changed

+82
-34
lines changed

5 files changed

+82
-34
lines changed

command/helpers.go

+24
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package command
22

33
import (
4+
"fmt"
45
"time"
56

7+
"github.com/hashicorp/nomad/api"
68
"github.com/ryanuber/columnize"
79
)
810

@@ -45,3 +47,25 @@ func limit(s string, length int) string {
4547
func formatTime(t time.Time) string {
4648
return t.Format("02/01/06 15:04:05 MST")
4749
}
50+
51+
// getLocalNodeID returns the node ID of the local Nomad Client and an error if
52+
// it couldn't be determined or the Agent is not running in Client mode.
53+
func getLocalNodeID(client *api.Client) (string, error) {
54+
info, err := client.Agent().Self()
55+
if err != nil {
56+
return "", fmt.Errorf("Error querying agent info: %s", err)
57+
}
58+
var stats map[string]interface{}
59+
stats, _ = info["stats"]
60+
clientStats, ok := stats["client"].(map[string]interface{})
61+
if !ok {
62+
return "", fmt.Errorf("Nomad not running in client mode")
63+
}
64+
65+
nodeID, ok := clientStats["node_id"].(string)
66+
if !ok {
67+
return "", fmt.Errorf("Failed to determine node ID")
68+
}
69+
70+
return nodeID, nil
71+
}

command/helpers_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package command
22

33
import (
44
"testing"
5+
6+
"github.com/mitchellh/cli"
57
)
68

79
func TestHelpers_FormatKV(t *testing.T) {
@@ -27,3 +29,19 @@ func TestHelpers_FormatList(t *testing.T) {
2729
t.Fatalf("expect: %s, got: %s", expect, out)
2830
}
2931
}
32+
33+
func TestHelpers_NodeID(t *testing.T) {
34+
srv, _, _ := testServer(t, nil)
35+
defer srv.Stop()
36+
37+
meta := Meta{Ui: new(cli.MockUi)}
38+
client, err := meta.Client()
39+
if err != nil {
40+
t.FailNow()
41+
}
42+
43+
// This is because there is no client
44+
if _, err := getLocalNodeID(client); err == nil {
45+
t.Fatalf("getLocalNodeID() should fail")
46+
}
47+
}

command/node_drain.go

+19-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Usage: nomad node-drain [options] <node>
1515
1616
Toggles node draining on a specified node. It is required
1717
that either -enable or -disable is specified, but not both.
18+
The -self flag is useful to drain the local node.
1819
1920
General Options:
2021
@@ -28,6 +29,9 @@ Node Drain Options:
2829
-enable
2930
Enable draining for the specified node.
3031
32+
-self
33+
Query the status of the local node.
34+
3135
-yes
3236
Automatic yes to prompts.
3337
`
@@ -39,12 +43,13 @@ func (c *NodeDrainCommand) Synopsis() string {
3943
}
4044

4145
func (c *NodeDrainCommand) Run(args []string) int {
42-
var enable, disable, autoYes bool
46+
var enable, disable, self, autoYes bool
4347

4448
flags := c.Meta.FlagSet("node-drain", FlagSetClient)
4549
flags.Usage = func() { c.Ui.Output(c.Help()) }
4650
flags.BoolVar(&enable, "enable", false, "Enable drain mode")
4751
flags.BoolVar(&disable, "disable", false, "Disable drain mode")
52+
flags.BoolVar(&self, "self", false, "")
4853
flags.BoolVar(&autoYes, "yes", false, "Automatic yes to prompts.")
4954

5055
if err := flags.Parse(args); err != nil {
@@ -59,11 +64,10 @@ func (c *NodeDrainCommand) Run(args []string) int {
5964

6065
// Check that we got a node ID
6166
args = flags.Args()
62-
if len(args) != 1 {
67+
if l := len(args); self && l != 0 || !self && l != 1 {
6368
c.Ui.Error(c.Help())
6469
return 1
6570
}
66-
nodeID := args[0]
6771

6872
// Get the HTTP client
6973
client, err := c.Meta.Client()
@@ -72,6 +76,18 @@ func (c *NodeDrainCommand) Run(args []string) int {
7276
return 1
7377
}
7478

79+
// If -self flag is set then determine the current node.
80+
nodeID := ""
81+
if !self {
82+
nodeID = args[0]
83+
} else {
84+
var err error
85+
if nodeID, err = getLocalNodeID(client); err != nil {
86+
c.Ui.Error(err.Error())
87+
return 1
88+
}
89+
}
90+
7591
// Check if node exists
7692
if len(nodeID) == 1 {
7793
c.Ui.Error(fmt.Sprintf("Identifier must contain at least two characters."))
@@ -83,7 +99,6 @@ func (c *NodeDrainCommand) Run(args []string) int {
8399
nodeID = nodeID[:len(nodeID)-1]
84100
}
85101

86-
// Exact lookup failed, try with prefix based search
87102
nodes, _, err := client.Nodes().PrefixList(nodeID)
88103
if err != nil {
89104
c.Ui.Error(fmt.Sprintf("Error toggling drain mode: %s", err))

command/node_status.go

+7-25
Original file line numberDiff line numberDiff line change
@@ -85,30 +85,6 @@ func (c *NodeStatusCommand) Run(args []string) int {
8585
return 1
8686
}
8787

88-
// If -self flag is set then determine the current node.
89-
nodeID := ""
90-
if self {
91-
info, err := client.Agent().Self()
92-
if err != nil {
93-
c.Ui.Error(fmt.Sprintf("Error querying agent info: %s", err))
94-
return 1
95-
}
96-
var stats map[string]interface{}
97-
stats, _ = info["stats"]
98-
clientStats, ok := stats["client"].(map[string]interface{})
99-
if !ok {
100-
c.Ui.Error("Nomad not running in client mode")
101-
return 1
102-
}
103-
104-
nodeID, ok = clientStats["node_id"].(string)
105-
if !ok {
106-
c.Ui.Error("Failed to determine node ID")
107-
return 1
108-
}
109-
110-
}
111-
11288
// Use list mode if no node name was provided
11389
if len(args) == 0 && !self {
11490
// Query the node info
@@ -162,8 +138,15 @@ func (c *NodeStatusCommand) Run(args []string) int {
162138
}
163139

164140
// Query the specific node
141+
nodeID := ""
165142
if !self {
166143
nodeID = args[0]
144+
} else {
145+
var err error
146+
if nodeID, err = getLocalNodeID(client); err != nil {
147+
c.Ui.Error(err.Error())
148+
return 1
149+
}
167150
}
168151
if len(nodeID) == 1 {
169152
c.Ui.Error(fmt.Sprintf("Identifier must contain at least two characters."))
@@ -175,7 +158,6 @@ func (c *NodeStatusCommand) Run(args []string) int {
175158
nodeID = nodeID[:len(nodeID)-1]
176159
}
177160

178-
// Exact lookup failed, try with prefix based search
179161
nodes, _, err := client.Nodes().PrefixList(nodeID)
180162
if err != nil {
181163
c.Ui.Error(fmt.Sprintf("Error querying node info: %s", err))

website/source/docs/commands/node-drain.html.md.erb

+14-5
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ nicely by providing the current drain status of a given node.
2121
nomad node-drain [options] <node>
2222
```
2323

24-
A node ID or prefix must be provided. If there is an exact match, the
25-
drain mode will be adjusted for that node. Otherwise, a list of matching
26-
nodes and information will be displayed.
24+
A `-self` flag can be used to drain the local node. If this is not supplied, a
25+
node ID or prefix must be provided. If there is an exact match, the drain mode
26+
will be adjusted for that node. Otherwise, a list of matching nodes and
27+
information will be displayed.
2728

2829
It is also required to pass one of `-enable` or `-disable`, depending on which
2930
operation is desired.
@@ -36,11 +37,19 @@ operation is desired.
3637

3738
* `-enable`: Enable node drain mode.
3839
* `-disable`: Disable node drain mode.
40+
* `-self`: Drain the local node.
41+
* `-yes`: Automtic yes to prompts.
3942

4043
## Examples
4144

42-
Enable drain mode on node1:
45+
Enable drain mode on node with ID prefix "4d2ba53b":
4346

4447
```
45-
$ nomad node-drain -enable node1
48+
$ nomad node-drain -enable 4d2ba53b
49+
```
50+
51+
Enable drain mode on the local node:
52+
53+
```
54+
$ nomad node-drain -enable -self
4655
```

0 commit comments

Comments
 (0)