Skip to content

Commit

Permalink
Use the same cloudcmd struct for create and apply
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Weiße <[email protected]>
  • Loading branch information
daniel-weisse committed Oct 26, 2023
1 parent f74d2e8 commit 8307eb3
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 82 deletions.
8 changes: 5 additions & 3 deletions cli/internal/cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,9 @@ func runApply(cmd *cobra.Command, _ []string) error {

upgradeID := generateUpgradeID(upgradeCmdKindApply)
upgradeDir := filepath.Join(constants.UpgradeDir, upgradeID)
clusterUpgrader, err := cloudcmd.NewClusterUpgrader(
cloudApplier, cleanUp, err := cloudcmd.NewApplier(
cmd.Context(),
spinner,
constants.TerraformWorkingDir,
upgradeDir,
flags.tfLogLevel,
Expand All @@ -145,6 +146,7 @@ func runApply(cmd *cobra.Command, _ []string) error {
if err != nil {
return fmt.Errorf("setting up cluster upgrader: %w", err)
}
defer cleanUp()

apply := &applyCmd{
fileHandler: fileHandler,
Expand All @@ -156,7 +158,7 @@ func runApply(cmd *cobra.Command, _ []string) error {
newHelmClient: newHelmClient,
newDialer: newDialer,
newKubeUpgrader: newKubeUpgrader,
clusterUpgrader: clusterUpgrader,
infraApplier: cloudApplier,
}

ctx, cancel := context.WithTimeout(cmd.Context(), time.Hour)
Expand All @@ -179,7 +181,7 @@ type applyCmd struct {
newHelmClient func(kubeConfigPath string, log debugLog) (helmApplier, error)
newDialer func(validator atls.Validator) *dialer.Dialer
newKubeUpgrader func(io.Writer, string, debugLog) (kubernetesUpgrader, error)
clusterUpgrader clusterUpgrader
infraApplier cloudApplier
}

/*
Expand Down
6 changes: 3 additions & 3 deletions cli/internal/cmd/applyterraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (a *applyCmd) planTerraformMigration(cmd *cobra.Command, conf *config.Confi
// u.infraApplier.AddManualStateMigration(migration)
// }

return a.clusterUpgrader.PlanClusterUpgrade(cmd.Context(), cmd.OutOrStdout(), vars, conf.GetProvider())
return a.infraApplier.Plan(cmd.Context(), conf)
}

// migrateTerraform migrates an existing Terraform state and the post-migration infrastructure state is returned.
Expand All @@ -82,7 +82,7 @@ func (a *applyCmd) migrateTerraform(cmd *cobra.Command, conf *config.Config, upg
cmd.Println("Aborting upgrade.")
// User doesn't expect to see any changes in his workspace after aborting an "upgrade apply",
// therefore, roll back to the backed up state.
if err := a.clusterUpgrader.RestoreClusterWorkspace(); err != nil {
if err := a.infraApplier.RestoreWorkspace(); err != nil {
return state.Infrastructure{}, fmt.Errorf(
"restoring Terraform workspace: %w, restore the Terraform workspace manually from %s ",
err,
Expand All @@ -95,7 +95,7 @@ func (a *applyCmd) migrateTerraform(cmd *cobra.Command, conf *config.Config, upg
a.log.Debugf("Applying Terraform migrations")

a.spinner.Start("Migrating Terraform resources", false)
infraState, err := a.clusterUpgrader.ApplyClusterUpgrade(cmd.Context(), conf.GetProvider())
infraState, err := a.infraApplier.Apply(cmd.Context(), conf.GetProvider(), cloudcmd.WithoutRollbackOnError)
a.spinner.Stop()
if err != nil {
return state.Infrastructure{}, fmt.Errorf("applying terraform migrations: %w", err)
Expand Down
9 changes: 2 additions & 7 deletions cli/internal/cmd/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,10 @@ import (
"github.com/edgelesssys/constellation/v2/internal/config"
)

type cloudCreator interface {
Create(ctx context.Context,
opts cloudcmd.CreateOptions,
) (state.Infrastructure, error)
}

type cloudApplier interface {
Plan(ctx context.Context, conf *config.Config) (bool, error)
Apply(ctx context.Context, csp cloudprovider.Provider, withRollback bool) (state.Infrastructure, error)
Apply(ctx context.Context, csp cloudprovider.Provider, rollback cloudcmd.RollbackBehavior) (state.Infrastructure, error)
RestoreWorkspace() error
}

type cloudIAMCreator interface {
Expand Down
23 changes: 13 additions & 10 deletions cli/internal/cmd/cloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,25 @@ func TestMain(m *testing.M) {
}

type stubCloudCreator struct {
createCalled bool
state state.Infrastructure
createErr error
state state.Infrastructure
planCalled bool
planErr error
applyCalled bool
applyErr error
}

func (c *stubCloudCreator) Create(_ context.Context, _ cloudcmd.CreateOptions) (state.Infrastructure, error) {
c.createCalled = true
return c.state, c.createErr
func (c *stubCloudCreator) Plan(_ context.Context, _ *config.Config) (bool, error) {
c.planCalled = true
return false, c.planErr
}

func (c *stubCloudCreator) Plan(_ context.Context, _ *config.Config) (bool, error) {
return false, nil
func (c *stubCloudCreator) Apply(_ context.Context, _ cloudprovider.Provider, _ cloudcmd.RollbackBehavior) (state.Infrastructure, error) {
c.applyCalled = true
return c.state, c.applyErr
}

func (c *stubCloudCreator) Apply(_ context.Context, _ cloudprovider.Provider, _ bool) (state.Infrastructure, error) {
return state.Infrastructure{}, nil
func (c *stubCloudCreator) RestoreWorkspace() error {
return nil
}

type stubCloudTerminator struct {
Expand Down
7 changes: 4 additions & 3 deletions cli/internal/cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"

"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
Expand Down Expand Up @@ -190,7 +191,7 @@ func (c *createCmd) create(cmd *cobra.Command, applier cloudApplier, fileHandler
if _, err := applier.Plan(cmd.Context(), conf); err != nil {
return fmt.Errorf("planning infrastructure creation: %w", err)
}
infraState, err := applier.Apply(cmd.Context(), conf.GetProvider(), true)
infraState, err := applier.Apply(cmd.Context(), conf.GetProvider(), cloudcmd.WithRollbackOnError)
spinner.Stop()
if err != nil {
return err
Expand Down Expand Up @@ -227,9 +228,9 @@ func (c *createCmd) checkDirClean(fileHandler file.Handler) error {
)
}
c.log.Debugf("Checking terraform working directory")
if clean, err := fileHandler.IsEmpty(constants.TerraformWorkingDir); err != nil {
if clean, err := fileHandler.IsEmpty(constants.TerraformWorkingDir); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("checking if terraform working directory is empty: %w", err)
} else if !clean {
} else if err == nil && !clean {
return fmt.Errorf(
"directory '%s' already exists and is not empty, run 'constellation terminate' before creating a new one",
c.flags.pathPrefixer.PrefixPrintablePath(constants.TerraformWorkingDir),
Expand Down
10 changes: 5 additions & 5 deletions cli/internal/cmd/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package cmd

import (
"bytes"
"errors"
"testing"

"github.com/edgelesssys/constellation/v2/cli/internal/state"
Expand Down Expand Up @@ -45,7 +44,6 @@ func TestCreate(t *testing.T) {
return fs
}
infraState := state.Infrastructure{ClusterEndpoint: "192.0.2.1"}
someErr := errors.New("failed")

testCases := map[string]struct {
setupFs func(*require.Assertions, cloudprovider.Provider) afero.Fs
Expand Down Expand Up @@ -125,7 +123,7 @@ func TestCreate(t *testing.T) {
},
"create error": {
setupFs: fsWithDefaultConfigAndState,
creator: &stubCloudCreator{createErr: someErr},
creator: &stubCloudCreator{applyErr: assert.AnError},
provider: cloudprovider.GCP,
yesFlag: true,
wantErr: true,
Expand Down Expand Up @@ -163,9 +161,11 @@ func TestCreate(t *testing.T) {
} else {
assert.NoError(err)
if tc.wantAbort {
assert.False(tc.creator.createCalled)
assert.False(tc.creator.planCalled)
assert.False(tc.creator.applyCalled)
} else {
assert.True(tc.creator.createCalled)
assert.True(tc.creator.planCalled)
assert.True(tc.creator.applyCalled)

var gotState state.State
expectedState := state.Infrastructure{
Expand Down
2 changes: 1 addition & 1 deletion cli/internal/cmd/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ func TestInitialize(t *testing.T) {
getClusterAttestationConfigErr: k8serrors.NewNotFound(schema.GroupResource{}, ""),
}, nil
},
clusterUpgrader: stubTerraformUpgrader{},
infraApplier: stubTerraformUpgrader{},
}

err := i.apply(cmd, stubAttestationFetcher{}, "test")
Expand Down
41 changes: 31 additions & 10 deletions cli/internal/cmd/miniup.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"time"

"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
Expand Down Expand Up @@ -58,7 +60,6 @@ func runUp(cmd *cobra.Command, _ []string) error {
return err
}
defer spinner.Stop()
creator := cloudcmd.NewCreator(spinner)

m := &miniUpCmd{
log: log,
Expand All @@ -68,15 +69,38 @@ func runUp(cmd *cobra.Command, _ []string) error {
if err := m.flags.parse(cmd.Flags()); err != nil {
return err
}

creator, cleanUp, err := cloudcmd.NewApplier(
cmd.Context(),
spinner,
constants.TerraformWorkingDir,
filepath.Join(constants.UpgradeDir, "create"), // Not used by create
m.flags.tfLogLevel,
m.fileHandler,
)
if err != nil {
return err
}
defer cleanUp()

return m.up(cmd, creator, spinner)
}

func (m *miniUpCmd) up(cmd *cobra.Command, creator cloudCreator, spinner spinnerInterf) error {
func (m *miniUpCmd) up(cmd *cobra.Command, creator cloudApplier, spinner spinnerInterf) error {
if err := m.checkSystemRequirements(cmd.ErrOrStderr()); err != nil {
return fmt.Errorf("system requirements not met: %w", err)
}

// create config if not passed as flag and set default values
if clean, err := m.fileHandler.IsEmpty(constants.TerraformWorkingDir); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("checking if terraform working directory is empty: %w", err)
} else if err == nil && !clean {
return fmt.Errorf(
"directory %q already exists and is not empty, run 'constellation mini down' before creating a new cluster",
m.flags.pathPrefixer.PrefixPrintablePath(constants.TerraformWorkingDir),
)
}

// create config if not present in directory and set default values
config, err := m.prepareConfig(cmd)
if err != nil {
return fmt.Errorf("preparing config: %w", err)
Expand Down Expand Up @@ -159,15 +183,12 @@ func (m *miniUpCmd) prepareExistingConfig(cmd *cobra.Command) (*config.Config, e
}

// createMiniCluster creates a new cluster using the given config.
func (m *miniUpCmd) createMiniCluster(ctx context.Context, creator cloudCreator, config *config.Config) error {
func (m *miniUpCmd) createMiniCluster(ctx context.Context, creator cloudApplier, config *config.Config) error {
m.log.Debugf("Creating mini cluster")
opts := cloudcmd.CreateOptions{
Provider: cloudprovider.QEMU,
Config: config,
TFWorkspace: constants.TerraformWorkingDir,
TFLogLevel: m.flags.tfLogLevel,
if _, err := creator.Plan(ctx, config); err != nil {
return err
}
infraState, err := creator.Create(ctx, opts)
infraState, err := creator.Apply(ctx, config.GetProvider(), cloudcmd.WithoutRollbackOnError)
if err != nil {
return err
}
Expand Down
10 changes: 0 additions & 10 deletions cli/internal/cmd/upgradeapply.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@ package cmd
import (
"context"
"fmt"
"io"
"strings"
"time"

"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"
"github.com/edgelesssys/constellation/v2/internal/config"
"github.com/rogpeppe/go-internal/diff"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -108,9 +104,3 @@ type kubernetesUpgrader interface {
BackupCRs(ctx context.Context, crds []apiextensionsv1.CustomResourceDefinition, upgradeDir string) error
BackupCRDs(ctx context.Context, upgradeDir string) ([]apiextensionsv1.CustomResourceDefinition, error)
}

type clusterUpgrader interface {
PlanClusterUpgrade(ctx context.Context, outWriter io.Writer, vars terraform.Variables, csp cloudprovider.Provider) (bool, error)
ApplyClusterUpgrade(ctx context.Context, csp cloudprovider.Provider) (state.Infrastructure, error)
RestoreClusterWorkspace() error
}
32 changes: 11 additions & 21 deletions cli/internal/cmd/upgradeapply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import (
"io"
"testing"

"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
"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/attestation/variant"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/config"
Expand Down Expand Up @@ -53,7 +53,7 @@ func TestUpgradeApply(t *testing.T) {
kubeUpgrader *stubKubernetesUpgrader
fh func() file.Handler
fhAssertions func(require *require.Assertions, assert *assert.Assertions, fh file.Handler)
terraformUpgrader clusterUpgrader
terraformUpgrader cloudApplier
wantErr bool
customK8sVersion string
flags applyFlags
Expand Down Expand Up @@ -265,7 +265,7 @@ func TestUpgradeApply(t *testing.T) {
newKubeUpgrader: func(_ io.Writer, _ string, _ debugLog) (kubernetesUpgrader, error) {
return tc.kubeUpgrader, nil
},
clusterUpgrader: tc.terraformUpgrader,
infraApplier: tc.terraformUpgrader,
}
err := upgrader.apply(cmd, stubAttestationFetcher{}, "test")
if tc.wantErr {
Expand Down Expand Up @@ -341,50 +341,40 @@ func (u *stubKubernetesUpgrader) ExtendClusterConfigCertSANs(_ context.Context,
return nil
}

// TODO(v2.11): Remove this function after v2.11 is released.
func (u *stubKubernetesUpgrader) RemoveAttestationConfigHelmManagement(_ context.Context) error {
return nil
}

// TODO(v2.12): Remove this function.
func (u *stubKubernetesUpgrader) RemoveHelmKeepAnnotation(_ context.Context) error {
return nil
}

type stubTerraformUpgrader struct {
terraformDiff bool
planTerraformErr error
applyTerraformErr error
rollbackWorkspaceErr error
}

func (u stubTerraformUpgrader) PlanClusterUpgrade(_ context.Context, _ io.Writer, _ terraform.Variables, _ cloudprovider.Provider) (bool, error) {
func (u stubTerraformUpgrader) Plan(_ context.Context, _ *config.Config) (bool, error) {
return u.terraformDiff, u.planTerraformErr
}

func (u stubTerraformUpgrader) ApplyClusterUpgrade(_ context.Context, _ cloudprovider.Provider) (state.Infrastructure, error) {
func (u stubTerraformUpgrader) Apply(_ context.Context, _ cloudprovider.Provider, _ cloudcmd.RollbackBehavior) (state.Infrastructure, error) {
return state.Infrastructure{}, u.applyTerraformErr
}

func (u stubTerraformUpgrader) RestoreClusterWorkspace() error {
func (u stubTerraformUpgrader) RestoreWorkspace() error {
return u.rollbackWorkspaceErr
}

type mockTerraformUpgrader struct {
mock.Mock
}

func (m *mockTerraformUpgrader) PlanClusterUpgrade(ctx context.Context, w io.Writer, variables terraform.Variables, provider cloudprovider.Provider) (bool, error) {
args := m.Called(ctx, w, variables, provider)
func (m *mockTerraformUpgrader) Plan(ctx context.Context, conf *config.Config) (bool, error) {
args := m.Called(ctx, conf)
return args.Bool(0), args.Error(1)
}

func (m *mockTerraformUpgrader) ApplyClusterUpgrade(ctx context.Context, provider cloudprovider.Provider) (state.Infrastructure, error) {
args := m.Called(ctx, provider)
func (m *mockTerraformUpgrader) Apply(ctx context.Context, provider cloudprovider.Provider, rollback cloudcmd.RollbackBehavior) (state.Infrastructure, error) {
args := m.Called(ctx, provider, rollback)
return args.Get(0).(state.Infrastructure), args.Error(1)
}

func (m *mockTerraformUpgrader) RestoreClusterWorkspace() error {
func (m *mockTerraformUpgrader) RestoreWorkspace() error {
args := m.Called()
return args.Error(0)
}
Expand Down
Loading

0 comments on commit 8307eb3

Please sign in to comment.