7568a19433
This patch refactors the commands that use the mitchellh/cli library to populate the command line flag set in both the Run() and the Help() method. Earlier versions of the mitchellh/cli library relied on the Run() method to populuate the flagset for generating the usage screen. This has changed in later versions and was previously solved with a small monkey patch to the library to restore the old behavior. However, this makes upgrading the library difficult since the patch has to be restored every time. This patch addresses this by moving the command line flags into an initFlags() method where appropriate and also moving all variables for the flags from the Run() method into the command itself. Fixes #3536
165 lines
4.6 KiB
Go
165 lines
4.6 KiB
Go
package command
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// MaintCommand is a Command implementation that enables or disables
|
|
// node or service maintenance mode.
|
|
type MaintCommand struct {
|
|
BaseCommand
|
|
|
|
// flags
|
|
enable bool
|
|
disable bool
|
|
reason string
|
|
serviceID string
|
|
}
|
|
|
|
func (c *MaintCommand) initFlags() {
|
|
c.InitFlagSet()
|
|
c.FlagSet.BoolVar(&c.enable, "enable", false,
|
|
"Enable maintenance mode.")
|
|
c.FlagSet.BoolVar(&c.disable, "disable", false,
|
|
"Disable maintenance mode.")
|
|
c.FlagSet.StringVar(&c.reason, "reason", "",
|
|
"Text describing the maintenance reason.")
|
|
c.FlagSet.StringVar(&c.serviceID, "service", "",
|
|
"Control maintenance mode for a specific service ID.")
|
|
}
|
|
|
|
func (c *MaintCommand) Help() string {
|
|
c.initFlags()
|
|
return c.HelpCommand(`
|
|
Usage: consul maint [options]
|
|
|
|
Places a node or service into maintenance mode. During maintenance mode,
|
|
the node or service will be excluded from all queries through the DNS
|
|
or API interfaces, effectively taking it out of the pool of available
|
|
nodes. This is done by registering an additional critical health check.
|
|
|
|
When enabling maintenance mode for a node or service, you may optionally
|
|
specify a reason string. This string will appear in the "Notes" field
|
|
of the critical health check which is registered against the node or
|
|
service. If no reason is provided, a default value will be used.
|
|
|
|
Maintenance mode is persistent, and will be restored in the event of an
|
|
agent restart. It is therefore required to disable maintenance mode on
|
|
a given node or service before it will be placed back into the pool.
|
|
|
|
By default, we operate on the node as a whole. By specifying the
|
|
"-service" argument, this behavior can be changed to enable or disable
|
|
only a specific service.
|
|
|
|
If no arguments are given, the agent's maintenance status will be shown.
|
|
This will return blank if nothing is currently under maintenance.
|
|
|
|
`)
|
|
}
|
|
|
|
func (c *MaintCommand) Run(args []string) int {
|
|
c.initFlags()
|
|
if err := c.FlagSet.Parse(args); err != nil {
|
|
return 1
|
|
}
|
|
|
|
// Ensure we don't have conflicting args
|
|
if c.enable && c.disable {
|
|
c.UI.Error("Only one of -enable or -disable may be provided")
|
|
return 1
|
|
}
|
|
if !c.enable && c.reason != "" {
|
|
c.UI.Error("Reason may only be provided with -enable")
|
|
return 1
|
|
}
|
|
if !c.enable && !c.disable && c.serviceID != "" {
|
|
c.UI.Error("Service requires either -enable or -disable")
|
|
return 1
|
|
}
|
|
|
|
// Create and test the HTTP client
|
|
client, err := c.HTTPClient()
|
|
if err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
|
|
return 1
|
|
}
|
|
a := client.Agent()
|
|
nodeName, err := a.NodeName()
|
|
if err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
|
|
return 1
|
|
}
|
|
|
|
if !c.enable && !c.disable {
|
|
// List mode - list nodes/services in maintenance mode
|
|
checks, err := a.Checks()
|
|
if err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error getting checks: %s", err))
|
|
return 1
|
|
}
|
|
|
|
for _, check := range checks {
|
|
if check.CheckID == "_node_maintenance" {
|
|
c.UI.Output("Node:")
|
|
c.UI.Output(" Name: " + nodeName)
|
|
c.UI.Output(" Reason: " + check.Notes)
|
|
c.UI.Output("")
|
|
} else if strings.HasPrefix(string(check.CheckID), "_service_maintenance:") {
|
|
c.UI.Output("Service:")
|
|
c.UI.Output(" ID: " + check.ServiceID)
|
|
c.UI.Output(" Reason: " + check.Notes)
|
|
c.UI.Output("")
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
if c.enable {
|
|
// Enable node maintenance
|
|
if c.serviceID == "" {
|
|
if err := a.EnableNodeMaintenance(c.reason); err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error enabling node maintenance: %s", err))
|
|
return 1
|
|
}
|
|
c.UI.Output("Node maintenance is now enabled")
|
|
return 0
|
|
}
|
|
|
|
// Enable service maintenance
|
|
if err := a.EnableServiceMaintenance(c.serviceID, c.reason); err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error enabling service maintenance: %s", err))
|
|
return 1
|
|
}
|
|
c.UI.Output(fmt.Sprintf("Service maintenance is now enabled for %q", c.serviceID))
|
|
return 0
|
|
}
|
|
|
|
if c.disable {
|
|
// Disable node maintenance
|
|
if c.serviceID == "" {
|
|
if err := a.DisableNodeMaintenance(); err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error disabling node maintenance: %s", err))
|
|
return 1
|
|
}
|
|
c.UI.Output("Node maintenance is now disabled")
|
|
return 0
|
|
}
|
|
|
|
// Disable service maintenance
|
|
if err := a.DisableServiceMaintenance(c.serviceID); err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error disabling service maintenance: %s", err))
|
|
return 1
|
|
}
|
|
c.UI.Output(fmt.Sprintf("Service maintenance is now disabled for %q", c.serviceID))
|
|
return 0
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func (c *MaintCommand) Synopsis() string {
|
|
return "Controls node or service maintenance mode"
|
|
}
|