mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
cli: remove old migration steps and id-file references (#2440)
* Remove old migration steps and id-file references * Update codeowners file --------- Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
9e1a0c06bf
commit
ab8a17e535
@ -6,7 +6,6 @@
|
|||||||
/bazel/sh @katexochen
|
/bazel/sh @katexochen
|
||||||
/bootstrapper @3u13r
|
/bootstrapper @3u13r
|
||||||
/cli/internal/cloudcmd @daniel-weisse
|
/cli/internal/cloudcmd @daniel-weisse
|
||||||
/cli/internal/clusterid @malt3
|
|
||||||
/cli/internal/cmd/upgrade* @derpsteb
|
/cli/internal/cmd/upgrade* @derpsteb
|
||||||
/cli/internal/featureset @malt3
|
/cli/internal/featureset @malt3
|
||||||
/cli/internal/helm @derpsteb
|
/cli/internal/helm @derpsteb
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|
||||||
load("//bazel/go:go_test.bzl", "go_test")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "clusterid",
|
|
||||||
srcs = ["id.go"],
|
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/clusterid",
|
|
||||||
visibility = ["//cli:__subpackages__"],
|
|
||||||
deps = [
|
|
||||||
"//internal/cloud/cloudprovider",
|
|
||||||
"//internal/config",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
go_test(
|
|
||||||
name = "clusterid_test",
|
|
||||||
srcs = ["id_test.go"],
|
|
||||||
embed = [":clusterid"],
|
|
||||||
deps = ["@com_github_stretchr_testify//require"],
|
|
||||||
)
|
|
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) Edgeless Systems GmbH
|
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
// package clusterid defines the structure of the Constellation cluster ID file.
|
|
||||||
// Logic in this package should be kept minimal.
|
|
||||||
package clusterid
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// File contains state information about a cluster.
|
|
||||||
// This information is accessible after the creation
|
|
||||||
// and can be used by further operations such as initialization and upgrades.
|
|
||||||
type File struct {
|
|
||||||
// ClusterID is the unique identifier of the cluster.
|
|
||||||
ClusterID string `json:"clusterID,omitempty"`
|
|
||||||
// OwnerID is the unique identifier of the owner of the cluster.
|
|
||||||
OwnerID string `json:"ownerID,omitempty"`
|
|
||||||
// UID is the unique identifier of the cluster, used for infrastructure management.
|
|
||||||
UID string `json:"uid,omitempty"`
|
|
||||||
// CloudProvider is the cloud provider of the cluster.
|
|
||||||
CloudProvider cloudprovider.Provider `json:"cloudprovider,omitempty"`
|
|
||||||
// IP is the IP address the cluster can be reached at (often the load balancer).
|
|
||||||
IP string `json:"ip,omitempty"`
|
|
||||||
// APIServerCertSANs are subject alternative names (SAN) that are added to
|
|
||||||
// the TLS certificate of each apiserver instance.
|
|
||||||
APIServerCertSANs []string `json:"apiServerCertSANs,omitempty"`
|
|
||||||
// InitSecret is the secret the first Bootstrapper uses to verify the user.
|
|
||||||
InitSecret []byte `json:"initsecret,omitempty"`
|
|
||||||
// AttestationURL is the URL of the attestation service.
|
|
||||||
// It is only set if the cluster is created on Azure.
|
|
||||||
AttestationURL string `json:"attestationURL,omitempty"`
|
|
||||||
// MeasurementSalt is the salt generated during cluster init.
|
|
||||||
MeasurementSalt []byte `json:"measurementSalt,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge merges the other file into the current file and returns the result.
|
|
||||||
// If a field is set in both files, the value of the other file is used.
|
|
||||||
// This does in-place changes on the current file.
|
|
||||||
func (f *File) Merge(other File) *File {
|
|
||||||
if other.ClusterID != "" {
|
|
||||||
f.ClusterID = other.ClusterID
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.OwnerID != "" {
|
|
||||||
f.OwnerID = other.OwnerID
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.UID != "" {
|
|
||||||
f.UID = other.UID
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.CloudProvider != cloudprovider.Unknown {
|
|
||||||
f.CloudProvider = other.CloudProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.IP != "" {
|
|
||||||
f.IP = other.IP
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.InitSecret != nil {
|
|
||||||
f.InitSecret = other.InitSecret
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.AttestationURL != "" {
|
|
||||||
f.AttestationURL = other.AttestationURL
|
|
||||||
}
|
|
||||||
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetClusterName returns the name of the cluster.
|
|
||||||
func GetClusterName(cfg *config.Config, idFile File) string {
|
|
||||||
return cfg.Name + "-" + idFile.UID
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) Edgeless Systems GmbH
|
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package clusterid
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMerge(t *testing.T) {
|
|
||||||
testCases := map[string]struct {
|
|
||||||
current File
|
|
||||||
other File
|
|
||||||
want File
|
|
||||||
}{
|
|
||||||
"empty": {
|
|
||||||
current: File{},
|
|
||||||
other: File{},
|
|
||||||
want: File{},
|
|
||||||
},
|
|
||||||
"current empty": {
|
|
||||||
current: File{},
|
|
||||||
other: File{
|
|
||||||
ClusterID: "clusterID",
|
|
||||||
},
|
|
||||||
want: File{
|
|
||||||
ClusterID: "clusterID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"other empty": {
|
|
||||||
current: File{
|
|
||||||
ClusterID: "clusterID",
|
|
||||||
},
|
|
||||||
other: File{},
|
|
||||||
want: File{
|
|
||||||
ClusterID: "clusterID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"both set": {
|
|
||||||
current: File{
|
|
||||||
ClusterID: "clusterID",
|
|
||||||
},
|
|
||||||
other: File{
|
|
||||||
ClusterID: "otherClusterID",
|
|
||||||
},
|
|
||||||
want: File{
|
|
||||||
ClusterID: "otherClusterID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
ret := tc.current.Merge(tc.other)
|
|
||||||
require.Equal(tc.want, *ret)
|
|
||||||
}
|
|
||||||
}
|
|
@ -40,7 +40,6 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//bootstrapper/initproto",
|
"//bootstrapper/initproto",
|
||||||
"//cli/internal/cloudcmd",
|
"//cli/internal/cloudcmd",
|
||||||
"//cli/internal/clusterid",
|
|
||||||
"//cli/internal/cmd/pathprefix",
|
"//cli/internal/cmd/pathprefix",
|
||||||
"//cli/internal/featureset",
|
"//cli/internal/featureset",
|
||||||
"//cli/internal/helm",
|
"//cli/internal/helm",
|
||||||
@ -135,7 +134,6 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"//bootstrapper/initproto",
|
"//bootstrapper/initproto",
|
||||||
"//cli/internal/cloudcmd",
|
"//cli/internal/cloudcmd",
|
||||||
"//cli/internal/clusterid",
|
|
||||||
"//cli/internal/cmd/pathprefix",
|
"//cli/internal/cmd/pathprefix",
|
||||||
"//cli/internal/helm",
|
"//cli/internal/helm",
|
||||||
"//cli/internal/kubecmd",
|
"//cli/internal/kubecmd",
|
||||||
|
@ -84,11 +84,6 @@ func terminate(cmd *cobra.Command, terminator cloudTerminator, fileHandler file.
|
|||||||
removeErr = errors.Join(err, fmt.Errorf("failed to remove file: '%s', please remove it manually", pf.PrefixPrintablePath(constants.AdminConfFilename)))
|
removeErr = errors.Join(err, fmt.Errorf("failed to remove file: '%s', please remove it manually", pf.PrefixPrintablePath(constants.AdminConfFilename)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(msanft): Once v2.12.0 is released, remove the ID-file-removal here.
|
|
||||||
if err := fileHandler.Remove(constants.ClusterIDsFilename); err != nil && !errors.Is(err, fs.ErrNotExist) {
|
|
||||||
removeErr = errors.Join(err, fmt.Errorf("failed to remove file: '%s', please remove it manually", pf.PrefixPrintablePath(constants.ClusterIDsFilename)))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := fileHandler.Remove(constants.StateFilename); err != nil && !errors.Is(err, fs.ErrNotExist) {
|
if err := fileHandler.Remove(constants.StateFilename); err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||||
removeErr = errors.Join(err, fmt.Errorf("failed to remove file: '%s', please remove it manually", pf.PrefixPrintablePath(constants.StateFilename)))
|
removeErr = errors.Join(err, fmt.Errorf("failed to remove file: '%s', please remove it manually", pf.PrefixPrintablePath(constants.StateFilename)))
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,11 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/cmd/pathprefix"
|
"github.com/edgelesssys/constellation/v2/cli/internal/cmd/pathprefix"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubecmd"
|
"github.com/edgelesssys/constellation/v2/cli/internal/kubecmd"
|
||||||
@ -31,7 +29,6 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
|
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/semver"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
"github.com/rogpeppe/go-internal/diff"
|
"github.com/rogpeppe/go-internal/diff"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
@ -114,11 +111,6 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error {
|
|||||||
return fmt.Errorf("setting up cluster upgrader: %w", err)
|
return fmt.Errorf("setting up cluster upgrader: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up terraform client to show existing cluster resources and information required for Helm upgrades
|
|
||||||
tfShower, err := terraform.New(cmd.Context(), constants.TerraformWorkingDir)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("setting up terraform client: %w", err)
|
|
||||||
}
|
|
||||||
helmClient, err := helm.NewClient(constants.AdminConfFilename, log)
|
helmClient, err := helm.NewClient(constants.AdminConfFilename, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("creating Helm client: %w", err)
|
return fmt.Errorf("creating Helm client: %w", err)
|
||||||
@ -129,7 +121,6 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error {
|
|||||||
helmApplier: helmClient,
|
helmApplier: helmClient,
|
||||||
clusterUpgrader: clusterUpgrader,
|
clusterUpgrader: clusterUpgrader,
|
||||||
configFetcher: configFetcher,
|
configFetcher: configFetcher,
|
||||||
clusterShower: tfShower,
|
|
||||||
fileHandler: fileHandler,
|
fileHandler: fileHandler,
|
||||||
log: log,
|
log: log,
|
||||||
}
|
}
|
||||||
@ -141,15 +132,10 @@ type upgradeApplyCmd struct {
|
|||||||
kubeUpgrader kubernetesUpgrader
|
kubeUpgrader kubernetesUpgrader
|
||||||
clusterUpgrader clusterUpgrader
|
clusterUpgrader clusterUpgrader
|
||||||
configFetcher attestationconfigapi.Fetcher
|
configFetcher attestationconfigapi.Fetcher
|
||||||
clusterShower infrastructureShower
|
|
||||||
fileHandler file.Handler
|
fileHandler file.Handler
|
||||||
log debugLog
|
log debugLog
|
||||||
}
|
}
|
||||||
|
|
||||||
type infrastructureShower interface {
|
|
||||||
ShowInfrastructure(ctx context.Context, provider cloudprovider.Provider) (state.Infrastructure, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, upgradeDir string, flags upgradeApplyFlags) error {
|
func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, upgradeDir string, flags upgradeApplyFlags) error {
|
||||||
conf, err := config.New(u.fileHandler, constants.ConfigFilename, u.configFetcher, flags.force)
|
conf, err := config.New(u.fileHandler, constants.ConfigFilename, u.configFetcher, flags.force)
|
||||||
var configValidationErr *config.ValidationError
|
var configValidationErr *config.ValidationError
|
||||||
@ -178,32 +164,10 @@ func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, upgradeDir string, fl
|
|||||||
}
|
}
|
||||||
|
|
||||||
stateFile, err := state.ReadFromFile(u.fileHandler, constants.StateFilename)
|
stateFile, err := state.ReadFromFile(u.fileHandler, constants.StateFilename)
|
||||||
// TODO(msanft): Remove reading from idFile once v2.12.0 is released and read from state file directly.
|
if err != nil {
|
||||||
// For now, this is only here to ensure upgradability from an id-file to a state file version.
|
|
||||||
if errors.Is(err, fs.ErrNotExist) {
|
|
||||||
u.log.Debugf("%s does not exist in current directory, falling back to reading from %s",
|
|
||||||
constants.StateFilename, constants.ClusterIDsFilename)
|
|
||||||
var idFile clusterid.File
|
|
||||||
if err := u.fileHandler.ReadJSON(constants.ClusterIDsFilename, &idFile); err != nil {
|
|
||||||
return fmt.Errorf("reading cluster ID file: %w", err)
|
|
||||||
}
|
|
||||||
// Convert id-file to state file
|
|
||||||
stateFile = state.NewFromIDFile(idFile, conf)
|
|
||||||
if stateFile.Infrastructure.Azure != nil {
|
|
||||||
conf.UpdateMAAURL(stateFile.Infrastructure.Azure.AttestationURL)
|
|
||||||
}
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("reading state file: %w", err)
|
return fmt.Errorf("reading state file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply migrations necessary for the upgrade
|
|
||||||
if err := migrateFrom2_10(cmd.Context(), u.kubeUpgrader); err != nil {
|
|
||||||
return fmt.Errorf("applying migration for upgrading from v2.10: %w", err)
|
|
||||||
}
|
|
||||||
if err := migrateFrom2_11(cmd.Context(), u.kubeUpgrader); err != nil {
|
|
||||||
return fmt.Errorf("applying migration for upgrading from v2.11: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := u.confirmAndUpgradeAttestationConfig(cmd, conf.GetAttestationConfig(), stateFile.ClusterValues.MeasurementSalt, flags); err != nil {
|
if err := u.confirmAndUpgradeAttestationConfig(cmd, conf.GetAttestationConfig(), stateFile.ClusterValues.MeasurementSalt, flags); err != nil {
|
||||||
return fmt.Errorf("upgrading measurements: %w", err)
|
return fmt.Errorf("upgrading measurements: %w", err)
|
||||||
}
|
}
|
||||||
@ -211,47 +175,37 @@ func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, upgradeDir string, fl
|
|||||||
// If infrastructure phase is skipped, we expect the new infrastructure
|
// If infrastructure phase is skipped, we expect the new infrastructure
|
||||||
// to be in the Terraform configuration already. Otherwise, perform
|
// to be in the Terraform configuration already. Otherwise, perform
|
||||||
// the Terraform migrations.
|
// the Terraform migrations.
|
||||||
var postMigrationInfraState state.Infrastructure
|
if !flags.skipPhases.contains(skipInfrastructurePhase) {
|
||||||
if flags.skipPhases.contains(skipInfrastructurePhase) {
|
migrationRequired, err := u.planTerraformMigration(cmd, conf)
|
||||||
// TODO(msanft): Once v2.12.0 is released, this should be removed and the state should be read
|
|
||||||
// from the state file instead, as it will be the only source of truth for the cluster's infrastructure.
|
|
||||||
postMigrationInfraState, err = u.clusterShower.ShowInfrastructure(cmd.Context(), conf.GetProvider())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting Terraform state: %w", err)
|
return fmt.Errorf("planning Terraform migrations: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
postMigrationInfraState, err = u.migrateTerraform(cmd, conf, upgradeDir, flags)
|
if migrationRequired {
|
||||||
if err != nil {
|
postMigrationInfraState, err := u.migrateTerraform(cmd, conf, upgradeDir, flags)
|
||||||
return fmt.Errorf("performing Terraform migrations: %w", err)
|
if err != nil {
|
||||||
|
return fmt.Errorf("performing Terraform migrations: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge the pre-upgrade state with the post-migration infrastructure values
|
||||||
|
if _, err := stateFile.Merge(
|
||||||
|
// temporary state with post-migration infrastructure values
|
||||||
|
state.New().SetInfrastructure(postMigrationInfraState),
|
||||||
|
); err != nil {
|
||||||
|
return fmt.Errorf("merging pre-upgrade state with post-migration infrastructure values: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the post-migration state to disk
|
||||||
|
if err := stateFile.WriteToFile(u.fileHandler, constants.StateFilename); err != nil {
|
||||||
|
return fmt.Errorf("writing state file: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge the pre-upgrade state with the post-migration infrastructure values
|
|
||||||
if _, err := stateFile.Merge(
|
|
||||||
// temporary state with post-migration infrastructure values
|
|
||||||
state.New().SetInfrastructure(postMigrationInfraState),
|
|
||||||
); err != nil {
|
|
||||||
return fmt.Errorf("merging pre-upgrade state with post-migration infrastructure values: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the post-migration state to disk
|
|
||||||
if err := stateFile.WriteToFile(u.fileHandler, constants.StateFilename); err != nil {
|
|
||||||
return fmt.Errorf("writing state file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(msanft): Remove this after v2.12.0 is released, as we do not support
|
|
||||||
// the id-file starting from v2.13.0.
|
|
||||||
err = u.fileHandler.RenameFile(constants.ClusterIDsFilename, constants.ClusterIDsFilename+".old")
|
|
||||||
if !errors.Is(err, fs.ErrNotExist) && err != nil {
|
|
||||||
return fmt.Errorf("removing cluster ID file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// extend the clusterConfig cert SANs with any of the supported endpoints:
|
// extend the clusterConfig cert SANs with any of the supported endpoints:
|
||||||
// - (legacy) public IP
|
// - (legacy) public IP
|
||||||
// - fallback endpoint
|
// - fallback endpoint
|
||||||
// - custom (user-provided) endpoint
|
// - custom (user-provided) endpoint
|
||||||
// TODO(msanft): Remove the comment below once v2.12.0 is released.
|
|
||||||
// At this point, state file and id-file should have been merged, so we can use the state file.
|
|
||||||
sans := append([]string{stateFile.Infrastructure.ClusterEndpoint, conf.CustomEndpoint}, stateFile.Infrastructure.APIServerCertSANs...)
|
sans := append([]string{stateFile.Infrastructure.ClusterEndpoint, conf.CustomEndpoint}, stateFile.Infrastructure.APIServerCertSANs...)
|
||||||
if err := u.kubeUpgrader.ExtendClusterConfigCertSANs(cmd.Context(), sans); err != nil {
|
if err := u.kubeUpgrader.ExtendClusterConfigCertSANs(cmd.Context(), sans); err != nil {
|
||||||
return fmt.Errorf("extending cert SANs: %w", err)
|
return fmt.Errorf("extending cert SANs: %w", err)
|
||||||
@ -304,17 +258,13 @@ func diffAttestationCfg(currentAttestationCfg config.AttestationCfg, newAttestat
|
|||||||
return diff, nil
|
return diff, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// migrateTerraform checks if the Constellation version the cluster is being upgraded to requires a migration
|
// planTerraformMigration checks if the Constellation version the cluster is being upgraded to requires a migration.
|
||||||
// of cloud resources with Terraform. If so, the migration is performed and the post-migration infrastructure state is returned.
|
func (u *upgradeApplyCmd) planTerraformMigration(cmd *cobra.Command, conf *config.Config) (bool, error) {
|
||||||
// If no migration is required, the current (pre-upgrade) infrastructure state is returned.
|
|
||||||
func (u *upgradeApplyCmd) migrateTerraform(
|
|
||||||
cmd *cobra.Command, conf *config.Config, upgradeDir string, flags upgradeApplyFlags,
|
|
||||||
) (state.Infrastructure, error) {
|
|
||||||
u.log.Debugf("Planning Terraform migrations")
|
u.log.Debugf("Planning Terraform migrations")
|
||||||
|
|
||||||
vars, err := cloudcmd.TerraformUpgradeVars(conf)
|
vars, err := cloudcmd.TerraformUpgradeVars(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state.Infrastructure{}, fmt.Errorf("parsing upgrade variables: %w", err)
|
return false, fmt.Errorf("parsing upgrade variables: %w", err)
|
||||||
}
|
}
|
||||||
u.log.Debugf("Using Terraform variables:\n%v", vars)
|
u.log.Debugf("Using Terraform variables:\n%v", vars)
|
||||||
|
|
||||||
@ -328,15 +278,15 @@ func (u *upgradeApplyCmd) migrateTerraform(
|
|||||||
// u.upgrader.AddManualStateMigration(migration)
|
// u.upgrader.AddManualStateMigration(migration)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
hasDiff, err := u.clusterUpgrader.PlanClusterUpgrade(cmd.Context(), cmd.OutOrStdout(), vars, conf.GetProvider())
|
return u.clusterUpgrader.PlanClusterUpgrade(cmd.Context(), cmd.OutOrStdout(), vars, conf.GetProvider())
|
||||||
if err != nil {
|
}
|
||||||
return state.Infrastructure{}, fmt.Errorf("planning terraform migrations: %w", err)
|
|
||||||
}
|
|
||||||
if !hasDiff {
|
|
||||||
u.log.Debugf("No Terraform diff detected")
|
|
||||||
return u.clusterShower.ShowInfrastructure(cmd.Context(), conf.GetProvider())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// migrateTerraform checks if the Constellation version the cluster is being upgraded to requires a migration
|
||||||
|
// of cloud resources with Terraform. If so, the migration is performed and the post-migration infrastructure state is returned.
|
||||||
|
// If no migration is required, the current (pre-upgrade) infrastructure state is returned.
|
||||||
|
func (u *upgradeApplyCmd) migrateTerraform(
|
||||||
|
cmd *cobra.Command, conf *config.Config, upgradeDir string, flags upgradeApplyFlags,
|
||||||
|
) (state.Infrastructure, error) {
|
||||||
// If there are any Terraform migrations to apply, ask for confirmation
|
// If there are any Terraform migrations to apply, ask for confirmation
|
||||||
fmt.Fprintln(cmd.OutOrStdout(), "The upgrade requires a migration of Constellation cloud resources by applying an updated Terraform template. Please manually review the suggested changes below.")
|
fmt.Fprintln(cmd.OutOrStdout(), "The upgrade requires a migration of Constellation cloud resources by applying an updated Terraform template. Please manually review the suggested changes below.")
|
||||||
if !flags.yes {
|
if !flags.yes {
|
||||||
@ -513,34 +463,6 @@ func (u *upgradeApplyCmd) handleServiceUpgrade(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// migrateFrom2_10 applies migrations necessary for upgrading from v2.10 to v2.11
|
|
||||||
// TODO(v2.11): Remove this function after v2.11 is released.
|
|
||||||
func migrateFrom2_10(ctx context.Context, kubeUpgrader kubernetesUpgrader) error {
|
|
||||||
// Sanity check to make sure we only run migrations on upgrades with CLI version 2.10 < v < 2.12
|
|
||||||
if !constants.BinaryVersion().MajorMinorEqual(semver.NewFromInt(2, 11, 0, "")) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := kubeUpgrader.RemoveAttestationConfigHelmManagement(ctx); err != nil {
|
|
||||||
return fmt.Errorf("removing helm management from attestation config: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// migrateFrom2_11 applies migrations necessary for upgrading from v2.11 to v2.12
|
|
||||||
// TODO(v2.12): Remove this function after v2.12 is released.
|
|
||||||
func migrateFrom2_11(ctx context.Context, kubeUpgrader kubernetesUpgrader) error {
|
|
||||||
// Sanity check to make sure we only run migrations on upgrades with CLI version 2.11 < v < 2.13
|
|
||||||
if !constants.BinaryVersion().MajorMinorEqual(semver.NewFromInt(2, 12, 0, "")) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := kubeUpgrader.RemoveHelmKeepAnnotation(ctx); err != nil {
|
|
||||||
return fmt.Errorf("removing helm keep annotation: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseUpgradeApplyFlags(cmd *cobra.Command) (upgradeApplyFlags, error) {
|
func parseUpgradeApplyFlags(cmd *cobra.Command) (upgradeApplyFlags, error) {
|
||||||
workDir, err := cmd.Flags().GetString("workspace")
|
workDir, err := cmd.Flags().GetString("workspace")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -641,10 +563,6 @@ type kubernetesUpgrader interface {
|
|||||||
ApplyJoinConfig(ctx context.Context, newAttestConfig config.AttestationCfg, measurementSalt []byte) error
|
ApplyJoinConfig(ctx context.Context, newAttestConfig config.AttestationCfg, measurementSalt []byte) error
|
||||||
BackupCRs(ctx context.Context, crds []apiextensionsv1.CustomResourceDefinition, upgradeDir string) error
|
BackupCRs(ctx context.Context, crds []apiextensionsv1.CustomResourceDefinition, upgradeDir string) error
|
||||||
BackupCRDs(ctx context.Context, upgradeDir string) ([]apiextensionsv1.CustomResourceDefinition, error)
|
BackupCRDs(ctx context.Context, upgradeDir string) ([]apiextensionsv1.CustomResourceDefinition, error)
|
||||||
// TODO(v2.11): Remove this function after v2.11 is released.
|
|
||||||
RemoveAttestationConfigHelmManagement(ctx context.Context) error
|
|
||||||
// TODO(v2.12): Remove this function after v2.12 is released.
|
|
||||||
RemoveHelmKeepAnnotation(ctx context.Context) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type clusterUpgrader interface {
|
type clusterUpgrader interface {
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubecmd"
|
"github.com/edgelesssys/constellation/v2/cli/internal/kubecmd"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/state"
|
"github.com/edgelesssys/constellation/v2/cli/internal/state"
|
||||||
@ -42,16 +41,6 @@ func TestUpgradeApply(t *testing.T) {
|
|||||||
InitSecret: []byte{0x42},
|
InitSecret: []byte{0x42},
|
||||||
}).
|
}).
|
||||||
SetClusterValues(state.ClusterValues{MeasurementSalt: []byte{0x41}})
|
SetClusterValues(state.ClusterValues{MeasurementSalt: []byte{0x41}})
|
||||||
defaultIDFile := clusterid.File{
|
|
||||||
MeasurementSalt: []byte{0x41},
|
|
||||||
UID: "uid",
|
|
||||||
InitSecret: []byte{0x42},
|
|
||||||
}
|
|
||||||
fsWithIDFile := func() file.Handler {
|
|
||||||
fh := file.NewHandler(afero.NewMemMapFs())
|
|
||||||
require.NoError(t, fh.WriteJSON(constants.ClusterIDsFilename, defaultIDFile))
|
|
||||||
return fh
|
|
||||||
}
|
|
||||||
fsWithStateFile := func() file.Handler {
|
fsWithStateFile := func() file.Handler {
|
||||||
fh := file.NewHandler(afero.NewMemMapFs())
|
fh := file.NewHandler(afero.NewMemMapFs())
|
||||||
require.NoError(t, fh.WriteYAML(constants.StateFilename, defaultState))
|
require.NoError(t, fh.WriteYAML(constants.StateFilename, defaultState))
|
||||||
@ -59,24 +48,22 @@ func TestUpgradeApply(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
helmUpgrader helmApplier
|
helmUpgrader helmApplier
|
||||||
kubeUpgrader *stubKubernetesUpgrader
|
kubeUpgrader *stubKubernetesUpgrader
|
||||||
fh func() file.Handler
|
fh func() file.Handler
|
||||||
fhAssertions func(require *require.Assertions, assert *assert.Assertions, fh file.Handler)
|
fhAssertions func(require *require.Assertions, assert *assert.Assertions, fh file.Handler)
|
||||||
terraformUpgrader clusterUpgrader
|
terraformUpgrader clusterUpgrader
|
||||||
infrastructureShower *stubShowInfrastructure
|
wantErr bool
|
||||||
wantErr bool
|
customK8sVersion string
|
||||||
customK8sVersion string
|
flags upgradeApplyFlags
|
||||||
flags upgradeApplyFlags
|
stdin string
|
||||||
stdin string
|
|
||||||
}{
|
}{
|
||||||
"success": {
|
"success": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{currentConfig: config.DefaultForAzureSEVSNP()},
|
kubeUpgrader: &stubKubernetesUpgrader{currentConfig: config.DefaultForAzureSEVSNP()},
|
||||||
helmUpgrader: stubApplier{},
|
helmUpgrader: stubApplier{},
|
||||||
terraformUpgrader: &stubTerraformUpgrader{},
|
terraformUpgrader: &stubTerraformUpgrader{},
|
||||||
flags: upgradeApplyFlags{yes: true},
|
flags: upgradeApplyFlags{yes: true},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
fhAssertions: func(require *require.Assertions, assert *assert.Assertions, fh file.Handler) {
|
fhAssertions: func(require *require.Assertions, assert *assert.Assertions, fh file.Handler) {
|
||||||
gotState, err := state.ReadFromFile(fh, constants.StateFilename)
|
gotState, err := state.ReadFromFile(fh, constants.StateFilename)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
@ -84,30 +71,11 @@ func TestUpgradeApply(t *testing.T) {
|
|||||||
assert.Equal(defaultState, gotState)
|
assert.Equal(defaultState, gotState)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"fall back to id file": {
|
"state file does not exist": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{currentConfig: config.DefaultForAzureSEVSNP()},
|
kubeUpgrader: &stubKubernetesUpgrader{currentConfig: config.DefaultForAzureSEVSNP()},
|
||||||
helmUpgrader: stubApplier{},
|
helmUpgrader: stubApplier{},
|
||||||
terraformUpgrader: &stubTerraformUpgrader{},
|
terraformUpgrader: &stubTerraformUpgrader{},
|
||||||
flags: upgradeApplyFlags{yes: true},
|
flags: upgradeApplyFlags{yes: true},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
|
||||||
fh: fsWithIDFile,
|
|
||||||
fhAssertions: func(require *require.Assertions, assert *assert.Assertions, fh file.Handler) {
|
|
||||||
gotState, err := state.ReadFromFile(fh, constants.StateFilename)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Equal("v1", gotState.Version)
|
|
||||||
assert.Equal(defaultState, gotState)
|
|
||||||
var oldIDFile clusterid.File
|
|
||||||
err = fh.ReadJSON(constants.ClusterIDsFilename+".old", &oldIDFile)
|
|
||||||
assert.NoError(err)
|
|
||||||
assert.Equal(defaultIDFile, oldIDFile)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"id file and state file do not exist": {
|
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{currentConfig: config.DefaultForAzureSEVSNP()},
|
|
||||||
helmUpgrader: stubApplier{},
|
|
||||||
terraformUpgrader: &stubTerraformUpgrader{},
|
|
||||||
flags: upgradeApplyFlags{yes: true},
|
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
|
||||||
fh: func() file.Handler {
|
fh: func() file.Handler {
|
||||||
return file.NewHandler(afero.NewMemMapFs())
|
return file.NewHandler(afero.NewMemMapFs())
|
||||||
},
|
},
|
||||||
@ -118,67 +86,61 @@ func TestUpgradeApply(t *testing.T) {
|
|||||||
currentConfig: config.DefaultForAzureSEVSNP(),
|
currentConfig: config.DefaultForAzureSEVSNP(),
|
||||||
nodeVersionErr: assert.AnError,
|
nodeVersionErr: assert.AnError,
|
||||||
},
|
},
|
||||||
helmUpgrader: stubApplier{},
|
helmUpgrader: stubApplier{},
|
||||||
terraformUpgrader: &stubTerraformUpgrader{},
|
terraformUpgrader: &stubTerraformUpgrader{},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
flags: upgradeApplyFlags{yes: true},
|
flags: upgradeApplyFlags{yes: true},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"nodeVersion in progress error": {
|
"nodeVersion in progress error": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
currentConfig: config.DefaultForAzureSEVSNP(),
|
currentConfig: config.DefaultForAzureSEVSNP(),
|
||||||
nodeVersionErr: kubecmd.ErrInProgress,
|
nodeVersionErr: kubecmd.ErrInProgress,
|
||||||
},
|
},
|
||||||
helmUpgrader: stubApplier{},
|
helmUpgrader: stubApplier{},
|
||||||
terraformUpgrader: &stubTerraformUpgrader{},
|
terraformUpgrader: &stubTerraformUpgrader{},
|
||||||
flags: upgradeApplyFlags{yes: true},
|
flags: upgradeApplyFlags{yes: true},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"helm other error": {
|
"helm other error": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
currentConfig: config.DefaultForAzureSEVSNP(),
|
currentConfig: config.DefaultForAzureSEVSNP(),
|
||||||
},
|
},
|
||||||
helmUpgrader: stubApplier{err: assert.AnError},
|
helmUpgrader: stubApplier{err: assert.AnError},
|
||||||
terraformUpgrader: &stubTerraformUpgrader{},
|
terraformUpgrader: &stubTerraformUpgrader{},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
flags: upgradeApplyFlags{yes: true},
|
flags: upgradeApplyFlags{yes: true},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
currentConfig: config.DefaultForAzureSEVSNP(),
|
currentConfig: config.DefaultForAzureSEVSNP(),
|
||||||
},
|
},
|
||||||
helmUpgrader: stubApplier{},
|
helmUpgrader: stubApplier{},
|
||||||
terraformUpgrader: &stubTerraformUpgrader{terraformDiff: true},
|
terraformUpgrader: &stubTerraformUpgrader{terraformDiff: true},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
stdin: "no\n",
|
stdin: "no\n",
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"abort, restore terraform err": {
|
"abort, restore terraform err": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
currentConfig: config.DefaultForAzureSEVSNP(),
|
currentConfig: config.DefaultForAzureSEVSNP(),
|
||||||
},
|
},
|
||||||
helmUpgrader: stubApplier{},
|
helmUpgrader: stubApplier{},
|
||||||
terraformUpgrader: &stubTerraformUpgrader{terraformDiff: true, rollbackWorkspaceErr: assert.AnError},
|
terraformUpgrader: &stubTerraformUpgrader{terraformDiff: true, rollbackWorkspaceErr: assert.AnError},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
stdin: "no\n",
|
stdin: "no\n",
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"plan terraform error": {
|
"plan terraform error": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
currentConfig: config.DefaultForAzureSEVSNP(),
|
currentConfig: config.DefaultForAzureSEVSNP(),
|
||||||
},
|
},
|
||||||
helmUpgrader: stubApplier{},
|
helmUpgrader: stubApplier{},
|
||||||
terraformUpgrader: &stubTerraformUpgrader{planTerraformErr: assert.AnError},
|
terraformUpgrader: &stubTerraformUpgrader{planTerraformErr: assert.AnError},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
flags: upgradeApplyFlags{yes: true},
|
flags: upgradeApplyFlags{yes: true},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"apply terraform error": {
|
"apply terraform error": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
@ -189,10 +151,9 @@ func TestUpgradeApply(t *testing.T) {
|
|||||||
applyTerraformErr: assert.AnError,
|
applyTerraformErr: assert.AnError,
|
||||||
terraformDiff: true,
|
terraformDiff: true,
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
flags: upgradeApplyFlags{yes: true},
|
flags: upgradeApplyFlags{yes: true},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"outdated K8s patch version": {
|
"outdated K8s patch version": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
@ -205,21 +166,19 @@ func TestUpgradeApply(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return semver.NewFromInt(v.Major(), v.Minor(), v.Patch()-1, "").String()
|
return semver.NewFromInt(v.Major(), v.Minor(), v.Patch()-1, "").String()
|
||||||
}(),
|
}(),
|
||||||
flags: upgradeApplyFlags{yes: true},
|
flags: upgradeApplyFlags{yes: true},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"outdated K8s version": {
|
"outdated K8s version": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
currentConfig: config.DefaultForAzureSEVSNP(),
|
currentConfig: config.DefaultForAzureSEVSNP(),
|
||||||
},
|
},
|
||||||
helmUpgrader: stubApplier{},
|
helmUpgrader: stubApplier{},
|
||||||
terraformUpgrader: &stubTerraformUpgrader{},
|
terraformUpgrader: &stubTerraformUpgrader{},
|
||||||
customK8sVersion: "v1.20.0",
|
customK8sVersion: "v1.20.0",
|
||||||
flags: upgradeApplyFlags{yes: true},
|
flags: upgradeApplyFlags{yes: true},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"skip all upgrade phases": {
|
"skip all upgrade phases": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
@ -231,24 +190,7 @@ func TestUpgradeApply(t *testing.T) {
|
|||||||
skipPhases: []skipPhase{skipInfrastructurePhase, skipHelmPhase, skipK8sPhase, skipImagePhase},
|
skipPhases: []skipPhase{skipInfrastructurePhase, skipHelmPhase, skipK8sPhase, skipImagePhase},
|
||||||
yes: true,
|
yes: true,
|
||||||
},
|
},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
|
||||||
"show state err": {
|
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
|
||||||
currentConfig: config.DefaultForAzureSEVSNP(),
|
|
||||||
},
|
|
||||||
helmUpgrader: &stubApplier{},
|
|
||||||
terraformUpgrader: &stubTerraformUpgrader{},
|
|
||||||
flags: upgradeApplyFlags{
|
|
||||||
skipPhases: []skipPhase{skipInfrastructurePhase},
|
|
||||||
yes: true,
|
|
||||||
},
|
|
||||||
infrastructureShower: &stubShowInfrastructure{
|
|
||||||
showInfraErr: assert.AnError,
|
|
||||||
},
|
|
||||||
wantErr: true,
|
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
"skip all phases except node upgrade": {
|
"skip all phases except node upgrade": {
|
||||||
kubeUpgrader: &stubKubernetesUpgrader{
|
kubeUpgrader: &stubKubernetesUpgrader{
|
||||||
@ -260,8 +202,7 @@ func TestUpgradeApply(t *testing.T) {
|
|||||||
skipPhases: []skipPhase{skipInfrastructurePhase, skipHelmPhase, skipK8sPhase},
|
skipPhases: []skipPhase{skipInfrastructurePhase, skipHelmPhase, skipK8sPhase},
|
||||||
yes: true,
|
yes: true,
|
||||||
},
|
},
|
||||||
infrastructureShower: &stubShowInfrastructure{},
|
fh: fsWithStateFile,
|
||||||
fh: fsWithStateFile,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +227,6 @@ func TestUpgradeApply(t *testing.T) {
|
|||||||
clusterUpgrader: tc.terraformUpgrader,
|
clusterUpgrader: tc.terraformUpgrader,
|
||||||
log: logger.NewTest(t),
|
log: logger.NewTest(t),
|
||||||
configFetcher: stubAttestationFetcher{},
|
configFetcher: stubAttestationFetcher{},
|
||||||
clusterShower: tc.infrastructureShower,
|
|
||||||
fileHandler: fh,
|
fileHandler: fh,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,11 +348,3 @@ func (m *mockApplier) PrepareApply(cfg *config.Config, stateFile *state.State,
|
|||||||
args := m.Called(cfg, stateFile, helmOpts, str, masterSecret)
|
args := m.Called(cfg, stateFile, helmOpts, str, masterSecret)
|
||||||
return args.Get(0).(helm.Applier), args.Bool(1), args.Error(2)
|
return args.Get(0).(helm.Applier), args.Bool(1), args.Error(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
type stubShowInfrastructure struct {
|
|
||||||
showInfraErr error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stubShowInfrastructure) ShowInfrastructure(context.Context, cloudprovider.Provider) (state.Infrastructure, error) {
|
|
||||||
return state.Infrastructure{}, s.showInfraErr
|
|
||||||
}
|
|
||||||
|
@ -35,7 +35,6 @@ go_library(
|
|||||||
"@io_k8s_client_go//util/retry",
|
"@io_k8s_client_go//util/retry",
|
||||||
"@io_k8s_kubernetes//cmd/kubeadm/app/apis/kubeadm/v1beta3",
|
"@io_k8s_kubernetes//cmd/kubeadm/app/apis/kubeadm/v1beta3",
|
||||||
"@io_k8s_sigs_yaml//:yaml",
|
"@io_k8s_sigs_yaml//:yaml",
|
||||||
"@sh_helm_helm_v3//pkg/kube",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions/components"
|
"github.com/edgelesssys/constellation/v2/internal/versions/components"
|
||||||
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
||||||
"helm.sh/helm/v3/pkg/kube"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -476,72 +475,6 @@ func joinConfigMap(attestationCfgJSON, measurementSalt []byte) *corev1.ConfigMap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveAttestationConfigHelmManagement removes labels and annotations from the join-config ConfigMap that are added by Helm.
|
|
||||||
// This is to ensure we can cleanly transition from Helm to Constellation's management of the ConfigMap.
|
|
||||||
// TODO(v2.11): Remove this function after v2.11 is released.
|
|
||||||
func (k *KubeCmd) RemoveAttestationConfigHelmManagement(ctx context.Context) error {
|
|
||||||
const (
|
|
||||||
appManagedByLabel = "app.kubernetes.io/managed-by"
|
|
||||||
appManagedByHelm = "Helm"
|
|
||||||
helmReleaseNameAnnotation = "meta.helm.sh/release-name"
|
|
||||||
helmReleaseNamespaceAnnotation = "meta.helm.sh/release-namespace"
|
|
||||||
)
|
|
||||||
|
|
||||||
k.log.Debugf("Checking if join-config ConfigMap needs to be migrated to remove Helm management")
|
|
||||||
joinConfig, err := k.kubectl.GetConfigMap(ctx, constants.ConstellationNamespace, constants.JoinConfigMap)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("getting join config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var needUpdate bool
|
|
||||||
if managedBy, ok := joinConfig.Labels[appManagedByLabel]; ok && managedBy == appManagedByHelm {
|
|
||||||
delete(joinConfig.Labels, appManagedByLabel)
|
|
||||||
needUpdate = true
|
|
||||||
}
|
|
||||||
if _, ok := joinConfig.Annotations[helmReleaseNameAnnotation]; ok {
|
|
||||||
delete(joinConfig.Annotations, helmReleaseNameAnnotation)
|
|
||||||
needUpdate = true
|
|
||||||
}
|
|
||||||
if _, ok := joinConfig.Annotations[helmReleaseNamespaceAnnotation]; ok {
|
|
||||||
delete(joinConfig.Annotations, helmReleaseNamespaceAnnotation)
|
|
||||||
needUpdate = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if needUpdate {
|
|
||||||
// Tell Helm to ignore this resource in the future.
|
|
||||||
// TODO(v2.11): Remove this annotation from the ConfigMap.
|
|
||||||
joinConfig.Annotations[kube.ResourcePolicyAnno] = kube.KeepPolicy
|
|
||||||
|
|
||||||
k.log.Debugf("Removing Helm management labels from join-config ConfigMap")
|
|
||||||
if _, err := k.kubectl.UpdateConfigMap(ctx, joinConfig); err != nil {
|
|
||||||
return fmt.Errorf("removing Helm management labels from join-config: %w", err)
|
|
||||||
}
|
|
||||||
k.log.Debugf("Successfully removed Helm management labels from join-config ConfigMap")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveHelmKeepAnnotation removes the Helm Resource Policy annotation from the join-config ConfigMap.
|
|
||||||
// TODO(v2.12): Remove this function after v2.12 is released.
|
|
||||||
func (k *KubeCmd) RemoveHelmKeepAnnotation(ctx context.Context) error {
|
|
||||||
k.log.Debugf("Checking if Helm Resource Policy can be removed from join-config ConfigMap")
|
|
||||||
joinConfig, err := k.kubectl.GetConfigMap(ctx, constants.ConstellationNamespace, constants.JoinConfigMap)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("getting join config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if policy, ok := joinConfig.Annotations[kube.ResourcePolicyAnno]; ok && policy == kube.KeepPolicy {
|
|
||||||
delete(joinConfig.Annotations, kube.ResourcePolicyAnno)
|
|
||||||
if _, err := k.kubectl.UpdateConfigMap(ctx, joinConfig); err != nil {
|
|
||||||
return fmt.Errorf("removing Helm Resource Policy from join-config: %w", err)
|
|
||||||
}
|
|
||||||
k.log.Debugf("Successfully removed Helm Resource Policy from join-config ConfigMap")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type kubeDoer struct {
|
type kubeDoer struct {
|
||||||
action func(ctx context.Context) error
|
action func(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ go_library(
|
|||||||
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/state",
|
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/state",
|
||||||
visibility = ["//cli:__subpackages__"],
|
visibility = ["//cli:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//cli/internal/clusterid",
|
|
||||||
"//internal/config",
|
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
"@cat_dario_mergo//:mergo",
|
"@cat_dario_mergo//:mergo",
|
||||||
],
|
],
|
||||||
@ -19,8 +17,6 @@ go_test(
|
|||||||
srcs = ["state_test.go"],
|
srcs = ["state_test.go"],
|
||||||
embed = [":state"],
|
embed = [":state"],
|
||||||
deps = [
|
deps = [
|
||||||
"//cli/internal/clusterid",
|
|
||||||
"//internal/config",
|
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
"@com_github_spf13_afero//:afero",
|
"@com_github_spf13_afero//:afero",
|
||||||
|
@ -11,8 +11,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"dario.cat/mergo"
|
"dario.cat/mergo"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,31 +42,6 @@ func New() *State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFromIDFile creates a new cluster state file from the given ID file and config.
|
|
||||||
func NewFromIDFile(idFile clusterid.File, cfg *config.Config) *State {
|
|
||||||
s := New().
|
|
||||||
SetClusterValues(ClusterValues{
|
|
||||||
OwnerID: idFile.OwnerID,
|
|
||||||
ClusterID: idFile.ClusterID,
|
|
||||||
MeasurementSalt: idFile.MeasurementSalt,
|
|
||||||
}).
|
|
||||||
SetInfrastructure(Infrastructure{
|
|
||||||
UID: idFile.UID,
|
|
||||||
ClusterEndpoint: idFile.IP,
|
|
||||||
APIServerCertSANs: idFile.APIServerCertSANs,
|
|
||||||
InitSecret: idFile.InitSecret,
|
|
||||||
Name: clusterid.GetClusterName(cfg, idFile),
|
|
||||||
})
|
|
||||||
|
|
||||||
if idFile.AttestationURL != "" {
|
|
||||||
s.Infrastructure.Azure = &Azure{
|
|
||||||
AttestationURL: idFile.AttestationURL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetInfrastructure sets the infrastructure state.
|
// SetInfrastructure sets the infrastructure state.
|
||||||
func (s *State) SetInfrastructure(infrastructure Infrastructure) *State {
|
func (s *State) SetInfrastructure(infrastructure Infrastructure) *State {
|
||||||
s.Infrastructure = infrastructure
|
s.Infrastructure = infrastructure
|
||||||
|
@ -9,8 +9,6 @@ package state
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
@ -328,65 +326,3 @@ func TestMerge(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewFromIDFile(t *testing.T) {
|
|
||||||
testCases := map[string]struct {
|
|
||||||
idFile clusterid.File
|
|
||||||
cfg *config.Config
|
|
||||||
expected *State
|
|
||||||
}{
|
|
||||||
"success": {
|
|
||||||
idFile: clusterid.File{
|
|
||||||
ClusterID: "test-cluster-id",
|
|
||||||
UID: "test-uid",
|
|
||||||
},
|
|
||||||
cfg: config.Default(),
|
|
||||||
expected: &State{
|
|
||||||
Version: Version1,
|
|
||||||
Infrastructure: Infrastructure{
|
|
||||||
UID: "test-uid",
|
|
||||||
Name: "constell-test-uid",
|
|
||||||
},
|
|
||||||
ClusterValues: ClusterValues{
|
|
||||||
ClusterID: "test-cluster-id",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"empty id file": {
|
|
||||||
idFile: clusterid.File{},
|
|
||||||
cfg: config.Default(),
|
|
||||||
expected: &State{Version: Version1, Infrastructure: Infrastructure{Name: "constell-"}},
|
|
||||||
},
|
|
||||||
"nested pointer": {
|
|
||||||
idFile: clusterid.File{
|
|
||||||
ClusterID: "test-cluster-id",
|
|
||||||
UID: "test-uid",
|
|
||||||
AttestationURL: "test-maaUrl",
|
|
||||||
},
|
|
||||||
cfg: config.Default(),
|
|
||||||
expected: &State{
|
|
||||||
Version: Version1,
|
|
||||||
Infrastructure: Infrastructure{
|
|
||||||
UID: "test-uid",
|
|
||||||
Azure: &Azure{
|
|
||||||
AttestationURL: "test-maaUrl",
|
|
||||||
},
|
|
||||||
Name: "constell-test-uid",
|
|
||||||
},
|
|
||||||
ClusterValues: ClusterValues{
|
|
||||||
ClusterID: "test-cluster-id",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, tc := range testCases {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
state := NewFromIDFile(tc.idFile, tc.cfg)
|
|
||||||
|
|
||||||
assert.Equal(tc.expected, state)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -74,8 +74,6 @@ const (
|
|||||||
// Filenames.
|
// Filenames.
|
||||||
//
|
//
|
||||||
|
|
||||||
// ClusterIDsFilename filename that contains Constellation clusterID and IP.
|
|
||||||
ClusterIDsFilename = "constellation-id.json"
|
|
||||||
// StateFilename filename that contains the entire state of the Constellation cluster.
|
// StateFilename filename that contains the entire state of the Constellation cluster.
|
||||||
StateFilename = "constellation-state.yaml"
|
StateFilename = "constellation-state.yaml"
|
||||||
// ConfigFilename filename of Constellation config file.
|
// ConfigFilename filename of Constellation config file.
|
||||||
|
Loading…
Reference in New Issue
Block a user