diff --git a/cli/internal/cmd/init.go b/cli/internal/cmd/init.go index 1c701c526..7cb4f2dc3 100644 --- a/cli/internal/cmd/init.go +++ b/cli/internal/cmd/init.go @@ -77,15 +77,29 @@ type initCmd struct { merger configMerger spinner spinnerInterf masterSecret uri.MasterSecret - fh *file.Handler + fileHandler file.Handler helmInstaller helm.Initializer - tfClient showClusterer + clusterShower clusterShower } -type showClusterer interface { +type clusterShower interface { ShowCluster(ctx context.Context, provider cloudprovider.Provider) (terraform.ApplyOutput, error) } +func newInitCmd( + clusterShower clusterShower, helmInstaller helm.Initializer, fileHandler file.Handler, + spinner spinnerInterf, merger configMerger, log debugLog, +) *initCmd { + return &initCmd{ + log: log, + merger: merger, + spinner: spinner, + fileHandler: fileHandler, + helmInstaller: helmInstaller, + clusterShower: clusterShower, + } +} + // runInitialize runs the initialize command. func runInitialize(cmd *cobra.Command, _ []string) error { log, err := newCLILogger(cmd) @@ -115,14 +129,14 @@ func runInitialize(cmd *cobra.Command, _ []string) error { if err != nil { return fmt.Errorf("creating Terraform client: %w", err) } - i := &initCmd{log: log, spinner: spinner, merger: &kubeconfigMerger{log: log}, fh: &fileHandler, helmInstaller: helmInstaller, tfClient: tfClient} + i := newInitCmd(tfClient, helmInstaller, fileHandler, spinner, &kubeconfigMerger{log: log}, log) fetcher := attestationconfigapi.NewFetcher() - return i.initialize(cmd, newDialer, fileHandler, license.NewClient(), fetcher) + return i.initialize(cmd, newDialer, license.NewClient(), fetcher) } // initialize initializes a Constellation. func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator atls.Validator) *dialer.Dialer, - fileHandler file.Handler, quotaChecker license.QuotaChecker, configFetcher attestationconfigapi.Fetcher, + quotaChecker license.QuotaChecker, configFetcher attestationconfigapi.Fetcher, ) error { flags, err := i.evalFlagArgs(cmd) if err != nil { @@ -130,7 +144,7 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator atls.V } i.log.Debugf("Using flags: %+v", flags) i.log.Debugf("Loading configuration file from %q", flags.configPath) - conf, err := config.New(fileHandler, flags.configPath, configFetcher, flags.force) + conf, err := config.New(i.fileHandler, flags.configPath, configFetcher, flags.force) var configValidationErr *config.ValidationError if errors.As(err, &configValidationErr) { cmd.PrintErrln(configValidationErr.LongMessage()) @@ -149,7 +163,7 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator atls.V i.log.Debugf("Checking cluster ID file") var idFile clusterid.File - if err := fileHandler.ReadJSON(constants.ClusterIDsFileName, &idFile); err != nil { + if err := i.fileHandler.ReadJSON(constants.ClusterIDsFileName, &idFile); err != nil { return fmt.Errorf("reading cluster ID file: %w", err) } @@ -166,7 +180,7 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator atls.V provider := conf.GetProvider() i.log.Debugf("Got provider %s", provider.String()) - checker := license.NewChecker(quotaChecker, fileHandler) + checker := license.NewChecker(quotaChecker, i.fileHandler) if err := checker.CheckLicense(cmd.Context(), provider, conf.Provider, cmd.Printf); err != nil { cmd.PrintErrf("License check failed: %v", err) } @@ -179,12 +193,12 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator atls.V return fmt.Errorf("creating new validator: %w", err) } i.log.Debugf("Created a new validator") - serviceAccURI, err := i.getMarshaledServiceAccountURI(provider, conf, fileHandler) + serviceAccURI, err := i.getMarshaledServiceAccountURI(provider, conf) if err != nil { return err } i.log.Debugf("Successfully marshaled service account URI") - masterSecret, err := i.readOrGenerateMasterSecret(cmd.OutOrStdout(), fileHandler, flags.masterSecretPath) + masterSecret, err := i.readOrGenerateMasterSecret(cmd.OutOrStdout(), flags.masterSecretPath) i.masterSecret = masterSecret if err != nil { return fmt.Errorf("parsing or generating master secret from file %s: %w", flags.masterSecretPath, err) @@ -225,14 +239,14 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator atls.V idFile.CloudProvider = provider bufferedOutput := &bytes.Buffer{} - err = i.writeOutput(idFile, resp, flags.mergeConfigs, bufferedOutput, fileHandler) + err = i.writeOutput(idFile, resp, flags.mergeConfigs, bufferedOutput) if err != nil { return err } helmLoader := helm.NewLoader(provider, k8sVersion, clusterName) i.log.Debugf("Created new Helm loader") - output, err := i.tfClient.ShowCluster(cmd.Context(), conf.GetProvider()) + output, err := i.clusterShower.ShowCluster(cmd.Context(), conf.GetProvider()) if err != nil { return fmt.Errorf("getting Terraform output: %w", err) } @@ -374,7 +388,7 @@ func (d *initDoer) handleGRPCStateChanges(ctx context.Context, wg *sync.WaitGrou } func (i *initCmd) writeOutput( - idFile clusterid.File, initResp *initproto.InitSuccessResponse, mergeConfig bool, wr io.Writer, fileHandler file.Handler, + idFile clusterid.File, initResp *initproto.InitSuccessResponse, mergeConfig bool, wr io.Writer, ) error { fmt.Fprint(wr, "Your Constellation cluster was successfully initialized.\n\n") @@ -389,13 +403,13 @@ func (i *initCmd) writeOutput( tw.Flush() fmt.Fprintln(wr) - if err := fileHandler.Write(constants.AdminConfFilename, initResp.GetKubeconfig(), file.OptNone); err != nil { + if err := i.fileHandler.Write(constants.AdminConfFilename, initResp.GetKubeconfig(), file.OptNone); err != nil { return fmt.Errorf("writing kubeconfig: %w", err) } i.log.Debugf("Kubeconfig written to %s", constants.AdminConfFilename) if mergeConfig { - if err := i.merger.mergeConfigs(constants.AdminConfFilename, fileHandler); err != nil { + if err := i.merger.mergeConfigs(constants.AdminConfFilename, i.fileHandler); err != nil { writeRow(tw, "Failed to automatically merge kubeconfig", err.Error()) mergeConfig = false // Set to false so we don't print the wrong message below. } else { @@ -406,7 +420,7 @@ func (i *initCmd) writeOutput( idFile.OwnerID = ownerID idFile.ClusterID = clusterID - if err := fileHandler.WriteJSON(constants.ClusterIDsFileName, idFile, file.OptOverwrite); err != nil { + if err := i.fileHandler.WriteJSON(constants.ClusterIDsFileName, idFile, file.OptOverwrite); err != nil { return fmt.Errorf("writing Constellation ID file: %w", err) } i.log.Debugf("Constellation ID file written to %s", constants.ClusterIDsFileName) @@ -491,11 +505,11 @@ type initFlags struct { } // readOrGenerateMasterSecret reads a base64 encoded master secret from file or generates a new 32 byte secret. -func (i *initCmd) readOrGenerateMasterSecret(outWriter io.Writer, fileHandler file.Handler, filename string) (uri.MasterSecret, error) { +func (i *initCmd) readOrGenerateMasterSecret(outWriter io.Writer, filename string) (uri.MasterSecret, error) { if filename != "" { i.log.Debugf("Reading master secret from file %q", filename) var secret uri.MasterSecret - if err := fileHandler.ReadJSON(filename, &secret); err != nil { + if err := i.fileHandler.ReadJSON(filename, &secret); err != nil { return uri.MasterSecret{}, err } @@ -523,14 +537,14 @@ func (i *initCmd) readOrGenerateMasterSecret(outWriter io.Writer, fileHandler fi Salt: salt, } i.log.Debugf("Generated master secret key and salt values") - if err := fileHandler.WriteJSON(constants.MasterSecretFilename, secret, file.OptNone); err != nil { + if err := i.fileHandler.WriteJSON(constants.MasterSecretFilename, secret, file.OptNone); err != nil { return uri.MasterSecret{}, err } fmt.Fprintf(outWriter, "Your Constellation master secret was successfully written to ./%s\n", constants.MasterSecretFilename) return secret, nil } -func (i *initCmd) getMarshaledServiceAccountURI(provider cloudprovider.Provider, config *config.Config, fileHandler file.Handler) (string, error) { +func (i *initCmd) getMarshaledServiceAccountURI(provider cloudprovider.Provider, config *config.Config) (string, error) { i.log.Debugf("Getting service account URI") switch provider { case cloudprovider.GCP: @@ -539,7 +553,7 @@ func (i *initCmd) getMarshaledServiceAccountURI(provider cloudprovider.Provider, i.log.Debugf("GCP service account key path %s", path) var key gcpshared.ServiceAccountKey - if err := fileHandler.ReadJSON(path, &key); err != nil { + if err := i.fileHandler.ReadJSON(path, &key); err != nil { return "", fmt.Errorf("reading service account key from path %q: %w", path, err) } i.log.Debugf("Read GCP service account key from path") diff --git a/cli/internal/cmd/init_test.go b/cli/internal/cmd/init_test.go index e693ab5ab..582ad9a2b 100644 --- a/cli/internal/cmd/init_test.go +++ b/cli/internal/cmd/init_test.go @@ -185,8 +185,8 @@ func TestInitialize(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 4*time.Second) defer cancel() cmd.SetContext(ctx) - i := &initCmd{log: logger.NewTest(t), spinner: &nopSpinner{}, helmInstaller: &stubHelmInstaller{}, tfClient: &stubShowCluster{}} - err := i.initialize(cmd, newDialer, fileHandler, &stubLicenseClient{}, stubAttestationFetcher{}) + i := newInitCmd(&stubShowCluster{}, &stubHelmInstaller{}, fileHandler, &nopSpinner{}, nil, logger.NewTest(t)) + err := i.initialize(cmd, newDialer, &stubLicenseClient{}, stubAttestationFetcher{}) if tc.wantErr { assert.Error(err) @@ -301,11 +301,9 @@ func TestWriteOutput(t *testing.T) { UID: "test-uid", IP: "cluster-ip", } - i := &initCmd{ - log: logger.NewTest(t), - merger: &stubMerger{}, - } - err := i.writeOutput(idFile, resp.GetInitSuccess(), false, &out, fileHandler) + + i := newInitCmd(nil, nil, fileHandler, nil, &stubMerger{}, logger.NewTest(t)) + err := i.writeOutput(idFile, resp.GetInitSuccess(), false, &out) require.NoError(err) // assert.Contains(out.String(), ownerID) assert.Contains(out.String(), clusterID) @@ -326,7 +324,7 @@ func TestWriteOutput(t *testing.T) { // test config merging out.Reset() require.NoError(afs.Remove(constants.AdminConfFilename)) - err = i.writeOutput(idFile, resp.GetInitSuccess(), true, &out, fileHandler) + err = i.writeOutput(idFile, resp.GetInitSuccess(), true, &out) require.NoError(err) // assert.Contains(out.String(), ownerID) assert.Contains(out.String(), clusterID) @@ -338,7 +336,7 @@ func TestWriteOutput(t *testing.T) { i.merger = &stubMerger{envVar: "/some/path/to/kubeconfig"} out.Reset() require.NoError(afs.Remove(constants.AdminConfFilename)) - err = i.writeOutput(idFile, resp.GetInitSuccess(), true, &out, fileHandler) + err = i.writeOutput(idFile, resp.GetInitSuccess(), true, &out) require.NoError(err) // assert.Contains(out.String(), ownerID) assert.Contains(out.String(), clusterID) @@ -435,8 +433,8 @@ func TestReadOrGenerateMasterSecret(t *testing.T) { require.NoError(tc.createFileFunc(fileHandler)) var out bytes.Buffer - i := &initCmd{log: logger.NewTest(t)} - secret, err := i.readOrGenerateMasterSecret(&out, fileHandler, tc.filename) + i := newInitCmd(nil, nil, fileHandler, nil, nil, logger.NewTest(t)) + secret, err := i.readOrGenerateMasterSecret(&out, tc.filename) if tc.wantErr { assert.Error(err) @@ -529,8 +527,8 @@ func TestAttestation(t *testing.T) { defer cancel() cmd.SetContext(ctx) - i := &initCmd{log: logger.NewTest(t), spinner: &nopSpinner{}} - err := i.initialize(cmd, newDialer, fileHandler, &stubLicenseClient{}, stubAttestationFetcher{}) + i := newInitCmd(nil, nil, fileHandler, &nopSpinner{}, nil, logger.NewTest(t)) + err := i.initialize(cmd, newDialer, &stubLicenseClient{}, stubAttestationFetcher{}) assert.Error(err) // make sure the error is actually a TLS handshake error assert.Contains(err.Error(), "transport: authentication handshake failed") diff --git a/cli/internal/cmd/miniup.go b/cli/internal/cmd/miniup.go index 0527271d5..ecdf7df0d 100644 --- a/cli/internal/cmd/miniup.go +++ b/cli/internal/cmd/miniup.go @@ -14,6 +14,7 @@ import ( "github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd" "github.com/edgelesssys/constellation/v2/cli/internal/featureset" + "github.com/edgelesssys/constellation/v2/cli/internal/helm" "github.com/edgelesssys/constellation/v2/cli/internal/libvirt" "github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" @@ -203,8 +204,18 @@ func (m *miniUpCmd) initializeMiniCluster(cmd *cobra.Command, fileHandler file.H } m.log.Debugf("Created new logger") defer log.Sync() - i := &initCmd{log: log, merger: &kubeconfigMerger{log: log}, spinner: spinner} - if err := i.initialize(cmd, newDialer, fileHandler, license.NewClient(), m.configFetcher); err != nil { + + helmInstaller, err := helm.NewInitializer(log) + if err != nil { + return fmt.Errorf("creating Helm installer: %w", err) + } + tfClient, err := terraform.New(cmd.Context(), constants.TerraformWorkingDir) + if err != nil { + return fmt.Errorf("creating Terraform client: %w", err) + } + + i := newInitCmd(tfClient, helmInstaller, fileHandler, spinner, &kubeconfigMerger{log: log}, log) + if err := i.initialize(cmd, newDialer, license.NewClient(), m.configFetcher); err != nil { return err } m.log.Debugf("Initialized mini cluster")