1package command
2
3import (
4	"fmt"
5	"strings"
6
7	"github.com/hashicorp/consul/command/flags"
8	"github.com/posener/complete"
9)
10
11type OperatorAutopilotSetCommand struct {
12	Meta
13}
14
15func (c *OperatorAutopilotSetCommand) AutocompleteFlags() complete.Flags {
16	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
17		complete.Flags{
18			"-cleanup-dead-servers":      complete.PredictAnything,
19			"-max-trailing-logs":         complete.PredictAnything,
20			"-last-contact-threshold":    complete.PredictAnything,
21			"-server-stabilization-time": complete.PredictAnything,
22			"-enable-redundancy-zones":   complete.PredictNothing,
23			"-disable-upgrade-migration": complete.PredictNothing,
24			"-enable-custom-upgrades":    complete.PredictNothing,
25		})
26}
27
28func (c *OperatorAutopilotSetCommand) AutocompleteArgs() complete.Predictor {
29	return complete.PredictNothing
30}
31
32func (c *OperatorAutopilotSetCommand) Name() string { return "operator autopilot set-config" }
33
34func (c *OperatorAutopilotSetCommand) Run(args []string) int {
35	var cleanupDeadServers flags.BoolValue
36	var maxTrailingLogs flags.UintValue
37	var lastContactThreshold flags.DurationValue
38	var serverStabilizationTime flags.DurationValue
39	var enableRedundancyZones flags.BoolValue
40	var disableUpgradeMigration flags.BoolValue
41	var enableCustomUpgrades flags.BoolValue
42
43	f := c.Meta.FlagSet("autopilot", FlagSetClient)
44	f.Usage = func() { c.Ui.Output(c.Help()) }
45
46	f.Var(&cleanupDeadServers, "cleanup-dead-servers", "")
47	f.Var(&maxTrailingLogs, "max-trailing-logs", "")
48	f.Var(&lastContactThreshold, "last-contact-threshold", "")
49	f.Var(&serverStabilizationTime, "server-stabilization-time", "")
50	f.Var(&enableRedundancyZones, "enable-redundancy-zones", "")
51	f.Var(&disableUpgradeMigration, "disable-upgrade-migration", "")
52	f.Var(&enableCustomUpgrades, "enable-custom-upgrades", "")
53
54	if err := f.Parse(args); err != nil {
55		c.Ui.Error(fmt.Sprintf("Failed to parse args: %v", err))
56		return 1
57	}
58
59	// Set up a client.
60	client, err := c.Meta.Client()
61	if err != nil {
62		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
63		return 1
64	}
65
66	// Fetch the current configuration.
67	operator := client.Operator()
68	conf, _, err := operator.AutopilotGetConfiguration(nil)
69	if err != nil {
70		c.Ui.Error(fmt.Sprintf("Error querying for Autopilot configuration: %s", err))
71		return 1
72	}
73
74	// Update the config values based on the set flags.
75	cleanupDeadServers.Merge(&conf.CleanupDeadServers)
76	enableRedundancyZones.Merge(&conf.EnableRedundancyZones)
77	disableUpgradeMigration.Merge(&conf.DisableUpgradeMigration)
78	enableCustomUpgrades.Merge(&conf.EnableCustomUpgrades)
79
80	trailing := uint(conf.MaxTrailingLogs)
81	maxTrailingLogs.Merge(&trailing)
82	conf.MaxTrailingLogs = uint64(trailing)
83	lastContactThreshold.Merge(&conf.LastContactThreshold)
84	serverStabilizationTime.Merge(&conf.ServerStabilizationTime)
85
86	// Check-and-set the new configuration.
87	result, _, err := operator.AutopilotCASConfiguration(conf, nil)
88	if err != nil {
89		c.Ui.Error(fmt.Sprintf("Error setting Autopilot configuration: %s", err))
90		return 1
91	}
92	if result {
93		c.Ui.Output("Configuration updated!")
94		return 0
95	}
96	c.Ui.Output("Configuration could not be atomically updated, please try again")
97	return 1
98}
99
100func (c *OperatorAutopilotSetCommand) Synopsis() string {
101	return "Modify the current Autopilot configuration"
102}
103
104func (c *OperatorAutopilotSetCommand) Help() string {
105	helpText := `
106Usage: nomad operator autopilot set-config [options]
107
108  Modifies the current Autopilot configuration.
109
110General Options:
111
112  ` + generalOptionsUsage() + `
113
114Set Config Options:
115
116  -cleanup-dead-servers=[true|false]
117     Controls whether Nomad will automatically remove dead servers when
118     new ones are successfully added. Must be one of [true|false].
119
120  -disable-upgrade-migration=[true|false]
121     (Enterprise-only) Controls whether Nomad will avoid promoting
122     new servers until it can perform a migration. Must be one of
123     "true|false".
124
125  -last-contact-threshold=200ms
126     Controls the maximum amount of time a server can go without contact
127     from the leader before being considered unhealthy. Must be a
128     duration value such as "200ms".
129
130  -max-trailing-logs=<value>
131     Controls the maximum number of log entries that a server can trail
132     the leader by before being considered unhealthy.
133
134  -redundancy-zone-tag=<value>
135     (Enterprise-only) Controls the node_meta tag name used for
136     separating servers into different redundancy zones.
137
138  -server-stabilization-time=<10s>
139     Controls the minimum amount of time a server must be stable in
140     the 'healthy' state before being added to the cluster. Only takes
141     effect if all servers are running Raft protocol version 3 or
142     higher. Must be a duration value such as "10s".
143
144  -upgrade-version-tag=<value>
145     (Enterprise-only) The node_meta tag to use for version info when
146     performing upgrade migrations. If left blank, the Nomad version
147     will be used.
148`
149	return strings.TrimSpace(helpText)
150}
151