github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/command/node_eligibility.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/nomad/api/contexts" 8 "github.com/posener/complete" 9 ) 10 11 type NodeEligibilityCommand struct { 12 Meta 13 } 14 15 func (c *NodeEligibilityCommand) Help() string { 16 helpText := ` 17 Usage: nomad node eligibility [options] <node> 18 19 Toggles the nodes scheduling eligibility. When a node is marked as ineligible, 20 no new allocations will be placed on it but existing allocations will remain. 21 To remove existing allocations, use the node drain command. 22 23 It is required that either -enable or -disable is specified, but not both. 24 The -self flag is useful to set the scheduling eligibility of the local node. 25 26 If ACLs are enabled, this option requires a token with the 'node:write' 27 capability. 28 29 General Options: 30 31 ` + generalOptionsUsage(usageOptsDefault|usageOptsNoNamespace) + ` 32 33 Node Eligibility Options: 34 35 -disable 36 Mark the specified node as ineligible for new allocations. 37 38 -enable 39 Mark the specified node as eligible for new allocations. 40 41 -self 42 Set the eligibility of the local node. 43 ` 44 return strings.TrimSpace(helpText) 45 } 46 47 func (c *NodeEligibilityCommand) Synopsis() string { 48 return "Toggle scheduling eligibility for a given node" 49 } 50 51 func (c *NodeEligibilityCommand) AutocompleteFlags() complete.Flags { 52 return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), 53 complete.Flags{ 54 "-disable": complete.PredictNothing, 55 "-enable": complete.PredictNothing, 56 "-self": complete.PredictNothing, 57 }) 58 } 59 60 func (c *NodeEligibilityCommand) AutocompleteArgs() complete.Predictor { 61 return complete.PredictFunc(func(a complete.Args) []string { 62 client, err := c.Meta.Client() 63 if err != nil { 64 return nil 65 } 66 67 resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Nodes, nil) 68 if err != nil { 69 return []string{} 70 } 71 return resp.Matches[contexts.Nodes] 72 }) 73 } 74 75 func (c *NodeEligibilityCommand) Name() string { return "node eligibility" } 76 77 func (c *NodeEligibilityCommand) Run(args []string) int { 78 var enable, disable, self bool 79 80 flags := c.Meta.FlagSet(c.Name(), FlagSetClient) 81 flags.Usage = func() { c.Ui.Output(c.Help()) } 82 flags.BoolVar(&enable, "enable", false, "Mark node as eligibile for scheduling") 83 flags.BoolVar(&disable, "disable", false, "Mark node as ineligibile for scheduling") 84 flags.BoolVar(&self, "self", false, "") 85 86 if err := flags.Parse(args); err != nil { 87 return 1 88 } 89 90 // Check that we got either enable or disable, but not both. 91 if (enable && disable) || (!enable && !disable) { 92 c.Ui.Error("Either the '-enable' or '-disable' flag must be set") 93 c.Ui.Error(commandErrorText(c)) 94 return 1 95 } 96 97 // Check that we got a node ID 98 args = flags.Args() 99 if l := len(args); self && l != 0 || !self && l != 1 { 100 c.Ui.Error("Node ID must be specified if -self isn't being used") 101 c.Ui.Error(commandErrorText(c)) 102 return 1 103 } 104 105 // Get the HTTP client 106 client, err := c.Meta.Client() 107 if err != nil { 108 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 109 return 1 110 } 111 112 // If -self flag is set then determine the current node. 113 var nodeID string 114 if !self { 115 nodeID = args[0] 116 } else { 117 var err error 118 if nodeID, err = getLocalNodeID(client); err != nil { 119 c.Ui.Error(err.Error()) 120 return 1 121 } 122 } 123 124 // Check if node exists 125 if len(nodeID) == 1 { 126 c.Ui.Error("Identifier must contain at least two characters.") 127 return 1 128 } 129 130 nodeID = sanitizeUUIDPrefix(nodeID) 131 nodes, _, err := client.Nodes().PrefixList(nodeID) 132 if err != nil { 133 c.Ui.Error(fmt.Sprintf("Error updating scheduling eligibility: %s", err)) 134 return 1 135 } 136 // Return error if no nodes are found 137 if len(nodes) == 0 { 138 c.Ui.Error(fmt.Sprintf("No node(s) with prefix or id %q found", nodeID)) 139 return 1 140 } 141 if len(nodes) > 1 { 142 c.Ui.Error(fmt.Sprintf("Prefix matched multiple nodes\n\n%s", 143 formatNodeStubList(nodes, true))) 144 return 1 145 } 146 147 // Prefix lookup matched a single node 148 node, _, err := client.Nodes().Info(nodes[0].ID, nil) 149 if err != nil { 150 c.Ui.Error(fmt.Sprintf("Error updating scheduling eligibility: %s", err)) 151 return 1 152 } 153 154 // Toggle node eligibility 155 if _, err := client.Nodes().ToggleEligibility(node.ID, enable, nil); err != nil { 156 c.Ui.Error(fmt.Sprintf("Error updating scheduling eligibility: %s", err)) 157 return 1 158 } 159 160 if enable { 161 c.Ui.Output(fmt.Sprintf("Node %q scheduling eligibility set: eligible for scheduling", node.ID)) 162 } else { 163 c.Ui.Output(fmt.Sprintf("Node %q scheduling eligibility set: ineligible for scheduling", node.ID)) 164 } 165 return 0 166 }