diff --git a/cli/internal/cloudcmd/clients.go b/cli/internal/cloudcmd/clients.go index 068fb4eccf..e6c02ee758 100644 --- a/cli/internal/cloudcmd/clients.go +++ b/cli/internal/cloudcmd/clients.go @@ -10,6 +10,7 @@ import ( "context" "io" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" @@ -33,7 +34,7 @@ type tfCommonClient interface { type tfResourceClient interface { tfCommonClient ApplyCluster(ctx context.Context, provider cloudprovider.Provider, logLevel terraform.LogLevel) (terraform.ApplyOutput, error) - ShowCluster(ctx context.Context, provider cloudprovider.Provider) (terraform.ApplyOutput, error) + ShowInfrastructure(ctx context.Context, provider cloudprovider.Provider) (state.Infrastructure, error) } type tfIAMClient interface { diff --git a/cli/internal/cloudcmd/clients_test.go b/cli/internal/cloudcmd/clients_test.go index c878ae28cf..b7efc67aa2 100644 --- a/cli/internal/cloudcmd/clients_test.go +++ b/cli/internal/cloudcmd/clients_test.go @@ -11,6 +11,7 @@ import ( "io" "testing" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" @@ -31,7 +32,7 @@ type stubTerraformClient struct { iamOutput terraform.IAMOutput uid string attestationURL string - applyOutput terraform.ApplyOutput + infraState state.Infrastructure cleanUpWorkspaceCalled bool removeInstallerCalled bool destroyCalled bool @@ -77,9 +78,9 @@ func (c *stubTerraformClient) RemoveInstaller() { c.removeInstallerCalled = true } -func (c *stubTerraformClient) ShowCluster(_ context.Context, _ cloudprovider.Provider) (terraform.ApplyOutput, error) { +func (c *stubTerraformClient) ShowInfrastructure(_ context.Context, _ cloudprovider.Provider) (state.Infrastructure, error) { c.showCalled = true - return c.applyOutput, c.showErr + return c.infraState, c.showErr } func (c *stubTerraformClient) ShowIAM(_ context.Context, _ cloudprovider.Provider) (terraform.IAMOutput, error) { diff --git a/cli/internal/cloudcmd/create.go b/cli/internal/cloudcmd/create.go index 17b7aa00f0..26d1d0c714 100644 --- a/cli/internal/cloudcmd/create.go +++ b/cli/internal/cloudcmd/create.go @@ -112,31 +112,7 @@ func (c *Creator) Create(ctx context.Context, opts CreateOptions) (state.Infrast if err != nil { return state.Infrastructure{}, fmt.Errorf("creating cluster: %w", err) } - return convertToInfrastructure(tfOutput), nil -} - -func convertToInfrastructure(applyOutput terraform.ApplyOutput) state.Infrastructure { - var infra state.Infrastructure - infra.UID = applyOutput.UID - infra.PublicIP = applyOutput.IP - infra.InitSecret = applyOutput.Secret - infra.APIServerCertSANs = applyOutput.APIServerCertSANs - - if applyOutput.Azure != nil { - infra.Azure.ResourceGroup = applyOutput.Azure.ResourceGroup - infra.Azure.SubscriptionID = applyOutput.Azure.SubscriptionID - infra.Azure.NetworkSecurityGroupName = applyOutput.Azure.NetworkSecurityGroupName - infra.Azure.LoadBalancerName = applyOutput.Azure.LoadBalancerName - infra.Azure.UserAssignedIdentity = applyOutput.Azure.UserAssignedIdentity - infra.Azure.AttestationURL = applyOutput.Azure.AttestationURL - } - - if applyOutput.GCP != nil { - infra.GCP.ProjectID = applyOutput.GCP.ProjectID - infra.GCP.IPCidrNode = applyOutput.GCP.IPCidrNode - infra.GCP.IPCidrPod = applyOutput.GCP.IPCidrPod - } - return infra + return terraform.ConvertToInfrastructure(tfOutput), nil } func (c *Creator) createAWS(ctx context.Context, cl tfResourceClient, opts CreateOptions) (tfOutput terraform.ApplyOutput, retErr error) { diff --git a/cli/internal/cmd/init.go b/cli/internal/cmd/init.go index 1781b13a5b..0164d7c1f5 100644 --- a/cli/internal/cmd/init.go +++ b/cli/internal/cmd/init.go @@ -40,6 +40,7 @@ import ( "github.com/edgelesssys/constellation/v2/cli/internal/cmd/pathprefix" "github.com/edgelesssys/constellation/v2/cli/internal/helm" "github.com/edgelesssys/constellation/v2/cli/internal/kubecmd" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/config" @@ -76,12 +77,12 @@ type initCmd struct { merger configMerger spinner spinnerInterf fileHandler file.Handler - clusterShower clusterShower + clusterShower infrastructureShower pf pathprefix.PathPrefixer } func newInitCmd( - clusterShower clusterShower, fileHandler file.Handler, + clusterShower infrastructureShower, fileHandler file.Handler, spinner spinnerInterf, merger configMerger, log debugLog, ) *initCmd { return &initCmd{ @@ -259,9 +260,9 @@ func (i *initCmd) initialize( return fmt.Errorf("applying attestation config: %w", err) } - output, err := i.clusterShower.ShowCluster(cmd.Context(), conf.GetProvider()) + infraState, err := i.clusterShower.ShowInfrastructure(cmd.Context(), conf.GetProvider()) if err != nil { - return fmt.Errorf("getting Terraform output: %w", err) + return fmt.Errorf("getting infrastructure state: %w", err) } i.spinner.Start("Installing Kubernetes components ", false) @@ -275,7 +276,7 @@ func (i *initCmd) initialize( if err != nil { return fmt.Errorf("creating Helm client: %w", err) } - executor, includesUpgrades, err := helmApplier.PrepareApply(conf, k8sVersion, idFile, options, output, + executor, includesUpgrades, err := helmApplier.PrepareApply(conf, k8sVersion, idFile, options, infraState, serviceAccURI, masterSecret) if err != nil { return fmt.Errorf("getting Helm chart executor: %w", err) @@ -629,9 +630,11 @@ type attestationConfigApplier interface { } type helmApplier interface { - PrepareApply(conf *config.Config, validK8sversion versions.ValidK8sVersion, idFile clusterid.File, flags helm.Options, tfOutput terraform.ApplyOutput, serviceAccURI string, masterSecret uri.MasterSecret) (helm.Applier, bool, error) + PrepareApply(conf *config.Config, validK8sversion versions.ValidK8sVersion, idFile clusterid.File, + flags helm.Options, infra state.Infrastructure, serviceAccURI string, masterSecret uri.MasterSecret) ( + helm.Applier, bool, error) } -type clusterShower interface { - ShowCluster(ctx context.Context, provider cloudprovider.Provider) (terraform.ApplyOutput, error) +type infrastructureShower interface { + ShowInfrastructure(ctx context.Context, provider cloudprovider.Provider) (state.Infrastructure, error) } diff --git a/cli/internal/cmd/init_test.go b/cli/internal/cmd/init_test.go index af0ecbc0cf..13ac229dc6 100644 --- a/cli/internal/cmd/init_test.go +++ b/cli/internal/cmd/init_test.go @@ -23,7 +23,7 @@ import ( "github.com/edgelesssys/constellation/v2/cli/internal/clusterid" "github.com/edgelesssys/constellation/v2/cli/internal/cmd/pathprefix" "github.com/edgelesssys/constellation/v2/cli/internal/helm" - "github.com/edgelesssys/constellation/v2/cli/internal/terraform" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/internal/atls" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" @@ -186,7 +186,7 @@ func TestInitialize(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 4*time.Second) defer cancel() cmd.SetContext(ctx) - i := newInitCmd(&stubShowCluster{}, fileHandler, &nopSpinner{}, nil, logger.NewTest(t)) + i := newInitCmd(&stubShowInfrastructure{}, fileHandler, &nopSpinner{}, nil, logger.NewTest(t)) err := i.initialize(cmd, newDialer, &stubLicenseClient{}, stubAttestationFetcher{}, func(io.Writer, string, debugLog) (attestationConfigApplier, error) { return &stubAttestationApplier{}, nil @@ -222,7 +222,7 @@ type stubApplier struct { err error } -func (s stubApplier) PrepareApply(_ *config.Config, _ versions.ValidK8sVersion, _ clusterid.File, _ helm.Options, _ terraform.ApplyOutput, _ string, _ uri.MasterSecret) (helm.Applier, bool, error) { +func (s stubApplier) PrepareApply(_ *config.Config, _ versions.ValidK8sVersion, _ clusterid.File, _ helm.Options, _ state.Infrastructure, _ string, _ uri.MasterSecret) (helm.Applier, bool, error) { return stubRunner{}, false, s.err } @@ -672,15 +672,15 @@ func (c stubInitClient) Recv() (*initproto.InitResponse, error) { return res, err } -type stubShowCluster struct{} +type stubShowInfrastructure struct{} -func (s *stubShowCluster) ShowCluster(_ context.Context, csp cloudprovider.Provider) (terraform.ApplyOutput, error) { - res := terraform.ApplyOutput{} +func (s *stubShowInfrastructure) ShowInfrastructure(_ context.Context, csp cloudprovider.Provider) (state.Infrastructure, error) { + res := state.Infrastructure{} switch csp { case cloudprovider.Azure: - res.Azure = &terraform.AzureApplyOutput{} + res.Azure = &state.Azure{} case cloudprovider.GCP: - res.GCP = &terraform.GCPApplyOutput{} + res.GCP = &state.GCP{} } return res, nil } diff --git a/cli/internal/cmd/upgradeapply.go b/cli/internal/cmd/upgradeapply.go index ff52bf140c..51cd5d7e08 100644 --- a/cli/internal/cmd/upgradeapply.go +++ b/cli/internal/cmd/upgradeapply.go @@ -19,6 +19,7 @@ import ( "github.com/edgelesssys/constellation/v2/cli/internal/cmd/pathprefix" "github.com/edgelesssys/constellation/v2/cli/internal/helm" "github.com/edgelesssys/constellation/v2/cli/internal/kubecmd" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" @@ -122,7 +123,7 @@ type upgradeApplyCmd struct { kubeUpgrader kubernetesUpgrader clusterUpgrader clusterUpgrader configFetcher attestationconfigapi.Fetcher - clusterShower clusterShower + clusterShower infrastructureShower fileHandler file.Handler log debugLog } @@ -172,10 +173,17 @@ func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, upgradeDir string, fl return fmt.Errorf("upgrading measurements: %w", err) } - tfOutput, err := u.migrateTerraform(cmd, conf, upgradeDir, flags) + infraState, err := u.migrateTerraform(cmd, conf, upgradeDir, flags) if err != nil { return fmt.Errorf("performing Terraform migrations: %w", err) } + state := state.State{ + Version: "v1", + Infrastructure: infraState, + } + if err := u.fileHandler.WriteYAML(constants.StateFilename, state, file.OptOverwrite); err != nil { + return fmt.Errorf("writing state file: %w", err) + } // reload idFile after terraform migration // it might have been updated by the migration if err := u.fileHandler.ReadJSON(constants.ClusterIDsFilename, &idFile); err != nil { @@ -197,7 +205,7 @@ func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, upgradeDir string, fl } var upgradeErr *compatibility.InvalidUpgradeError - err = u.handleServiceUpgrade(cmd, conf, idFile, tfOutput, validK8sVersion, upgradeDir, flags) + err = u.handleServiceUpgrade(cmd, conf, idFile, infraState, validK8sVersion, upgradeDir, flags) switch { case errors.As(err, &upgradeErr): cmd.PrintErrln(err) @@ -237,7 +245,7 @@ func diffAttestationCfg(currentAttestationCfg config.AttestationCfg, newAttestat // 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, upgradeDir string, flags upgradeApplyFlags, -) (res terraform.ApplyOutput, err error) { +) (res state.Infrastructure, err error) { u.log.Debugf("Planning Terraform migrations") vars, err := cloudcmd.TerraformUpgradeVars(conf) @@ -280,13 +288,14 @@ func (u *upgradeApplyCmd) migrateTerraform(cmd *cobra.Command, conf *config.Conf } u.log.Debugf("Applying Terraform migrations") tfOutput, err := u.clusterUpgrader.ApplyClusterUpgrade(cmd.Context(), conf.GetProvider()) + res = terraform.ConvertToInfrastructure(tfOutput) if err != nil { - return tfOutput, fmt.Errorf("applying terraform migrations: %w", err) + return res, fmt.Errorf("applying terraform migrations: %w", err) } // Apply possible updates to cluster ID file if err := updateClusterIDFile(tfOutput, u.fileHandler); err != nil { - return tfOutput, fmt.Errorf("merging cluster ID files: %w", err) + return res, fmt.Errorf("merging cluster ID files: %w", err) } cmd.Printf("Terraform migrations applied successfully and output written to: %s\n"+ @@ -298,7 +307,7 @@ func (u *upgradeApplyCmd) migrateTerraform(cmd *cobra.Command, conf *config.Conf u.log.Debugf("No Terraform diff detected") } u.log.Debugf("No Terraform diff detected") - tfOutput, err := u.clusterShower.ShowCluster(cmd.Context(), conf.GetProvider()) + tfOutput, err := u.clusterShower.ShowInfrastructure(cmd.Context(), conf.GetProvider()) if err != nil { return tfOutput, fmt.Errorf("getting Terraform output: %w", err) } @@ -369,7 +378,7 @@ func (u *upgradeApplyCmd) confirmAndUpgradeAttestationConfig( } func (u *upgradeApplyCmd) handleServiceUpgrade( - cmd *cobra.Command, conf *config.Config, idFile clusterid.File, tfOutput terraform.ApplyOutput, + cmd *cobra.Command, conf *config.Config, idFile clusterid.File, infra state.Infrastructure, validK8sVersion versions.ValidK8sVersion, upgradeDir string, flags upgradeApplyFlags, ) error { var secret uri.MasterSecret @@ -389,7 +398,7 @@ func (u *upgradeApplyCmd) handleServiceUpgrade( prepareApply := func(allowDestructive bool) (helm.Applier, bool, error) { options.AllowDestructive = allowDestructive executor, includesUpgrades, err := u.helmApplier.PrepareApply(conf, validK8sVersion, idFile, options, - tfOutput, serviceAccURI, secret) + infra, serviceAccURI, secret) var upgradeErr *compatibility.InvalidUpgradeError switch { case errors.As(err, &upgradeErr): diff --git a/cli/internal/cmd/upgradeapply_test.go b/cli/internal/cmd/upgradeapply_test.go index 6b2e68629f..eda368356e 100644 --- a/cli/internal/cmd/upgradeapply_test.go +++ b/cli/internal/cmd/upgradeapply_test.go @@ -14,6 +14,7 @@ import ( "github.com/edgelesssys/constellation/v2/cli/internal/clusterid" "github.com/edgelesssys/constellation/v2/cli/internal/kubecmd" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" @@ -124,7 +125,7 @@ func TestUpgradeApply(t *testing.T) { clusterUpgrader: tc.terraformUpgrader, log: logger.NewTest(t), configFetcher: stubAttestationFetcher{}, - clusterShower: &stubShowCluster{}, + clusterShower: &stubShowInfrastructure{}, fileHandler: handler, } @@ -134,6 +135,15 @@ func TestUpgradeApply(t *testing.T) { return } assert.NoError(err) + + var gotState state.State + expectedState := state.Infrastructure{ + APIServerCertSANs: []string{}, + Azure: &state.Azure{}, + } + require.NoError(handler.ReadYAML(constants.StateFilename, &gotState)) + assert.Equal("v1", gotState.Version) + assert.Equal(expectedState, gotState.Infrastructure) }) } } diff --git a/cli/internal/helm/BUILD.bazel b/cli/internal/helm/BUILD.bazel index 663ca1951e..3f7a852757 100644 --- a/cli/internal/helm/BUILD.bazel +++ b/cli/internal/helm/BUILD.bazel @@ -421,7 +421,7 @@ go_library( deps = [ "//cli/internal/clusterid", "//cli/internal/helm/imageversion", - "//cli/internal/terraform", + "//cli/internal/state", "//internal/cloud/azureshared", "//internal/cloud/cloudprovider", "//internal/cloud/gcpshared", @@ -459,7 +459,7 @@ go_test( embed = [":helm"], deps = [ "//cli/internal/clusterid", - "//cli/internal/terraform", + "//cli/internal/state", "//internal/attestation/measurements", "//internal/cloud/azureshared", "//internal/cloud/cloudprovider", diff --git a/cli/internal/helm/helm.go b/cli/internal/helm/helm.go index 261b431e23..536e91ccc4 100644 --- a/cli/internal/helm/helm.go +++ b/cli/internal/helm/helm.go @@ -33,7 +33,7 @@ import ( "fmt" "github.com/edgelesssys/constellation/v2/cli/internal/clusterid" - "github.com/edgelesssys/constellation/v2/cli/internal/terraform" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/kms/uri" @@ -87,8 +87,10 @@ type Options struct { // PrepareApply loads the charts and returns the executor to apply them. // TODO(elchead): remove validK8sVersion by putting ValidK8sVersion into config.Config, see AB#3374. -func (h Client) PrepareApply(conf *config.Config, validK8sversion versions.ValidK8sVersion, idFile clusterid.File, flags Options, tfOutput terraform.ApplyOutput, serviceAccURI string, masterSecret uri.MasterSecret) (Applier, bool, error) { - releases, err := h.loadReleases(conf, masterSecret, validK8sversion, idFile, flags, tfOutput, serviceAccURI) +func (h Client) PrepareApply(conf *config.Config, validK8sversion versions.ValidK8sVersion, idFile clusterid.File, + flags Options, infra state.Infrastructure, serviceAccURI string, masterSecret uri.MasterSecret, +) (Applier, bool, error) { + releases, err := h.loadReleases(conf, masterSecret, validK8sversion, idFile, flags, infra, serviceAccURI) if err != nil { return nil, false, fmt.Errorf("loading Helm releases: %w", err) } @@ -97,11 +99,13 @@ func (h Client) PrepareApply(conf *config.Config, validK8sversion versions.Valid return &ChartApplyExecutor{actions: actions, log: h.log}, includesUpgrades, err } -func (h Client) loadReleases(conf *config.Config, secret uri.MasterSecret, validK8sVersion versions.ValidK8sVersion, idFile clusterid.File, flags Options, tfOutput terraform.ApplyOutput, serviceAccURI string) ([]Release, error) { +func (h Client) loadReleases(conf *config.Config, secret uri.MasterSecret, validK8sVersion versions.ValidK8sVersion, + idFile clusterid.File, flags Options, infra state.Infrastructure, serviceAccURI string, +) ([]Release, error) { helmLoader := newLoader(conf, idFile, validK8sVersion, h.cliVersion) h.log.Debugf("Created new Helm loader") return helmLoader.loadReleases(flags.Conformance, flags.HelmWaitMode, secret, - serviceAccURI, tfOutput) + serviceAccURI, infra) } // Applier runs the Helm actions. diff --git a/cli/internal/helm/helm_test.go b/cli/internal/helm/helm_test.go index f813ffbacd..1a405a2b11 100644 --- a/cli/internal/helm/helm_test.go +++ b/cli/internal/helm/helm_test.go @@ -11,7 +11,7 @@ import ( "testing" "github.com/edgelesssys/constellation/v2/cli/internal/clusterid" - "github.com/edgelesssys/constellation/v2/cli/internal/terraform" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/compatibility" "github.com/edgelesssys/constellation/v2/internal/config" @@ -209,7 +209,7 @@ func TestHelmApply(t *testing.T) { options.AllowDestructive = tc.allowDestructive ex, includesUpgrade, err := sut.PrepareApply(cfg, versions.ValidK8sVersion("v1.27.4"), clusterid.File{UID: "testuid", MeasurementSalt: []byte("measurementSalt")}, options, - fakeTerraformOutput(csp), fakeServiceAccURI(csp), + fakeInfraOutput(csp), fakeServiceAccURI(csp), uri.MasterSecret{Key: []byte("secret"), Salt: []byte("masterSalt")}) var upgradeErr *compatibility.InvalidUpgradeError if tc.expectError { @@ -225,12 +225,12 @@ func TestHelmApply(t *testing.T) { } } -func fakeTerraformOutput(csp cloudprovider.Provider) terraform.ApplyOutput { +func fakeInfraOutput(csp cloudprovider.Provider) state.Infrastructure { switch csp { case cloudprovider.AWS: - return terraform.ApplyOutput{} + return state.Infrastructure{} case cloudprovider.GCP: - return terraform.ApplyOutput{GCP: &terraform.GCPApplyOutput{}} + return state.Infrastructure{GCP: &state.GCP{}} default: panic("invalid csp") } diff --git a/cli/internal/helm/loader.go b/cli/internal/helm/loader.go index 02047ad196..b890dc1619 100644 --- a/cli/internal/helm/loader.go +++ b/cli/internal/helm/loader.go @@ -21,7 +21,7 @@ import ( "github.com/edgelesssys/constellation/v2/cli/internal/clusterid" "github.com/edgelesssys/constellation/v2/cli/internal/helm/imageversion" - "github.com/edgelesssys/constellation/v2/cli/internal/terraform" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/constants" @@ -119,13 +119,13 @@ type releaseApplyOrder []Release // loadReleases loads the embedded helm charts and returns them as a HelmReleases object. func (i *chartLoader) loadReleases(conformanceMode bool, helmWaitMode WaitMode, masterSecret uri.MasterSecret, - serviceAccURI string, output terraform.ApplyOutput, + serviceAccURI string, infra state.Infrastructure, ) (releaseApplyOrder, error) { ciliumRelease, err := i.loadRelease(ciliumInfo, helmWaitMode) if err != nil { return nil, fmt.Errorf("loading cilium: %w", err) } - ciliumVals := extraCiliumValues(i.config.GetProvider(), conformanceMode, output) + ciliumVals := extraCiliumValues(i.config.GetProvider(), conformanceMode, infra) ciliumRelease.Values = mergeMaps(ciliumRelease.Values, ciliumVals) certManagerRelease, err := i.loadRelease(certManagerInfo, helmWaitMode) @@ -144,7 +144,7 @@ func (i *chartLoader) loadReleases(conformanceMode bool, helmWaitMode WaitMode, return nil, fmt.Errorf("loading constellation-services: %w", err) } - svcVals, err := extraConstellationServicesValues(i.config, masterSecret, i.idFile.UID, serviceAccURI, output) + svcVals, err := extraConstellationServicesValues(i.config, masterSecret, i.idFile.UID, serviceAccURI, infra) if err != nil { return nil, fmt.Errorf("extending constellation-services values: %w", err) } diff --git a/cli/internal/helm/loader_test.go b/cli/internal/helm/loader_test.go index 1eb385662d..708c30e761 100644 --- a/cli/internal/helm/loader_test.go +++ b/cli/internal/helm/loader_test.go @@ -23,7 +23,7 @@ import ( "helm.sh/helm/v3/pkg/engine" "github.com/edgelesssys/constellation/v2/cli/internal/clusterid" - "github.com/edgelesssys/constellation/v2/cli/internal/terraform" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/azureshared" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" @@ -73,7 +73,7 @@ func TestLoadReleases(t *testing.T) { helmReleases, err := chartLoader.loadReleases( true, WaitModeAtomic, uri.MasterSecret{Key: []byte("secret"), Salt: []byte("masterSalt")}, - fakeServiceAccURI(cloudprovider.GCP), terraform.ApplyOutput{GCP: &terraform.GCPApplyOutput{}}, + fakeServiceAccURI(cloudprovider.GCP), state.Infrastructure{GCP: &state.GCP{}}, ) require.NoError(err) for _, release := range helmReleases { @@ -177,9 +177,9 @@ func TestConstellationServices(t *testing.T) { Key: []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), Salt: []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), }, - "uid", serviceAccURI, terraform.ApplyOutput{ - Azure: &terraform.AzureApplyOutput{}, - GCP: &terraform.GCPApplyOutput{}, + "uid", serviceAccURI, state.Infrastructure{ + Azure: &state.Azure{}, + GCP: &state.GCP{}, }) require.NoError(err) values = mergeMaps(values, extraVals) diff --git a/cli/internal/helm/overrides.go b/cli/internal/helm/overrides.go index 16a181e2c2..1d952fbbe7 100644 --- a/cli/internal/helm/overrides.go +++ b/cli/internal/helm/overrides.go @@ -13,7 +13,7 @@ import ( "encoding/json" "fmt" - "github.com/edgelesssys/constellation/v2/cli/internal/terraform" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/internal/cloud/azureshared" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/cloud/gcpshared" @@ -31,7 +31,7 @@ import ( // reuse user input from the init step. However, we can't rely on reuse-values, because // during upgrades we all values need to be set locally as they might have changed. // Also, the charts are not rendered correctly without all of these values. -func extraCiliumValues(provider cloudprovider.Provider, conformanceMode bool, output terraform.ApplyOutput) map[string]any { +func extraCiliumValues(provider cloudprovider.Provider, conformanceMode bool, output state.Infrastructure) map[string]any { extraVals := map[string]any{} if conformanceMode { extraVals["kubeProxyReplacementHealthzBindAddr"] = "" @@ -42,7 +42,7 @@ func extraCiliumValues(provider cloudprovider.Provider, conformanceMode bool, ou } } - extraVals["k8sServiceHost"] = output.IP + extraVals["k8sServiceHost"] = output.PublicIP extraVals["k8sServicePort"] = constants.KubernetesPort if provider == cloudprovider.GCP { extraVals["ipv4NativeRoutingCIDR"] = output.GCP.IPCidrPod @@ -54,7 +54,7 @@ func extraCiliumValues(provider cloudprovider.Provider, conformanceMode bool, ou // extraConstellationServicesValues extends the given values map by some values depending on user input. // Values set inside this function are only applied during init, not during upgrade. func extraConstellationServicesValues( - cfg *config.Config, masterSecret uri.MasterSecret, uid, serviceAccURI string, output terraform.ApplyOutput, + cfg *config.Config, masterSecret uri.MasterSecret, uid, serviceAccURI string, output state.Infrastructure, ) (map[string]any, error) { extraVals := map[string]any{} extraVals["join-service"] = map[string]any{ @@ -62,10 +62,10 @@ func extraConstellationServicesValues( } extraVals["verification-service"] = map[string]any{ "attestationVariant": cfg.GetAttestationConfig().GetVariant().String(), - "loadBalancerIP": output.IP, + "loadBalancerIP": output.PublicIP, } extraVals["konnectivity"] = map[string]any{ - "loadBalancerIP": output.IP, + "loadBalancerIP": output.PublicIP, } extraVals["key-service"] = map[string]any{ @@ -147,7 +147,7 @@ type cloudConfig struct { } // getCCMConfig returns the configuration needed for the Kubernetes Cloud Controller Manager on Azure. -func getCCMConfig(tfOutput terraform.AzureApplyOutput, serviceAccURI string) ([]byte, error) { +func getCCMConfig(azureState state.Azure, serviceAccURI string) ([]byte, error) { creds, err := azureshared.ApplicationCredentialsFromURI(serviceAccURI) if err != nil { return nil, fmt.Errorf("getting service account key: %w", err) @@ -156,16 +156,16 @@ func getCCMConfig(tfOutput terraform.AzureApplyOutput, serviceAccURI string) ([] config := cloudConfig{ Cloud: "AzurePublicCloud", TenantID: creds.TenantID, - SubscriptionID: tfOutput.SubscriptionID, - ResourceGroup: tfOutput.ResourceGroup, + SubscriptionID: azureState.SubscriptionID, + ResourceGroup: azureState.ResourceGroup, LoadBalancerSku: "standard", - SecurityGroupName: tfOutput.NetworkSecurityGroupName, - LoadBalancerName: tfOutput.LoadBalancerName, + SecurityGroupName: azureState.NetworkSecurityGroupName, + LoadBalancerName: azureState.LoadBalancerName, UseInstanceMetadata: true, VMType: "vmss", Location: creds.Location, UseManagedIdentityExtension: useManagedIdentityExtension, - UserAssignedIdentityID: tfOutput.UserAssignedIdentity, + UserAssignedIdentityID: azureState.UserAssignedIdentity, } return json.Marshal(config) diff --git a/cli/internal/state/state.go b/cli/internal/state/state.go index 8ba9230bdb..3daf1cf640 100644 --- a/cli/internal/state/state.go +++ b/cli/internal/state/state.go @@ -15,23 +15,23 @@ type State struct { // Infrastructure describe the state related to the cloud resources of the cluster. type Infrastructure struct { - UID string `yaml:"uid"` - PublicIP string `yaml:"publicIP"` - InitSecret string `yaml:"initSecret"` - APIServerCertSANs []string `yaml:"apiServerCertSANs"` - Azure AzureState `yaml:"azure"` - GCP GCPState `yaml:"gcp"` + UID string `yaml:"uid"` + PublicIP string `yaml:"publicIP"` + InitSecret string `yaml:"initSecret"` + APIServerCertSANs []string `yaml:"apiServerCertSANs"` + Azure *Azure `yaml:"azure"` + GCP *GCP `yaml:"gcp"` } -// GCPState describes the infra state related to GCP. -type GCPState struct { +// GCP describes the infra state related to GCP. +type GCP struct { ProjectID string `yaml:"projectID"` IPCidrNode string `yaml:"ipCidrNode"` IPCidrPod string `yaml:"ipCidrPod"` } -// AzureState describes the infra state related to Azure. -type AzureState struct { +// Azure describes the infra state related to Azure. +type Azure struct { ResourceGroup string `yaml:"resourceGroup"` SubscriptionID string `yaml:"subscriptionID"` NetworkSecurityGroupName string `yaml:"networkSecurityGroupName"` diff --git a/cli/internal/terraform/BUILD.bazel b/cli/internal/terraform/BUILD.bazel index 98f3c75833..789e4f1549 100644 --- a/cli/internal/terraform/BUILD.bazel +++ b/cli/internal/terraform/BUILD.bazel @@ -74,6 +74,7 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/cli/internal/terraform", visibility = ["//cli:__subpackages__"], deps = [ + "//cli/internal/state", "//internal/cloud/cloudprovider", "//internal/constants", "//internal/file", diff --git a/cli/internal/terraform/terraform.go b/cli/internal/terraform/terraform.go index 29d08925c3..59bc977fcb 100644 --- a/cli/internal/terraform/terraform.go +++ b/cli/internal/terraform/terraform.go @@ -24,6 +24,7 @@ import ( "io" "path/filepath" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/file" @@ -170,6 +171,44 @@ func (c *Client) ShowIAM(ctx context.Context, provider cloudprovider.Provider) ( } } +// ShowInfrastructure reads the state of Constellation cluster resources from Terraform. +func (c *Client) ShowInfrastructure(ctx context.Context, provider cloudprovider.Provider) (state.Infrastructure, error) { + tfOutput, err := c.ShowCluster(ctx, provider) + if err != nil { + return state.Infrastructure{}, err + } + return ConvertToInfrastructure(tfOutput), nil +} + +// ConvertToInfrastructure converts the Terraform output of a cluster creation or apply operation to a state.Infrastructure. +func ConvertToInfrastructure(applyOutput ApplyOutput) state.Infrastructure { + var infra state.Infrastructure + infra.UID = applyOutput.UID + infra.PublicIP = applyOutput.IP + infra.InitSecret = applyOutput.Secret + infra.APIServerCertSANs = applyOutput.APIServerCertSANs + + if applyOutput.Azure != nil { + infra.Azure = &state.Azure{ + ResourceGroup: applyOutput.Azure.ResourceGroup, + SubscriptionID: applyOutput.Azure.SubscriptionID, + UserAssignedIdentity: applyOutput.Azure.UserAssignedIdentity, + NetworkSecurityGroupName: applyOutput.Azure.NetworkSecurityGroupName, + LoadBalancerName: applyOutput.Azure.LoadBalancerName, + AttestationURL: applyOutput.Azure.AttestationURL, + } + } + + if applyOutput.GCP != nil { + infra.GCP = &state.GCP{ + ProjectID: applyOutput.GCP.ProjectID, + IPCidrNode: applyOutput.GCP.IPCidrNode, + IPCidrPod: applyOutput.GCP.IPCidrPod, + } + } + return infra +} + // ShowCluster reads the state of Constellation cluster resources from Terraform. func (c *Client) ShowCluster(ctx context.Context, provider cloudprovider.Provider) (ApplyOutput, error) { tfState, err := c.tf.Show(ctx)