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:
cskh 2023-12-06 14:45:37 -05:00 committed by GitHub
parent 053367a3b2
commit 04d4412afd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 242 additions and 61 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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)
} }
} }

View File

@ -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
} }

View File

@ -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