github.com/s-matyukevich/consul@v1.4.5/command/maint/maint.go (about) 1 package maint 2 3 import ( 4 "flag" 5 "fmt" 6 "strings" 7 8 "github.com/hashicorp/consul/command/flags" 9 "github.com/mitchellh/cli" 10 ) 11 12 // cmd is a Command implementation that enables or disables 13 // node or service maintenance mode. 14 type cmd struct { 15 UI cli.Ui 16 help string 17 flags *flag.FlagSet 18 http *flags.HTTPFlags 19 20 // flags 21 enable bool 22 disable bool 23 reason string 24 serviceID string 25 } 26 27 func New(ui cli.Ui) *cmd { 28 c := &cmd{UI: ui} 29 c.init() 30 return c 31 } 32 33 func (c *cmd) init() { 34 c.flags = flag.NewFlagSet("", flag.ContinueOnError) 35 c.flags.BoolVar(&c.enable, "enable", false, 36 "Enable maintenance mode.") 37 c.flags.BoolVar(&c.disable, "disable", false, 38 "Disable maintenance mode.") 39 c.flags.StringVar(&c.reason, "reason", "", 40 "Text describing the maintenance reason.") 41 c.flags.StringVar(&c.serviceID, "service", "", 42 "Control maintenance mode for a specific service ID.") 43 44 c.http = &flags.HTTPFlags{} 45 flags.Merge(c.flags, c.http.ClientFlags()) 46 c.help = flags.Usage(help, c.flags) 47 } 48 49 func (c *cmd) Run(args []string) int { 50 if err := c.flags.Parse(args); err != nil { 51 return 1 52 } 53 54 // Ensure we don't have conflicting args 55 if c.enable && c.disable { 56 c.UI.Error("Only one of -enable or -disable may be provided") 57 return 1 58 } 59 if !c.enable && c.reason != "" { 60 c.UI.Error("Reason may only be provided with -enable") 61 return 1 62 } 63 if !c.enable && !c.disable && c.serviceID != "" { 64 c.UI.Error("Service requires either -enable or -disable") 65 return 1 66 } 67 68 // Create and test the HTTP client 69 client, err := c.http.APIClient() 70 if err != nil { 71 c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) 72 return 1 73 } 74 a := client.Agent() 75 nodeName, err := a.NodeName() 76 if err != nil { 77 c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err)) 78 return 1 79 } 80 81 if !c.enable && !c.disable { 82 // List mode - list nodes/services in maintenance mode 83 checks, err := a.Checks() 84 if err != nil { 85 c.UI.Error(fmt.Sprintf("Error getting checks: %s", err)) 86 return 1 87 } 88 89 for _, check := range checks { 90 if check.CheckID == "_node_maintenance" { 91 c.UI.Output("Node:") 92 c.UI.Output(" Name: " + nodeName) 93 c.UI.Output(" Reason: " + check.Notes) 94 c.UI.Output("") 95 } else if strings.HasPrefix(string(check.CheckID), "_service_maintenance:") { 96 c.UI.Output("Service:") 97 c.UI.Output(" ID: " + check.ServiceID) 98 c.UI.Output(" Reason: " + check.Notes) 99 c.UI.Output("") 100 } 101 } 102 103 return 0 104 } 105 106 if c.enable { 107 // Enable node maintenance 108 if c.serviceID == "" { 109 if err := a.EnableNodeMaintenance(c.reason); err != nil { 110 c.UI.Error(fmt.Sprintf("Error enabling node maintenance: %s", err)) 111 return 1 112 } 113 c.UI.Output("Node maintenance is now enabled") 114 return 0 115 } 116 117 // Enable service maintenance 118 if err := a.EnableServiceMaintenance(c.serviceID, c.reason); err != nil { 119 c.UI.Error(fmt.Sprintf("Error enabling service maintenance: %s", err)) 120 return 1 121 } 122 c.UI.Output(fmt.Sprintf("Service maintenance is now enabled for %q", c.serviceID)) 123 return 0 124 } 125 126 if c.disable { 127 // Disable node maintenance 128 if c.serviceID == "" { 129 if err := a.DisableNodeMaintenance(); err != nil { 130 c.UI.Error(fmt.Sprintf("Error disabling node maintenance: %s", err)) 131 return 1 132 } 133 c.UI.Output("Node maintenance is now disabled") 134 return 0 135 } 136 137 // Disable service maintenance 138 if err := a.DisableServiceMaintenance(c.serviceID); err != nil { 139 c.UI.Error(fmt.Sprintf("Error disabling service maintenance: %s", err)) 140 return 1 141 } 142 c.UI.Output(fmt.Sprintf("Service maintenance is now disabled for %q", c.serviceID)) 143 return 0 144 } 145 146 return 0 147 } 148 149 func (c *cmd) Synopsis() string { 150 return synopsis 151 } 152 153 func (c *cmd) Help() string { 154 return c.help 155 } 156 157 const synopsis = "Controls node or service maintenance mode" 158 const help = ` 159 Usage: consul maint [options] 160 161 Places a node or service into maintenance mode. During maintenance mode, 162 the node or service will be excluded from all queries through the DNS 163 or API interfaces, effectively taking it out of the pool of available 164 nodes. This is done by registering an additional critical health check. 165 166 When enabling maintenance mode for a node or service, you may optionally 167 specify a reason string. This string will appear in the "Notes" field 168 of the critical health check which is registered against the node or 169 service. If no reason is provided, a default value will be used. 170 171 Maintenance mode is persistent, and will be restored in the event of an 172 agent restart. It is therefore required to disable maintenance mode on 173 a given node or service before it will be placed back into the pool. 174 175 By default, we operate on the node as a whole. By specifying the 176 "-service" argument, this behavior can be changed to enable or disable 177 only a specific service. 178 179 If no arguments are given, the agent's maintenance status will be shown. 180 This will return blank if nothing is currently under maintenance. 181 `