mirror of https://github.com/status-im/consul.git
NET-6643: upgrade test from 1.10 to 1.15 (lts) of a single cluster (#19847)
* NET-6643: upgrade test from 1.10 to 1.15 (lts) of a single cluster * license header
This commit is contained in:
parent
053367a3b2
commit
04d4412afd
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
|
package usage_profiles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/test/integration/consul-container/libs/utils"
|
||||||
|
"github.com/hashicorp/consul/testing/deployer/sprawl"
|
||||||
|
"github.com/hashicorp/consul/testing/deployer/sprawl/sprawltest"
|
||||||
|
"github.com/hashicorp/consul/testing/deployer/topology"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// The long term support version
|
||||||
|
ltsVersion = "1.15.7"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test_Upgrade_ServiceDiscovery_Wan_Segment test upgrade from a source version
|
||||||
|
// to a specified long term support version
|
||||||
|
// Clusters: multi-segment and multi-cluster (TODO)
|
||||||
|
// Workload: service discovery (no mesh) (TODO)
|
||||||
|
func Test_Upgrade_ServiceDiscovery_Wan_Segment(t *testing.T) {
|
||||||
|
utils.LatestVersion = "1.10.8"
|
||||||
|
utils.TargetVersion = ltsVersion
|
||||||
|
|
||||||
|
dc1, err := createTopology("dc1")
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Log("Created topology:", dc1.Name, "enterprise:", utils.IsEnterprise())
|
||||||
|
|
||||||
|
toplogyConfig := &topology.Config{
|
||||||
|
Networks: []*topology.Network{
|
||||||
|
{Name: "dc1"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
toplogyConfig.Clusters = append(toplogyConfig.Clusters, dc1)
|
||||||
|
sp := sprawltest.Launch(t, toplogyConfig)
|
||||||
|
|
||||||
|
cfg := sp.Config()
|
||||||
|
require.NoError(t, sp.Upgrade(cfg, "dc1", sprawl.UpgradeTypeStandard, utils.TargetImages(), nil))
|
||||||
|
t.Log("Finished standard upgrade ...")
|
||||||
|
|
||||||
|
time.Sleep(30 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTopology(name string) (*topology.Cluster, error) {
|
||||||
|
clu := &topology.Cluster{
|
||||||
|
Name: name,
|
||||||
|
Images: utils.LatestImages(),
|
||||||
|
Nodes: []*topology.Node{
|
||||||
|
{
|
||||||
|
Kind: topology.NodeKindServer,
|
||||||
|
Name: "dc1-server1",
|
||||||
|
Addresses: []*topology.Address{
|
||||||
|
{Network: "dc1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Kind: topology.NodeKindClient,
|
||||||
|
Name: "dc1-client1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Enterprise: utils.IsEnterprise(),
|
||||||
|
}
|
||||||
|
return clu, nil
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ require (
|
||||||
github.com/hashicorp/go-hclog v1.5.0
|
github.com/hashicorp/go-hclog v1.5.0
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
github.com/hashicorp/go-rootcerts v1.0.2
|
github.com/hashicorp/go-rootcerts v1.0.2
|
||||||
|
github.com/hashicorp/go-version v1.2.1
|
||||||
github.com/hashicorp/hcl/v2 v2.16.2
|
github.com/hashicorp/hcl/v2 v2.16.2
|
||||||
github.com/mitchellh/copystructure v1.2.0
|
github.com/mitchellh/copystructure v1.2.0
|
||||||
github.com/rboyer/safeio v0.2.2
|
github.com/rboyer/safeio v0.2.2
|
||||||
|
@ -40,7 +41,6 @@ require (
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||||
github.com/hashicorp/go-netaddrs v0.1.0 // indirect
|
github.com/hashicorp/go-netaddrs v0.1.0 // indirect
|
||||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||||
github.com/hashicorp/go-version v1.2.1 // indirect
|
|
||||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||||
github.com/hashicorp/serf v0.10.1 // indirect
|
github.com/hashicorp/serf v0.10.1 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
|
|
@ -146,6 +146,56 @@ func (s *Sprawl) createAnonymousPolicy(cluster *topology.Cluster) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assignAgentJoinPolicyToAnonymousToken is used only for version prior to agent token
|
||||||
|
func (s *Sprawl) assignAgentJoinPolicyToAnonymousToken(cluster *topology.Cluster) error {
|
||||||
|
var (
|
||||||
|
client = s.clients[cluster.Name]
|
||||||
|
)
|
||||||
|
|
||||||
|
acl := client.ACL()
|
||||||
|
anonymousTok, _, err := acl.TokenRead(anonymousTokenAccessorID, &api.QueryOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rule := `
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
agent_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
node_prefix "" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
policy, _, err := acl.PolicyCreate(
|
||||||
|
&api.ACLPolicy{
|
||||||
|
Name: "client-join-policy",
|
||||||
|
Rules: rule,
|
||||||
|
},
|
||||||
|
&api.WriteOptions{},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
anonymousTok.Policies = append(anonymousTok.Policies,
|
||||||
|
&api.ACLLink{
|
||||||
|
Name: policy.Name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
_, _, err = acl.TokenUpdate(anonymousTok, &api.WriteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Sprawl) createAgentTokens(cluster *topology.Cluster) error {
|
func (s *Sprawl) createAgentTokens(cluster *topology.Cluster) error {
|
||||||
var (
|
var (
|
||||||
client = s.clients[cluster.Name]
|
client = s.clients[cluster.Name]
|
||||||
|
@ -158,10 +208,11 @@ func (s *Sprawl) createAgentTokens(cluster *topology.Cluster) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if node.Images.GreaterThanVersion(topology.MinVersionAgentTokenPartition) {
|
||||||
if tok := s.secrets.ReadAgentToken(cluster.Name, node.ID()); tok == "" {
|
if tok := s.secrets.ReadAgentToken(cluster.Name, node.ID()); tok == "" {
|
||||||
token, err := CreateOrUpdateToken(client, tokenForNode(node, cluster.Enterprise))
|
token, err := CreateOrUpdateToken(client, tokenForNode(node, cluster.Enterprise))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("node %s: %w", node.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("created agent token",
|
logger.Debug("created agent token",
|
||||||
|
@ -172,6 +223,7 @@ func (s *Sprawl) createAgentTokens(cluster *topology.Cluster) error {
|
||||||
s.secrets.SaveAgentToken(cluster.Name, node.ID(), token.SecretID)
|
s.secrets.SaveAgentToken(cluster.Name, node.ID(), token.SecretID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,7 +266,7 @@ func (s *Sprawl) initConsulServers() error {
|
||||||
s.waitForLocalWrites(cluster, mgmtToken)
|
s.waitForLocalWrites(cluster, mgmtToken)
|
||||||
|
|
||||||
// Create tenancies so that the ACL tokens and clients have somewhere to go.
|
// Create tenancies so that the ACL tokens and clients have somewhere to go.
|
||||||
if cluster.Enterprise {
|
if cluster.Enterprise && node.Images.GreaterThanVersion(topology.MinVersionAgentTokenPartition) {
|
||||||
if err := s.initTenancies(cluster); err != nil {
|
if err := s.initTenancies(cluster); err != nil {
|
||||||
return fmt.Errorf("initTenancies[%s]: %w", cluster.Name, err)
|
return fmt.Errorf("initTenancies[%s]: %w", cluster.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -287,6 +287,7 @@ func (s *Sprawl) initConsulServers() error {
|
||||||
return fmt.Errorf("createAnonymousToken[%s]: %w", cluster.Name, err)
|
return fmt.Errorf("createAnonymousToken[%s]: %w", cluster.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if node.Images.GreaterThanVersion(topology.MinVersionAgentTokenPartition) {
|
||||||
// Create tokens for all of the agents to use for anti-entropy.
|
// Create tokens for all of the agents to use for anti-entropy.
|
||||||
//
|
//
|
||||||
// NOTE: this will cause the servers to roll to pick up the change to
|
// NOTE: this will cause the servers to roll to pick up the change to
|
||||||
|
@ -294,6 +295,12 @@ func (s *Sprawl) initConsulServers() error {
|
||||||
if err := s.createAgentTokens(cluster); err != nil {
|
if err := s.createAgentTokens(cluster); err != nil {
|
||||||
return fmt.Errorf("createAgentTokens[%s]: %w", cluster.Name, err)
|
return fmt.Errorf("createAgentTokens[%s]: %w", cluster.Name, err)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Assign agent join policy to the anonymous token
|
||||||
|
if err := s.assignAgentJoinPolicyToAnonymousToken(cluster); err != nil {
|
||||||
|
return fmt.Errorf("assignAgentJoinPolicyToAnonymousToken[%s]: %w", cluster.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -487,7 +494,8 @@ func (s *Sprawl) waitForLocalWrites(cluster *topology.Cluster, token string) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if cluster.Enterprise {
|
serverNodes := cluster.ServerNodes()
|
||||||
|
if cluster.Enterprise && serverNodes[0].Images.GreaterThanVersion(topology.MinVersionAgentTokenPartition) {
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
for attempts := 0; ; attempts++ {
|
for attempts := 0; ; attempts++ {
|
||||||
if err := tryAP(); err != nil {
|
if err := tryAP(); err != nil {
|
||||||
|
@ -543,7 +551,7 @@ func (s *Sprawl) waitForClientAntiEntropyOnce(cluster *topology.Cluster) error {
|
||||||
nid := node.CatalogID()
|
nid := node.CatalogID()
|
||||||
|
|
||||||
got, ok := current[nid]
|
got, ok := current[nid]
|
||||||
if ok && len(got.TaggedAddresses) > 0 {
|
if ok && (len(got.TaggedAddresses) > 0 || got.Address != "") {
|
||||||
// this is a field that is not updated just due to serf reconcile
|
// this is a field that is not updated just due to serf reconcile
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,11 +60,13 @@ func (g *Generator) generateAgentHCL(node *topology.Node, enableV2, enableV2Tena
|
||||||
b.add("retry_interval", "1s")
|
b.add("retry_interval", "1s")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if node.Images.GreaterThanVersion(topology.MinVersionPeering) {
|
||||||
if node.IsServer() {
|
if node.IsServer() {
|
||||||
b.addBlock("peering", func() {
|
b.addBlock("peering", func() {
|
||||||
b.add("enabled", true)
|
b.add("enabled", true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b.addBlock("ui_config", func() {
|
b.addBlock("ui_config", func() {
|
||||||
b.add("enabled", true)
|
b.add("enabled", true)
|
||||||
|
@ -85,6 +87,7 @@ func (g *Generator) generateAgentHCL(node *topology.Node, enableV2, enableV2Tena
|
||||||
certKey = root + "/" + node.TLSCertPrefix + "-key.pem"
|
certKey = root + "/" + node.TLSCertPrefix + "-key.pem"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if node.Images.GreaterThanVersion(topology.MinVersionTLS) {
|
||||||
b.addBlock("tls", func() {
|
b.addBlock("tls", func() {
|
||||||
b.addBlock("internal_rpc", func() {
|
b.addBlock("internal_rpc", func() {
|
||||||
b.add("ca_file", caFile)
|
b.add("ca_file", caFile)
|
||||||
|
@ -112,8 +115,10 @@ func (g *Generator) generateAgentHCL(node *topology.Node, enableV2, enableV2Tena
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b.addBlock("ports", func() {
|
b.addBlock("ports", func() {
|
||||||
|
if node.Images.GreaterThanVersion(topology.MinVersionPeering) {
|
||||||
if node.IsServer() {
|
if node.IsServer() {
|
||||||
b.add("grpc_tls", 8503)
|
b.add("grpc_tls", 8503)
|
||||||
b.add("grpc", -1)
|
b.add("grpc", -1)
|
||||||
|
@ -121,6 +126,7 @@ func (g *Generator) generateAgentHCL(node *topology.Node, enableV2, enableV2Tena
|
||||||
b.add("grpc", 8502)
|
b.add("grpc", 8502)
|
||||||
b.add("grpc_tls", -1)
|
b.add("grpc_tls", -1)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
b.add("http", 8500)
|
b.add("http", 8500)
|
||||||
b.add("dns", 8600)
|
b.add("dns", 8600)
|
||||||
})
|
})
|
||||||
|
@ -132,6 +138,8 @@ func (g *Generator) generateAgentHCL(node *topology.Node, enableV2, enableV2Tena
|
||||||
b.add("default_policy", "deny")
|
b.add("default_policy", "deny")
|
||||||
b.add("down_policy", "extend-cache")
|
b.add("down_policy", "extend-cache")
|
||||||
b.add("enable_token_persistence", true)
|
b.add("enable_token_persistence", true)
|
||||||
|
|
||||||
|
if node.Images.GreaterThanVersion(topology.MinVersionAgentTokenPartition) {
|
||||||
b.addBlock("tokens", func() {
|
b.addBlock("tokens", func() {
|
||||||
if node.IsServer() {
|
if node.IsServer() {
|
||||||
b.add("initial_management", g.sec.ReadGeneric(node.Cluster, secrets.BootstrapToken))
|
b.add("initial_management", g.sec.ReadGeneric(node.Cluster, secrets.BootstrapToken))
|
||||||
|
@ -139,6 +147,13 @@ func (g *Generator) generateAgentHCL(node *topology.Node, enableV2, enableV2Tena
|
||||||
b.add("agent_recovery", g.sec.ReadGeneric(node.Cluster, secrets.AgentRecovery))
|
b.add("agent_recovery", g.sec.ReadGeneric(node.Cluster, secrets.AgentRecovery))
|
||||||
b.add("agent", g.sec.ReadAgentToken(node.Cluster, node.ID()))
|
b.add("agent", g.sec.ReadAgentToken(node.Cluster, node.ID()))
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
b.addBlock("tokens", func() {
|
||||||
|
if node.IsServer() {
|
||||||
|
b.add("master", g.sec.ReadGeneric(node.Cluster, secrets.BootstrapToken))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if node.IsServer() {
|
if node.IsServer() {
|
||||||
|
@ -195,7 +210,7 @@ func (g *Generator) generateAgentHCL(node *topology.Node, enableV2, enableV2Tena
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if cluster.Enterprise {
|
if cluster.Enterprise && node.Images.GreaterThanVersion(topology.MinVersionAgentTokenPartition) {
|
||||||
b.add("partition", node.Partition)
|
b.add("partition", node.Partition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,6 +299,18 @@ func (s *Sprawl) standardUpgrade(cluster *topology.Cluster,
|
||||||
return fmt.Errorf("error upgrading node %s: %w", node.Name, err)
|
return fmt.Errorf("error upgrading node %s: %w", node.Name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// upgrade client agents one at a time
|
||||||
|
for _, node := range cluster.Nodes {
|
||||||
|
if node.Kind != topology.NodeKindClient {
|
||||||
|
s.logger.Info("Skip non-client node", "node", node.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := upgradeFn(node.ID()); err != nil {
|
||||||
|
return fmt.Errorf("error upgrading node %s: %w", node.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,14 @@ package topology
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
goversion "github.com/hashicorp/go-version"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
MinVersionAgentTokenPartition = goversion.Must(goversion.NewVersion("v1.11.0"))
|
||||||
|
MinVersionPeering = goversion.Must(goversion.NewVersion("v1.13.0"))
|
||||||
|
MinVersionTLS = goversion.Must(goversion.NewVersion("v1.12.0"))
|
||||||
)
|
)
|
||||||
|
|
||||||
type Images struct {
|
type Images struct {
|
||||||
|
@ -13,6 +21,10 @@ type Images struct {
|
||||||
Consul string `json:",omitempty"`
|
Consul string `json:",omitempty"`
|
||||||
// ConsulCE sets the CE image
|
// ConsulCE sets the CE image
|
||||||
ConsulCE string `json:",omitempty"`
|
ConsulCE string `json:",omitempty"`
|
||||||
|
// consulVersion is the version part of Consul image,
|
||||||
|
// e.g., if Consul image is hashicorp/consul-enterprise:1.15.0-ent,
|
||||||
|
// consulVersion is 1.15.0-ent
|
||||||
|
consulVersion string
|
||||||
// ConsulEnterprise sets the ent image
|
// ConsulEnterprise sets the ent image
|
||||||
ConsulEnterprise string `json:",omitempty"`
|
ConsulEnterprise string `json:",omitempty"`
|
||||||
Envoy string
|
Envoy string
|
||||||
|
@ -93,9 +105,21 @@ func (i Images) ChooseConsul(enterprise bool) Images {
|
||||||
}
|
}
|
||||||
i.ConsulEnterprise = ""
|
i.ConsulEnterprise = ""
|
||||||
i.ConsulCE = ""
|
i.ConsulCE = ""
|
||||||
|
|
||||||
|
// extract the version part of Consul
|
||||||
|
i.consulVersion = i.Consul[strings.Index(i.Consul, ":")+1:]
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GreaterThanVersion compares the image version to a specified version
|
||||||
|
func (i Images) GreaterThanVersion(version *goversion.Version) bool {
|
||||||
|
if i.consulVersion == "local" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
iVer := goversion.Must(goversion.NewVersion(i.consulVersion))
|
||||||
|
return iVer.GreaterThanOrEqual(version)
|
||||||
|
}
|
||||||
|
|
||||||
func (i Images) OverrideWith(i2 Images) Images {
|
func (i Images) OverrideWith(i2 Images) Images {
|
||||||
if i2.Consul != "" {
|
if i2.Consul != "" {
|
||||||
i.Consul = i2.Consul
|
i.Consul = i2.Consul
|
||||||
|
|
Loading…
Reference in New Issue