diff --git a/cli/internal/cloudcmd/terraform.go b/cli/internal/cloudcmd/terraform.go index 2606c63d0..4e88536f4 100644 --- a/cli/internal/cloudcmd/terraform.go +++ b/cli/internal/cloudcmd/terraform.go @@ -18,18 +18,16 @@ import ( ) // TerraformUpgradeVars returns variables required to execute the Terraform scripts. -func TerraformUpgradeVars(conf *config.Config) (terraform.Variables, error) { - // Note that we pass "" as imageRef, as we ignore changes to the image in the terraform. - // The image is updates via our operator. +func TerraformUpgradeVars(conf *config.Config, imageRef string) (terraform.Variables, error) { switch conf.GetProvider() { case cloudprovider.AWS: - vars := awsTerraformVars(conf, "") + vars := awsTerraformVars(conf, imageRef) return vars, nil case cloudprovider.Azure: - vars := azureTerraformVars(conf, "") + vars := azureTerraformVars(conf, imageRef) return vars, nil case cloudprovider.GCP: - vars := gcpTerraformVars(conf, "") + vars := gcpTerraformVars(conf, imageRef) return vars, nil default: return nil, fmt.Errorf("unsupported provider: %s", conf.GetProvider()) diff --git a/cli/internal/cmd/BUILD.bazel b/cli/internal/cmd/BUILD.bazel index d9c88c9c8..03fa9d70d 100644 --- a/cli/internal/cmd/BUILD.bazel +++ b/cli/internal/cmd/BUILD.bazel @@ -68,6 +68,7 @@ go_library( "//internal/grpc/dialer", "//internal/grpc/grpclog", "//internal/grpc/retry", + "//internal/imagefetcher", "//internal/kms/uri", "//internal/kubernetes/kubectl", "//internal/license", diff --git a/cli/internal/cmd/upgradeapply.go b/cli/internal/cmd/upgradeapply.go index 748565b33..28a7dc854 100644 --- a/cli/internal/cmd/upgradeapply.go +++ b/cli/internal/cmd/upgradeapply.go @@ -27,6 +27,7 @@ import ( "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/file" + "github.com/edgelesssys/constellation/v2/internal/imagefetcher" "github.com/edgelesssys/constellation/v2/internal/kms/uri" "github.com/edgelesssys/constellation/v2/internal/versions" "github.com/rogpeppe/go-internal/diff" @@ -75,18 +76,20 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error { return err } + imagefetcher := imagefetcher.New() configFetcher := attestationconfigapi.NewFetcher() tfClient, err := terraform.New(cmd.Context(), constants.TerraformWorkingDir) if err != nil { return fmt.Errorf("setting up terraform client: %w", err) } - applyCmd := upgradeApplyCmd{upgrader: upgrader, log: log, configFetcher: configFetcher, clusterShower: tfClient, fileHandler: fileHandler} + applyCmd := upgradeApplyCmd{upgrader: upgrader, log: log, imageFetcher: imagefetcher, configFetcher: configFetcher, clusterShower: tfClient, fileHandler: fileHandler} return applyCmd.upgradeApply(cmd) } type upgradeApplyCmd struct { upgrader cloudUpgrader + imageFetcher imageFetcher configFetcher attestationconfigapi.Fetcher clusterShower clusterShower fileHandler file.Handler @@ -146,7 +149,7 @@ func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command) error { return fmt.Errorf("upgrading measurements: %w", err) } // not moving existing Terraform migrator because of planned apply refactor - tfOutput, err := u.migrateTerraform(cmd, conf, flags) + tfOutput, err := u.migrateTerraform(cmd, u.imageFetcher, conf, flags) if err != nil { return fmt.Errorf("performing Terraform migrations: %w", err) } @@ -207,10 +210,18 @@ func diffAttestationCfg(currentAttestationCfg config.AttestationCfg, newAttestat return diff, nil } +func getImage(ctx context.Context, conf *config.Config, fetcher imageFetcher) (string, error) { + // Fetch variables to execute Terraform script with + provider := conf.GetProvider() + attestationVariant := conf.GetAttestationConfig().GetVariant() + region := conf.GetRegion() + return fetcher.FetchReference(ctx, provider, attestationVariant, conf.Image, region) +} + // 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. func (u *upgradeApplyCmd) migrateTerraform( - cmd *cobra.Command, conf *config.Config, flags upgradeApplyFlags, + cmd *cobra.Command, fetcher imageFetcher, conf *config.Config, flags upgradeApplyFlags, ) (res terraform.ApplyOutput, err error) { u.log.Debugf("Planning Terraform migrations") @@ -218,7 +229,12 @@ func (u *upgradeApplyCmd) migrateTerraform( return res, fmt.Errorf("checking workspace: %w", err) } - vars, err := cloudcmd.TerraformUpgradeVars(conf) + imageRef, err := getImage(cmd.Context(), conf, fetcher) + if err != nil { + return res, fmt.Errorf("fetching image reference: %w", err) + } + + vars, err := cloudcmd.TerraformUpgradeVars(conf, imageRef) if err != nil { return res, fmt.Errorf("parsing upgrade variables: %w", err) } @@ -326,6 +342,13 @@ func validK8sVersion(cmd *cobra.Command, version string, yes bool) (validVersion return validVersion, nil } +type imageFetcher interface { + FetchReference(ctx context.Context, + provider cloudprovider.Provider, attestationVariant variant.Variant, + image, region string, + ) (string, error) +} + // confirmIfUpgradeAttestConfigHasDiff checks if the locally configured measurements are different from the cluster's measurements. // If so the function will ask the user to confirm (if --yes is not set). func (u *upgradeApplyCmd) confirmIfUpgradeAttestConfigHasDiff(cmd *cobra.Command, newConfig config.AttestationCfg, flags upgradeApplyFlags) error { diff --git a/cli/internal/cmd/upgradeapply_test.go b/cli/internal/cmd/upgradeapply_test.go index e38962695..45ede1210 100644 --- a/cli/internal/cmd/upgradeapply_test.go +++ b/cli/internal/cmd/upgradeapply_test.go @@ -35,6 +35,7 @@ func TestUpgradeApply(t *testing.T) { someErr := errors.New("some error") testCases := map[string]struct { upgrader *stubUpgrader + fetcher stubImageFetcher wantErr bool yesFlag bool dontWantJoinConfigBackup bool @@ -65,6 +66,7 @@ func TestUpgradeApply(t *testing.T) { helmErr: someErr, }, wantErr: true, + fetcher: stubImageFetcher{}, yesFlag: true, }, "check terraform error": { @@ -72,6 +74,7 @@ func TestUpgradeApply(t *testing.T) { currentConfig: config.DefaultForAzureSEVSNP(), checkTerraformErr: someErr, }, + fetcher: stubImageFetcher{}, wantErr: true, yesFlag: true, }, @@ -80,6 +83,7 @@ func TestUpgradeApply(t *testing.T) { currentConfig: config.DefaultForAzureSEVSNP(), terraformDiff: true, }, + fetcher: stubImageFetcher{}, wantErr: true, stdin: "no\n", }, @@ -89,6 +93,7 @@ func TestUpgradeApply(t *testing.T) { cleanTerraformErr: someErr, terraformDiff: true, }, + fetcher: stubImageFetcher{}, wantErr: true, stdin: "no\n", }, @@ -97,6 +102,7 @@ func TestUpgradeApply(t *testing.T) { currentConfig: config.DefaultForAzureSEVSNP(), planTerraformErr: someErr, }, + fetcher: stubImageFetcher{}, wantErr: true, yesFlag: true, }, @@ -106,6 +112,15 @@ func TestUpgradeApply(t *testing.T) { applyTerraformErr: someErr, terraformDiff: true, }, + fetcher: stubImageFetcher{}, + wantErr: true, + yesFlag: true, + }, + "fetch reference error": { + upgrader: &stubUpgrader{ + currentConfig: config.DefaultForAzureSEVSNP(), + }, + fetcher: stubImageFetcher{fetchReferenceErr: someErr}, wantErr: true, yesFlag: true, }, @@ -113,6 +128,7 @@ func TestUpgradeApply(t *testing.T) { upgrader: &stubUpgrader{ currentConfig: fakeAzureAttestationConfigFromCluster(context.Background(), t, cloudprovider.Azure), }, + fetcher: stubImageFetcher{}, yesFlag: true, dontWantJoinConfigBackup: true, }, @@ -141,7 +157,7 @@ func TestUpgradeApply(t *testing.T) { require.NoError(handler.WriteJSON(constants.ClusterIDsFilename, clusterid.File{})) require.NoError(handler.WriteJSON(constants.MasterSecretFilename, uri.MasterSecret{})) - upgrader := upgradeApplyCmd{upgrader: tc.upgrader, log: logger.NewTest(t), configFetcher: stubAttestationFetcher{}, clusterShower: &stubShowCluster{}, fileHandler: handler} + upgrader := upgradeApplyCmd{upgrader: tc.upgrader, log: logger.NewTest(t), imageFetcher: tc.fetcher, configFetcher: stubAttestationFetcher{}, clusterShower: &stubShowCluster{}, fileHandler: handler} err := upgrader.upgradeApply(cmd) if tc.wantErr { @@ -215,6 +231,17 @@ func (u stubUpgrader) ExtendClusterConfigCertSANs(_ context.Context, _ []string) return nil } +type stubImageFetcher struct { + fetchReferenceErr error +} + +func (f stubImageFetcher) FetchReference(_ context.Context, + _ cloudprovider.Provider, _ variant.Variant, + _, _ string, +) (string, error) { + return "", f.fetchReferenceErr +} + func fakeAzureAttestationConfigFromCluster(ctx context.Context, t *testing.T, provider cloudprovider.Provider) config.AttestationCfg { cpCfg := defaultConfigWithExpectedMeasurements(t, config.Default(), provider) // the cluster attestation config needs to have real version numbers that are translated from "latest" as defined in config.Default() diff --git a/cli/internal/cmd/upgradecheck.go b/cli/internal/cmd/upgradecheck.go index ee967bcce..d3b66a41d 100644 --- a/cli/internal/cmd/upgradecheck.go +++ b/cli/internal/cmd/upgradecheck.go @@ -31,6 +31,7 @@ import ( "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/file" + "github.com/edgelesssys/constellation/v2/internal/imagefetcher" "github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl" consemver "github.com/edgelesssys/constellation/v2/internal/semver" "github.com/edgelesssys/constellation/v2/internal/sigstore" @@ -99,8 +100,9 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error { log: log, versionsapi: versionfetcher, }, - checker: checker, - log: log, + checker: checker, + imagefetcher: imagefetcher.New(), + log: log, } return up.upgradeCheck(cmd, fileHandler, attestationconfigapi.NewFetcher(), flags) @@ -146,6 +148,7 @@ type upgradeCheckCmd struct { canUpgradeCheck bool collect collector checker upgradeChecker + imagefetcher imageFetcher log debugLog } @@ -216,7 +219,12 @@ func (u *upgradeCheckCmd) upgradeCheck(cmd *cobra.Command, fileHandler file.Hand return fmt.Errorf("checking workspace: %w", err) } - vars, err := cloudcmd.TerraformUpgradeVars(conf) + imageRef, err := getImage(cmd.Context(), conf, u.imagefetcher) + if err != nil { + return fmt.Errorf("fetching image reference: %w", err) + } + + vars, err := cloudcmd.TerraformUpgradeVars(conf, imageRef) if err != nil { return fmt.Errorf("parsing upgrade variables: %w", err) } diff --git a/cli/internal/cmd/upgradecheck_test.go b/cli/internal/cmd/upgradecheck_test.go index b5445641e..8463ab7e0 100644 --- a/cli/internal/cmd/upgradecheck_test.go +++ b/cli/internal/cmd/upgradecheck_test.go @@ -213,26 +213,29 @@ func TestUpgradeCheck(t *testing.T) { } testCases := map[string]struct { - collector stubVersionCollector - csp cloudprovider.Provider - checker stubUpgradeChecker - cliVersion string - wantError bool + collector stubVersionCollector + csp cloudprovider.Provider + checker stubUpgradeChecker + imagefetcher stubImageFetcher + cliVersion string + wantError bool }{ "upgrades gcp": { - collector: collector, - checker: stubUpgradeChecker{}, - csp: cloudprovider.GCP, - cliVersion: "v1.0.0", + collector: collector, + checker: stubUpgradeChecker{}, + imagefetcher: stubImageFetcher{}, + csp: cloudprovider.GCP, + cliVersion: "v1.0.0", }, "terraform err": { collector: collector, checker: stubUpgradeChecker{ err: assert.AnError, }, - csp: cloudprovider.GCP, - cliVersion: "v1.0.0", - wantError: true, + imagefetcher: stubImageFetcher{}, + csp: cloudprovider.GCP, + cliVersion: "v1.0.0", + wantError: true, }, } @@ -248,6 +251,7 @@ func TestUpgradeCheck(t *testing.T) { canUpgradeCheck: true, collect: &tc.collector, checker: tc.checker, + imagefetcher: tc.imagefetcher, log: logger.NewTest(t), }