diff --git a/agent/agent.go b/agent/agent.go index 0ae753b1ce..83de1b3579 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -750,6 +750,9 @@ func (a *Agent) consulConfig() (*consul.Config, error) { if a.config.Autopilot.DisableUpgradeMigration != nil { base.AutopilotConfig.DisableUpgradeMigration = *a.config.Autopilot.DisableUpgradeMigration } + if a.config.Autopilot.UpgradeVersionTag != "" { + base.AutopilotConfig.UpgradeVersionTag = a.config.Autopilot.UpgradeVersionTag + } // make sure the advertise address is always set if base.RPCAdvertise == nil { diff --git a/agent/config.go b/agent/config.go index 33b537abc8..d7af3a2626 100644 --- a/agent/config.go +++ b/agent/config.go @@ -324,6 +324,10 @@ type Autopilot struct { // strategy of waiting until enough newer-versioned servers have been added to the // cluster before promoting them to voters. DisableUpgradeMigration *bool `mapstructure:"disable_upgrade_migration"` + + // (Enterprise-only) UpgradeVersionTag is the node tag to use for version info when + // performing upgrade migrations. If left blank, the Consul version will be used. + UpgradeVersionTag string `mapstructure:"upgrade_version_tag"` } // Config is the configuration that can be set for an Agent. @@ -1687,6 +1691,9 @@ func MergeConfig(a, b *Config) *Config { if b.Autopilot.DisableUpgradeMigration != nil { result.Autopilot.DisableUpgradeMigration = b.Autopilot.DisableUpgradeMigration } + if b.Autopilot.UpgradeVersionTag != "" { + result.Autopilot.UpgradeVersionTag = b.Autopilot.UpgradeVersionTag + } if b.Telemetry.DisableHostname == true { result.Telemetry.DisableHostname = true } diff --git a/agent/config_test.go b/agent/config_test.go index 368111c1ba..0d988314e2 100644 --- a/agent/config_test.go +++ b/agent/config_test.go @@ -181,6 +181,10 @@ func TestDecodeConfig(t *testing.T) { in: `{"autopilot":{"disable_upgrade_migration":true}}`, c: &Config{Autopilot: Autopilot{DisableUpgradeMigration: Bool(true)}}, }, + { + in: `{"autopilot":{"upgrade_version_tag":"rev"}}`, + c: &Config{Autopilot: Autopilot{UpgradeVersionTag: "rev"}}, + }, { in: `{"autopilot":{"last_contact_threshold":"2s"}}`, c: &Config{Autopilot: Autopilot{LastContactThreshold: Duration(2 * time.Second), LastContactThresholdRaw: "2s"}}, diff --git a/agent/consul/state/autopilot_test.go b/agent/consul/state/autopilot_test.go index 91187a473e..545c7e4b21 100644 --- a/agent/consul/state/autopilot_test.go +++ b/agent/consul/state/autopilot_test.go @@ -3,6 +3,7 @@ package state import ( "reflect" "testing" + "time" "github.com/hashicorp/consul/agent/consul/structs" ) @@ -11,7 +12,13 @@ func TestStateStore_Autopilot(t *testing.T) { s := testStateStore(t) expected := &structs.AutopilotConfig{ - CleanupDeadServers: true, + CleanupDeadServers: true, + LastContactThreshold: 5 * time.Second, + MaxTrailingLogs: 500, + ServerStabilizationTime: 100 * time.Second, + RedundancyZoneTag: "az", + DisableUpgradeMigration: true, + UpgradeVersionTag: "build", } if err := s.AutopilotSetConfig(0, expected); err != nil { diff --git a/agent/consul/structs/operator.go b/agent/consul/structs/operator.go index 332d9e556d..3bafa9f566 100644 --- a/agent/consul/structs/operator.go +++ b/agent/consul/structs/operator.go @@ -35,6 +35,10 @@ type AutopilotConfig struct { // cluster before promoting them to voters. DisableUpgradeMigration bool + // (Enterprise-only) UpgradeVersionTag is the node tag to use for version info when + // performing upgrade migrations. If left blank, the Consul version will be used. + UpgradeVersionTag string + // RaftIndex stores the create/modify indexes of this configuration. RaftIndex } diff --git a/api/operator_autopilot.go b/api/operator_autopilot.go index 59471ecf99..0fa9d16040 100644 --- a/api/operator_autopilot.go +++ b/api/operator_autopilot.go @@ -39,6 +39,10 @@ type AutopilotConfiguration struct { // cluster before promoting them to voters. DisableUpgradeMigration bool + // (Enterprise-only) UpgradeVersionTag is the node tag to use for version info when + // performing upgrade migrations. If left blank, the Consul version will be used. + UpgradeVersionTag string + // CreateIndex holds the index corresponding the creation of this configuration. // This is a read-only field. CreateIndex uint64 diff --git a/command/operator_autopilot_get.go b/command/operator_autopilot_get.go index d8dc59f83d..e4ef81568c 100644 --- a/command/operator_autopilot_get.go +++ b/command/operator_autopilot_get.go @@ -60,6 +60,7 @@ func (c *OperatorAutopilotGetCommand) Run(args []string) int { c.UI.Output(fmt.Sprintf("ServerStabilizationTime = %v", config.ServerStabilizationTime.String())) c.UI.Output(fmt.Sprintf("RedundancyZoneTag = %q", config.RedundancyZoneTag)) c.UI.Output(fmt.Sprintf("DisableUpgradeMigration = %v", config.DisableUpgradeMigration)) + c.UI.Output(fmt.Sprintf("UpgradeVersionTag = %q", config.UpgradeVersionTag)) return 0 } diff --git a/command/operator_autopilot_set.go b/command/operator_autopilot_set.go index 53df6945c6..a864ad5855 100644 --- a/command/operator_autopilot_set.go +++ b/command/operator_autopilot_set.go @@ -36,6 +36,7 @@ func (c *OperatorAutopilotSetCommand) Run(args []string) int { var serverStabilizationTime configutil.DurationValue var redundancyZoneTag configutil.StringValue var disableUpgradeMigration configutil.BoolValue + var upgradeVersionTag configutil.StringValue f := c.BaseCommand.NewFlagSet(c) @@ -60,6 +61,9 @@ func (c *OperatorAutopilotSetCommand) Run(args []string) int { f.Var(&disableUpgradeMigration, "disable-upgrade-migration", "(Enterprise-only) Controls whether Consul will avoid promoting new servers until "+ "it can perform a migration. Must be one of `true|false`.") + f.Var(&upgradeVersionTag, "upgrade-version-tag", + "(Enterprise-only) The node_meta tag to use for version info when performing upgrade "+ + "migrations. If left blank, the Consul version will be used.") if err := c.BaseCommand.Parse(args); err != nil { if err == flag.ErrHelp { @@ -88,6 +92,7 @@ func (c *OperatorAutopilotSetCommand) Run(args []string) int { cleanupDeadServers.Merge(&conf.CleanupDeadServers) redundancyZoneTag.Merge(&conf.RedundancyZoneTag) disableUpgradeMigration.Merge(&conf.DisableUpgradeMigration) + upgradeVersionTag.Merge(&conf.UpgradeVersionTag) trailing := uint(conf.MaxTrailingLogs) maxTrailingLogs.Merge(&trailing) diff --git a/website/source/api/operator/autopilot.html.md b/website/source/api/operator/autopilot.html.md index 5edfffb11b..03fee5c6e9 100644 --- a/website/source/api/operator/autopilot.html.md +++ b/website/source/api/operator/autopilot.html.md @@ -60,6 +60,7 @@ $ curl \ "ServerStabilizationTime": "10s", "RedundancyZoneTag": "", "DisableUpgradeMigration": false, + "UpgradeVersionTag": "", "CreateIndex": 4, "ModifyIndex": 4 } @@ -110,7 +111,7 @@ The table below shows this endpoint's support for cluster. Only takes effect if all servers are running Raft protocol version 3 or higher. Must be a duration value such as `30s`. -- `RedundancyZoneTag` `(string: "")` controls the node-meta key to use when +- `RedundancyZoneTag` `(string: "")` - Controls the node-meta key to use when Autopilot is separating servers into zones for redundancy. Only one server in each zone can be a voting member at one time. If left blank, this feature will be disabled. @@ -120,6 +121,10 @@ The table below shows this endpoint's support for newer-versioned servers have been added to the cluster before promoting any of them to voters. +- `UpgradeVersionTag` `(string: "")` - Controls the node-meta key to use for + version info when performing upgrade migrations. If left blank, the Consul + version will be used. + ### Sample Payload ```json @@ -130,6 +135,7 @@ The table below shows this endpoint's support for "ServerStabilizationTime": "10s", "RedundancyZoneTag": "", "DisableUpgradeMigration": false, + "UpgradeVersionTag": "", "CreateIndex": 4, "ModifyIndex": 4 } diff --git a/website/source/docs/commands/operator/autopilot.html.markdown.erb b/website/source/docs/commands/operator/autopilot.html.markdown.erb index 39e47cfe02..79e113ee6c 100644 --- a/website/source/docs/commands/operator/autopilot.html.markdown.erb +++ b/website/source/docs/commands/operator/autopilot.html.markdown.erb @@ -46,6 +46,7 @@ MaxTrailingLogs = 250 ServerStabilizationTime = 10s RedundancyZoneTag = "" DisableUpgradeMigration = false +UpgradeMigrationTag = "" ``` ## set-config @@ -80,6 +81,9 @@ new servers until it can perform a migration. Must be one of `[true|false]`. * `-redundancy-zone-tag`- (Enterprise-only) Controls the [`-node-meta`](/docs/agent/options.html#_node_meta) key name used for separating servers into different redundancy zones. +* `-upgrade-version-tag` - (Enterprise-only) Controls the [`-node-meta`](/docs/agent/options.html#_node_meta) +tag to use for version info when performing upgrade migrations. If left blank, the Consul version will be used. + The output looks like this: ``` diff --git a/website/source/docs/guides/autopilot.html.md b/website/source/docs/guides/autopilot.html.md index 0ffbcc0d13..ec1bf91979 100644 --- a/website/source/docs/guides/autopilot.html.md +++ b/website/source/docs/guides/autopilot.html.md @@ -32,7 +32,8 @@ bootstrapping the cluster: "max_trailing_logs": 250, "server_stabilization_time": "10s", "redundancy_zone_tag": "az", - "disable_upgrade_migration": false + "disable_upgrade_migration": false, + "upgrade_version_tag": "" } ``` @@ -49,6 +50,7 @@ MaxTrailingLogs = 250 ServerStabilizationTime = 10s RedundancyZoneTag = "" DisableUpgradeMigration = false +UpgradeVersionTag = "" $ consul operator autopilot set-config -cleanup-dead-servers=false Configuration updated! @@ -60,6 +62,7 @@ MaxTrailingLogs = 250 ServerStabilizationTime = 10s RedundancyZoneTag = "" DisableUpgradeMigration = false +UpgradeVersionTag = "" ``` ## Dead Server Cleanup @@ -200,3 +203,16 @@ node2 127.0.0.1:8703 alive server 0.7.5 2 dc1 node3 127.0.0.1:8803 alive server 0.7.5 2 dc1 node4 127.0.0.1:8203 alive server 0.8.0 2 dc1 ``` + +### Migrations Without a Consul Version Change + +The `UpgradeVersionTag` can be used to override the version information used during +a migration, so that the migration logic can be used for updating the cluster when +changing configuration. + +If the `UpgradeVersionTag` setting is set, Consul will use its value to look for a +version in each server's specified [`-node-meta`](/docs/agent/options.html#_node_meta) +tag. For example, if `UpgradeVersionTag` is set to `build`, and `-node-meta build:0.0.2` +is used when starting a server, that server's version will be `0.0.2` when considered in +a migration. The upgrade logic will follow semantic versioning and the version string +must be in the form of either `X`, `X.Y`, or `X.Y.Z`.