mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-02-03 02:50:03 -05:00
cli: store upgrade files in versioned folders (#1929)
* upgrade versioning * dont pass upgrade kind as boolean * whitespace * fix godot lint check * clarify upgrade check directory suffix * cli: dry-run Terraform migrations on `upgrade check` (#1942) * dry-run Terraform migrations on upgrade check * clean whole upgrade dir * clean up check workspace after planning * fix parsing * extend upgrade check test * rename unused parameters * exclude false positives in test
This commit is contained in:
parent
f3c2198a9a
commit
b25228d175
@ -62,7 +62,7 @@ func runUpgradeApply(cmd *cobra.Command, _ []string) error {
|
|||||||
defer log.Sync()
|
defer log.Sync()
|
||||||
|
|
||||||
fileHandler := file.NewHandler(afero.NewOsFs())
|
fileHandler := file.NewHandler(afero.NewOsFs())
|
||||||
upgrader, err := kubernetes.NewUpgrader(cmd.Context(), cmd.OutOrStdout(), log)
|
upgrader, err := kubernetes.NewUpgrader(cmd.Context(), cmd.OutOrStdout(), log, kubernetes.UpgradeCmdKindApply)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ func (u *upgradeApplyCmd) migrateTerraform(cmd *cobra.Command, file file.Handler
|
|||||||
return fmt.Errorf("checking workspace: %w", err)
|
return fmt.Errorf("checking workspace: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
targets, vars, err := u.parseUpgradeVars(cmd, conf, fetcher)
|
targets, vars, err := parseTerraformUpgradeVars(cmd, conf, fetcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parsing upgrade variables: %w", err)
|
return fmt.Errorf("parsing upgrade variables: %w", err)
|
||||||
}
|
}
|
||||||
@ -201,7 +201,8 @@ func (u *upgradeApplyCmd) migrateTerraform(cmd *cobra.Command, file file.Handler
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *upgradeApplyCmd) parseUpgradeVars(cmd *cobra.Command, conf *config.Config, fetcher imageFetcher) ([]string, terraform.Variables, error) {
|
// parseTerraformUpgradeVars parses the variables required to execute the Terraform script with.
|
||||||
|
func parseTerraformUpgradeVars(cmd *cobra.Command, conf *config.Config, fetcher imageFetcher) ([]string, terraform.Variables, error) {
|
||||||
// Fetch variables to execute Terraform script with
|
// Fetch variables to execute Terraform script with
|
||||||
provider := conf.GetProvider()
|
provider := conf.GetProvider()
|
||||||
attestationVariant := conf.GetAttestationConfig().GetVariant()
|
attestationVariant := conf.GetAttestationConfig().GetVariant()
|
||||||
|
@ -18,6 +18,8 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/cli/internal/featureset"
|
"github.com/edgelesssys/constellation/v2/cli/internal/featureset"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
|
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
|
||||||
|
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||||
|
"github.com/edgelesssys/constellation/v2/cli/internal/upgrade"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
|
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||||
@ -28,6 +30,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"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/edgelesssys/constellation/v2/internal/imagefetcher"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
|
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
|
||||||
conSemver "github.com/edgelesssys/constellation/v2/internal/semver"
|
conSemver "github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||||
@ -65,7 +68,7 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
checker, err := kubernetes.NewUpgrader(cmd.Context(), cmd.OutOrStdout(), log)
|
checker, err := kubernetes.NewUpgrader(cmd.Context(), cmd.OutOrStdout(), log, kubernetes.UpgradeCmdKindCheck)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -89,7 +92,9 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
|
|||||||
log: log,
|
log: log,
|
||||||
versionsapi: versionfetcher,
|
versionsapi: versionfetcher,
|
||||||
},
|
},
|
||||||
log: log,
|
checker: checker,
|
||||||
|
imagefetcher: imagefetcher.New(),
|
||||||
|
log: log,
|
||||||
}
|
}
|
||||||
|
|
||||||
return up.upgradeCheck(cmd, fileHandler, attestationconfigapi.NewFetcher(), flags)
|
return up.upgradeCheck(cmd, fileHandler, attestationconfigapi.NewFetcher(), flags)
|
||||||
@ -98,36 +103,49 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
|
|||||||
func parseUpgradeCheckFlags(cmd *cobra.Command) (upgradeCheckFlags, error) {
|
func parseUpgradeCheckFlags(cmd *cobra.Command) (upgradeCheckFlags, error) {
|
||||||
configPath, err := cmd.Flags().GetString("config")
|
configPath, err := cmd.Flags().GetString("config")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return upgradeCheckFlags{}, err
|
return upgradeCheckFlags{}, fmt.Errorf("parsing config string: %w", err)
|
||||||
}
|
}
|
||||||
force, err := cmd.Flags().GetBool("force")
|
force, err := cmd.Flags().GetBool("force")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return upgradeCheckFlags{}, err
|
return upgradeCheckFlags{}, fmt.Errorf("parsing force bool: %w", err)
|
||||||
}
|
}
|
||||||
writeConfig, err := cmd.Flags().GetBool("write-config")
|
writeConfig, err := cmd.Flags().GetBool("write-config")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return upgradeCheckFlags{}, err
|
return upgradeCheckFlags{}, fmt.Errorf("parsing write-config bool: %w", err)
|
||||||
}
|
}
|
||||||
ref, err := cmd.Flags().GetString("ref")
|
ref, err := cmd.Flags().GetString("ref")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return upgradeCheckFlags{}, err
|
return upgradeCheckFlags{}, fmt.Errorf("parsing ref string: %w", err)
|
||||||
}
|
}
|
||||||
stream, err := cmd.Flags().GetString("stream")
|
stream, err := cmd.Flags().GetString("stream")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return upgradeCheckFlags{}, err
|
return upgradeCheckFlags{}, fmt.Errorf("parsing stream string: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logLevelString, err := cmd.Flags().GetString("tf-log")
|
||||||
|
if err != nil {
|
||||||
|
return upgradeCheckFlags{}, fmt.Errorf("parsing tf-log string: %w", err)
|
||||||
|
}
|
||||||
|
logLevel, err := terraform.ParseLogLevel(logLevelString)
|
||||||
|
if err != nil {
|
||||||
|
return upgradeCheckFlags{}, fmt.Errorf("parsing Terraform log level %s: %w", logLevelString, err)
|
||||||
|
}
|
||||||
|
|
||||||
return upgradeCheckFlags{
|
return upgradeCheckFlags{
|
||||||
configPath: configPath,
|
configPath: configPath,
|
||||||
force: force,
|
force: force,
|
||||||
writeConfig: writeConfig,
|
writeConfig: writeConfig,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
stream: stream,
|
stream: stream,
|
||||||
|
terraformLogLevel: logLevel,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type upgradeCheckCmd struct {
|
type upgradeCheckCmd struct {
|
||||||
canUpgradeCheck bool
|
canUpgradeCheck bool
|
||||||
collect collector
|
collect collector
|
||||||
|
checker upgradeChecker
|
||||||
|
imagefetcher imageFetcher
|
||||||
log debugLog
|
log debugLog
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +202,44 @@ func (u *upgradeCheckCmd) upgradeCheck(cmd *cobra.Command, fileHandler file.Hand
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u.log.Debugf("Planning Terraform migrations")
|
||||||
|
|
||||||
|
if err := u.checker.CheckTerraformMigrations(fileHandler); err != nil {
|
||||||
|
return fmt.Errorf("checking workspace: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
targets, vars, err := parseTerraformUpgradeVars(cmd, conf, u.imagefetcher)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("parsing upgrade variables: %w", err)
|
||||||
|
}
|
||||||
|
u.log.Debugf("Using migration targets:\n%v", targets)
|
||||||
|
u.log.Debugf("Using Terraform variables:\n%v", vars)
|
||||||
|
|
||||||
|
opts := upgrade.TerraformUpgradeOptions{
|
||||||
|
LogLevel: flags.terraformLogLevel,
|
||||||
|
CSP: conf.GetProvider(),
|
||||||
|
Vars: vars,
|
||||||
|
Targets: targets,
|
||||||
|
OutputFile: constants.TerraformMigrationOutputFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Println("The following Teraform migrations are available with this CLI:")
|
||||||
|
|
||||||
|
// Check if there are any Terraform migrations
|
||||||
|
hasDiff, err := u.checker.PlanTerraformMigrations(cmd.Context(), opts)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("planning terraform migrations: %w", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := u.checker.CleanUpTerraformMigrations(fileHandler); err != nil {
|
||||||
|
u.log.Debugf("Failed to clean up Terraform migrations: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if !hasDiff {
|
||||||
|
cmd.Println(" No Terraform migrations are available.")
|
||||||
|
}
|
||||||
|
|
||||||
upgrade := versionUpgrade{
|
upgrade := versionUpgrade{
|
||||||
newServices: newServices,
|
newServices: newServices,
|
||||||
newImages: newImages,
|
newImages: newImages,
|
||||||
@ -661,16 +717,20 @@ func (v *versionCollector) filterCompatibleCLIVersions(ctx context.Context, cliP
|
|||||||
}
|
}
|
||||||
|
|
||||||
type upgradeCheckFlags struct {
|
type upgradeCheckFlags struct {
|
||||||
configPath string
|
configPath string
|
||||||
force bool
|
force bool
|
||||||
writeConfig bool
|
writeConfig bool
|
||||||
ref string
|
ref string
|
||||||
stream string
|
stream string
|
||||||
|
terraformLogLevel terraform.LogLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
type upgradeChecker interface {
|
type upgradeChecker interface {
|
||||||
CurrentImage(ctx context.Context) (string, error)
|
CurrentImage(ctx context.Context) (string, error)
|
||||||
CurrentKubernetesVersion(ctx context.Context) (string, error)
|
CurrentKubernetesVersion(ctx context.Context) (string, error)
|
||||||
|
PlanTerraformMigrations(ctx context.Context, opts upgrade.TerraformUpgradeOptions) (bool, error)
|
||||||
|
CheckTerraformMigrations(fileHandler file.Handler) error
|
||||||
|
CleanUpTerraformMigrations(fileHandler file.Handler) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type versionListFetcher interface {
|
type versionListFetcher interface {
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/cli/internal/upgrade"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||||
@ -224,34 +225,53 @@ func TestUpgradeCheck(t *testing.T) {
|
|||||||
Version: "v2.5.0",
|
Version: "v2.5.0",
|
||||||
Kind: versionsapi.VersionKindImage,
|
Kind: versionsapi.VersionKindImage,
|
||||||
}
|
}
|
||||||
|
collector := stubVersionCollector{
|
||||||
|
supportedServicesVersions: "v2.5.0",
|
||||||
|
supportedImages: []versionsapi.Version{v2_3},
|
||||||
|
supportedImageVersions: map[string]measurements.M{
|
||||||
|
"v2.3.0": measurements.DefaultsFor(cloudprovider.GCP, variant.GCPSEVES{}),
|
||||||
|
},
|
||||||
|
supportedK8sVersions: []string{"v1.24.5", "v1.24.12", "v1.25.6"},
|
||||||
|
currentServicesVersions: "v2.4.0",
|
||||||
|
currentImageVersion: "v2.4.0",
|
||||||
|
currentK8sVersion: "v1.24.5",
|
||||||
|
currentCLIVersion: "v2.4.0",
|
||||||
|
images: []versionsapi.Version{v2_5},
|
||||||
|
newCLIVersionsList: []string{"v2.5.0", "v2.6.0"},
|
||||||
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
collector stubVersionCollector
|
collector stubVersionCollector
|
||||||
flags upgradeCheckFlags
|
flags upgradeCheckFlags
|
||||||
csp cloudprovider.Provider
|
csp cloudprovider.Provider
|
||||||
cliVersion string
|
checker stubUpgradeChecker
|
||||||
wantError bool
|
imagefetcher stubImageFetcher
|
||||||
|
cliVersion string
|
||||||
|
wantError bool
|
||||||
}{
|
}{
|
||||||
"upgrades gcp": {
|
"upgrades gcp": {
|
||||||
collector: stubVersionCollector{
|
collector: collector,
|
||||||
supportedServicesVersions: "v2.5.0",
|
checker: stubUpgradeChecker{},
|
||||||
supportedImages: []versionsapi.Version{v2_3},
|
imagefetcher: stubImageFetcher{},
|
||||||
supportedImageVersions: map[string]measurements.M{
|
|
||||||
"v2.3.0": measurements.DefaultsFor(cloudprovider.GCP, variant.GCPSEVES{}),
|
|
||||||
},
|
|
||||||
supportedK8sVersions: []string{"v1.24.5", "v1.24.12", "v1.25.6"},
|
|
||||||
currentServicesVersions: "v2.4.0",
|
|
||||||
currentImageVersion: "v2.4.0",
|
|
||||||
currentK8sVersion: "v1.24.5",
|
|
||||||
currentCLIVersion: "v2.4.0",
|
|
||||||
images: []versionsapi.Version{v2_5},
|
|
||||||
newCLIVersionsList: []string{"v2.5.0", "v2.6.0"},
|
|
||||||
},
|
|
||||||
flags: upgradeCheckFlags{
|
flags: upgradeCheckFlags{
|
||||||
configPath: constants.ConfigFilename,
|
configPath: constants.ConfigFilename,
|
||||||
},
|
},
|
||||||
csp: cloudprovider.GCP,
|
csp: cloudprovider.GCP,
|
||||||
cliVersion: "v1.0.0",
|
cliVersion: "v1.0.0",
|
||||||
},
|
},
|
||||||
|
"terraform err": {
|
||||||
|
collector: collector,
|
||||||
|
checker: stubUpgradeChecker{
|
||||||
|
err: assert.AnError,
|
||||||
|
},
|
||||||
|
imagefetcher: stubImageFetcher{},
|
||||||
|
flags: upgradeCheckFlags{
|
||||||
|
configPath: constants.ConfigFilename,
|
||||||
|
},
|
||||||
|
csp: cloudprovider.GCP,
|
||||||
|
cliVersion: "v1.0.0",
|
||||||
|
wantError: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, tc := range testCases {
|
for name, tc := range testCases {
|
||||||
@ -266,6 +286,8 @@ func TestUpgradeCheck(t *testing.T) {
|
|||||||
checkCmd := upgradeCheckCmd{
|
checkCmd := upgradeCheckCmd{
|
||||||
canUpgradeCheck: true,
|
canUpgradeCheck: true,
|
||||||
collect: &tc.collector,
|
collect: &tc.collector,
|
||||||
|
checker: tc.checker,
|
||||||
|
imagefetcher: tc.imagefetcher,
|
||||||
log: logger.NewTest(t),
|
log: logger.NewTest(t),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,6 +360,7 @@ func (s *stubVersionCollector) filterCompatibleCLIVersions(_ context.Context, _
|
|||||||
type stubUpgradeChecker struct {
|
type stubUpgradeChecker struct {
|
||||||
image string
|
image string
|
||||||
k8sVersion string
|
k8sVersion string
|
||||||
|
tfDiff bool
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,10 +368,22 @@ func (u stubUpgradeChecker) CurrentImage(context.Context) (string, error) {
|
|||||||
return u.image, u.err
|
return u.image, u.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u stubUpgradeChecker) CurrentKubernetesVersion(_ context.Context) (string, error) {
|
func (u stubUpgradeChecker) CurrentKubernetesVersion(context.Context) (string, error) {
|
||||||
return u.k8sVersion, u.err
|
return u.k8sVersion, u.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u stubUpgradeChecker) PlanTerraformMigrations(context.Context, upgrade.TerraformUpgradeOptions) (bool, error) {
|
||||||
|
return u.tfDiff, u.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u stubUpgradeChecker) CheckTerraformMigrations(file.Handler) error {
|
||||||
|
return u.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u stubUpgradeChecker) CleanUpTerraformMigrations(file.Handler) error {
|
||||||
|
return u.err
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewCLIVersions(t *testing.T) {
|
func TestNewCLIVersions(t *testing.T) {
|
||||||
someErr := errors.New("some error")
|
someErr := errors.New("some error")
|
||||||
minorList := func() versionsapi.List {
|
minorList := func() versionsapi.List {
|
||||||
|
@ -17,17 +17,13 @@ import (
|
|||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func (c *Client) backupCRDs(ctx context.Context, upgradeID string) ([]apiextensionsv1.CustomResourceDefinition, error) {
|
||||||
backupFolder = filepath.Join(constants.UpgradeDir, "backups") + string(filepath.Separator)
|
|
||||||
crdBackupFolder = filepath.Join(backupFolder, "crds") + string(filepath.Separator)
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Client) backupCRDs(ctx context.Context) ([]apiextensionsv1.CustomResourceDefinition, error) {
|
|
||||||
crds, err := c.kubectl.GetCRDs(ctx)
|
crds, err := c.kubectl.GetCRDs(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("getting CRDs: %w", err)
|
return nil, fmt.Errorf("getting CRDs: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crdBackupFolder := c.crdBackupFolder(upgradeID)
|
||||||
if err := c.fs.MkdirAll(crdBackupFolder); err != nil {
|
if err := c.fs.MkdirAll(crdBackupFolder); err != nil {
|
||||||
return nil, fmt.Errorf("creating backup dir: %w", err)
|
return nil, fmt.Errorf("creating backup dir: %w", err)
|
||||||
}
|
}
|
||||||
@ -54,7 +50,7 @@ func (c *Client) backupCRDs(ctx context.Context) ([]apiextensionsv1.CustomResour
|
|||||||
return crds, nil
|
return crds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) backupCRs(ctx context.Context, crds []apiextensionsv1.CustomResourceDefinition) error {
|
func (c *Client) backupCRs(ctx context.Context, crds []apiextensionsv1.CustomResourceDefinition, upgradeID string) error {
|
||||||
for _, crd := range crds {
|
for _, crd := range crds {
|
||||||
for _, version := range crd.Spec.Versions {
|
for _, version := range crd.Spec.Versions {
|
||||||
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: version.Name, Resource: crd.Spec.Names.Plural}
|
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: version.Name, Resource: crd.Spec.Names.Plural}
|
||||||
@ -63,6 +59,7 @@ func (c *Client) backupCRs(ctx context.Context, crds []apiextensionsv1.CustomRes
|
|||||||
return fmt.Errorf("retrieving CR %s: %w", crd.Name, err)
|
return fmt.Errorf("retrieving CR %s: %w", crd.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
backupFolder := c.backupFolder(upgradeID)
|
||||||
for _, cr := range crs {
|
for _, cr := range crs {
|
||||||
targetFolder := filepath.Join(backupFolder, gvr.Group, gvr.Version, cr.GetNamespace(), cr.GetKind())
|
targetFolder := filepath.Join(backupFolder, gvr.Group, gvr.Version, cr.GetNamespace(), cr.GetKind())
|
||||||
if err := c.fs.MkdirAll(targetFolder); err != nil {
|
if err := c.fs.MkdirAll(targetFolder); err != nil {
|
||||||
@ -83,3 +80,11 @@ func (c *Client) backupCRs(ctx context.Context, crds []apiextensionsv1.CustomRes
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) backupFolder(upgradeID string) string {
|
||||||
|
return filepath.Join(constants.UpgradeDir, upgradeID, "backups") + string(filepath.Separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) crdBackupFolder(upgradeID string) string {
|
||||||
|
return filepath.Join(c.backupFolder(upgradeID), "crds") + string(filepath.Separator)
|
||||||
|
}
|
||||||
|
@ -24,16 +24,19 @@ import (
|
|||||||
|
|
||||||
func TestBackupCRDs(t *testing.T) {
|
func TestBackupCRDs(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
|
upgradeID string
|
||||||
crd string
|
crd string
|
||||||
expectedFile string
|
expectedFile string
|
||||||
getCRDsError error
|
getCRDsError error
|
||||||
wantError bool
|
wantError bool
|
||||||
}{
|
}{
|
||||||
"success": {
|
"success": {
|
||||||
|
upgradeID: "1234",
|
||||||
crd: "apiVersion: \nkind: \nmetadata:\n name: foobar\n creationTimestamp: null\nspec:\n group: \"\"\n names:\n kind: \"somename\"\n plural: \"somenames\"\n scope: \"\"\n versions: null\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: null\n storedVersions: null\n",
|
crd: "apiVersion: \nkind: \nmetadata:\n name: foobar\n creationTimestamp: null\nspec:\n group: \"\"\n names:\n kind: \"somename\"\n plural: \"somenames\"\n scope: \"\"\n versions: null\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: null\n storedVersions: null\n",
|
||||||
expectedFile: "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n name: foobar\n creationTimestamp: null\nspec:\n group: \"\"\n names:\n kind: \"somename\"\n plural: \"somenames\"\n scope: \"\"\n versions: null\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: null\n storedVersions: null\n",
|
expectedFile: "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n name: foobar\n creationTimestamp: null\nspec:\n group: \"\"\n names:\n kind: \"somename\"\n plural: \"somenames\"\n scope: \"\"\n versions: null\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: null\n storedVersions: null\n",
|
||||||
},
|
},
|
||||||
"api request fails": {
|
"api request fails": {
|
||||||
|
upgradeID: "1234",
|
||||||
getCRDsError: errors.New("api error"),
|
getCRDsError: errors.New("api error"),
|
||||||
wantError: true,
|
wantError: true,
|
||||||
},
|
},
|
||||||
@ -55,14 +58,14 @@ func TestBackupCRDs(t *testing.T) {
|
|||||||
log: stubLog{},
|
log: stubLog{},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.backupCRDs(context.Background())
|
_, err = client.backupCRDs(context.Background(), tc.upgradeID)
|
||||||
if tc.wantError {
|
if tc.wantError {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
data, err := afero.ReadFile(memFs, filepath.Join(crdBackupFolder, crd.Name+".yaml"))
|
data, err := afero.ReadFile(memFs, filepath.Join(client.crdBackupFolder(tc.upgradeID), crd.Name+".yaml"))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
assert.YAMLEq(tc.expectedFile, string(data))
|
assert.YAMLEq(tc.expectedFile, string(data))
|
||||||
})
|
})
|
||||||
@ -71,6 +74,7 @@ func TestBackupCRDs(t *testing.T) {
|
|||||||
|
|
||||||
func TestBackupCRs(t *testing.T) {
|
func TestBackupCRs(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
|
upgradeID string
|
||||||
crd apiextensionsv1.CustomResourceDefinition
|
crd apiextensionsv1.CustomResourceDefinition
|
||||||
resource unstructured.Unstructured
|
resource unstructured.Unstructured
|
||||||
expectedFile string
|
expectedFile string
|
||||||
@ -78,6 +82,7 @@ func TestBackupCRs(t *testing.T) {
|
|||||||
wantError bool
|
wantError bool
|
||||||
}{
|
}{
|
||||||
"success": {
|
"success": {
|
||||||
|
upgradeID: "1234",
|
||||||
crd: apiextensionsv1.CustomResourceDefinition{
|
crd: apiextensionsv1.CustomResourceDefinition{
|
||||||
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
|
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
|
||||||
Names: apiextensionsv1.CustomResourceDefinitionNames{
|
Names: apiextensionsv1.CustomResourceDefinitionNames{
|
||||||
@ -95,6 +100,7 @@ func TestBackupCRs(t *testing.T) {
|
|||||||
expectedFile: "metadata:\n name: foobar\n",
|
expectedFile: "metadata:\n name: foobar\n",
|
||||||
},
|
},
|
||||||
"api request fails": {
|
"api request fails": {
|
||||||
|
upgradeID: "1234",
|
||||||
crd: apiextensionsv1.CustomResourceDefinition{
|
crd: apiextensionsv1.CustomResourceDefinition{
|
||||||
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
|
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
|
||||||
Names: apiextensionsv1.CustomResourceDefinitionNames{
|
Names: apiextensionsv1.CustomResourceDefinitionNames{
|
||||||
@ -126,14 +132,14 @@ func TestBackupCRs(t *testing.T) {
|
|||||||
log: stubLog{},
|
log: stubLog{},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := client.backupCRs(context.Background(), []apiextensionsv1.CustomResourceDefinition{tc.crd})
|
err := client.backupCRs(context.Background(), []apiextensionsv1.CustomResourceDefinition{tc.crd}, tc.upgradeID)
|
||||||
if tc.wantError {
|
if tc.wantError {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
data, err := afero.ReadFile(memFs, filepath.Join(backupFolder, tc.crd.Spec.Group, tc.crd.Spec.Versions[0].Name, tc.resource.GetNamespace(), tc.resource.GetKind(), tc.resource.GetName()+".yaml"))
|
data, err := afero.ReadFile(memFs, filepath.Join(client.backupFolder(tc.upgradeID), tc.crd.Spec.Group, tc.crd.Spec.Versions[0].Name, tc.resource.GetNamespace(), tc.resource.GetKind(), tc.resource.GetName()+".yaml"))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
assert.YAMLEq(tc.expectedFile, string(data))
|
assert.YAMLEq(tc.expectedFile, string(data))
|
||||||
})
|
})
|
||||||
|
@ -102,7 +102,7 @@ func (c *Client) shouldUpgrade(releaseName, newVersion string) error {
|
|||||||
// Upgrade runs a helm-upgrade on all deployments that are managed via Helm.
|
// Upgrade runs a helm-upgrade on all deployments that are managed via Helm.
|
||||||
// If the CLI receives an interrupt signal it will cancel the context.
|
// If the CLI receives an interrupt signal it will cancel the context.
|
||||||
// Canceling the context will prompt helm to abort and roll back the ongoing upgrade.
|
// Canceling the context will prompt helm to abort and roll back the ongoing upgrade.
|
||||||
func (c *Client) Upgrade(ctx context.Context, config *config.Config, timeout time.Duration, allowDestructive bool) error {
|
func (c *Client) Upgrade(ctx context.Context, config *config.Config, timeout time.Duration, allowDestructive bool, upgradeID string) error {
|
||||||
upgradeErrs := []error{}
|
upgradeErrs := []error{}
|
||||||
upgradeReleases := []*chart.Chart{}
|
upgradeReleases := []*chart.Chart{}
|
||||||
invalidUpgrade := &compatibility.InvalidUpgradeError{}
|
invalidUpgrade := &compatibility.InvalidUpgradeError{}
|
||||||
@ -138,11 +138,11 @@ func (c *Client) Upgrade(ctx context.Context, config *config.Config, timeout tim
|
|||||||
return errors.Join(upgradeErrs...)
|
return errors.Join(upgradeErrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
crds, err := c.backupCRDs(ctx)
|
crds, err := c.backupCRDs(ctx, upgradeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("creating CRD backup: %w", err)
|
return fmt.Errorf("creating CRD backup: %w", err)
|
||||||
}
|
}
|
||||||
if err := c.backupCRs(ctx, crds); err != nil {
|
if err := c.backupCRs(ctx, crds, upgradeID); err != nil {
|
||||||
return fmt.Errorf("creating CR backup: %w", err)
|
return fmt.Errorf("creating CR backup: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ go_library(
|
|||||||
"//internal/versions",
|
"//internal/versions",
|
||||||
"//internal/versions/components",
|
"//internal/versions/components",
|
||||||
"//operators/constellation-node-operator/api/v1alpha1",
|
"//operators/constellation-node-operator/api/v1alpha1",
|
||||||
|
"@com_github_google_uuid//:uuid",
|
||||||
"@io_k8s_api//core/v1:core",
|
"@io_k8s_api//core/v1:core",
|
||||||
"@io_k8s_apimachinery//pkg/api/errors",
|
"@io_k8s_apimachinery//pkg/api/errors",
|
||||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:meta",
|
"@io_k8s_apimachinery//pkg/apis/meta/v1:meta",
|
||||||
|
@ -33,6 +33,7 @@ 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"
|
||||||
|
"github.com/google/uuid"
|
||||||
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"
|
||||||
@ -44,6 +45,16 @@ import (
|
|||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UpgradeCmdKind is the kind of the upgrade command (check, apply).
|
||||||
|
type UpgradeCmdKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UpgradeCmdKindCheck corresponds to the upgrade check command.
|
||||||
|
UpgradeCmdKindCheck UpgradeCmdKind = iota
|
||||||
|
// UpgradeCmdKindApply corresponds to the upgrade apply command.
|
||||||
|
UpgradeCmdKindApply
|
||||||
|
)
|
||||||
|
|
||||||
// ErrInProgress signals that an upgrade is in progress inside the cluster.
|
// ErrInProgress signals that an upgrade is in progress inside the cluster.
|
||||||
var ErrInProgress = errors.New("upgrade in progress")
|
var ErrInProgress = errors.New("upgrade in progress")
|
||||||
|
|
||||||
@ -85,10 +96,26 @@ type Upgrader struct {
|
|||||||
outWriter io.Writer
|
outWriter io.Writer
|
||||||
tfUpgrader *upgrade.TerraformUpgrader
|
tfUpgrader *upgrade.TerraformUpgrader
|
||||||
log debugLog
|
log debugLog
|
||||||
|
upgradeID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUpgrader returns a new Upgrader.
|
// NewUpgrader returns a new Upgrader.
|
||||||
func NewUpgrader(ctx context.Context, outWriter io.Writer, log debugLog) (*Upgrader, error) {
|
func NewUpgrader(ctx context.Context, outWriter io.Writer, log debugLog, upgradeCmdKind UpgradeCmdKind) (*Upgrader, error) {
|
||||||
|
upgradeID := "upgrade-" + time.Now().Format("20060102150405") + "-" + strings.Split(uuid.New().String(), "-")[0]
|
||||||
|
if upgradeCmdKind == UpgradeCmdKindCheck {
|
||||||
|
// When performing an upgrade check, the upgrade directory will only be used temporarily to store the
|
||||||
|
// Terraform state. The directory is deleted after the check is finished.
|
||||||
|
// Therefore, add a tmp-suffix to the upgrade ID to indicate that the directory will be cleared after the check.
|
||||||
|
upgradeID += "-tmp"
|
||||||
|
}
|
||||||
|
|
||||||
|
u := &Upgrader{
|
||||||
|
imageFetcher: imagefetcher.New(),
|
||||||
|
outWriter: outWriter,
|
||||||
|
log: log,
|
||||||
|
upgradeID: upgradeID,
|
||||||
|
}
|
||||||
|
|
||||||
kubeConfig, err := clientcmd.BuildConfigFromFlags("", constants.AdminConfFilename)
|
kubeConfig, err := clientcmd.BuildConfigFromFlags("", constants.AdminConfFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("building kubernetes config: %w", err)
|
return nil, fmt.Errorf("building kubernetes config: %w", err)
|
||||||
@ -98,19 +125,22 @@ func NewUpgrader(ctx context.Context, outWriter io.Writer, log debugLog) (*Upgra
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("setting up kubernetes client: %w", err)
|
return nil, fmt.Errorf("setting up kubernetes client: %w", err)
|
||||||
}
|
}
|
||||||
|
u.stableInterface = &stableClient{client: kubeClient}
|
||||||
|
|
||||||
// use unstructured client to avoid importing the operator packages
|
// use unstructured client to avoid importing the operator packages
|
||||||
unstructuredClient, err := dynamic.NewForConfig(kubeConfig)
|
unstructuredClient, err := dynamic.NewForConfig(kubeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("setting up custom resource client: %w", err)
|
return nil, fmt.Errorf("setting up custom resource client: %w", err)
|
||||||
}
|
}
|
||||||
|
u.dynamicInterface = &NodeVersionClient{client: unstructuredClient}
|
||||||
|
|
||||||
helmClient, err := helm.NewClient(kubectl.New(), constants.AdminConfFilename, constants.HelmNamespace, log)
|
helmClient, err := helm.NewClient(kubectl.New(), constants.AdminConfFilename, constants.HelmNamespace, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("setting up helm client: %w", err)
|
return nil, fmt.Errorf("setting up helm client: %w", err)
|
||||||
}
|
}
|
||||||
|
u.helmClient = helmClient
|
||||||
|
|
||||||
tfClient, err := terraform.New(ctx, filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeWorkingDir))
|
tfClient, err := terraform.New(ctx, filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("setting up terraform client: %w", err)
|
return nil, fmt.Errorf("setting up terraform client: %w", err)
|
||||||
}
|
}
|
||||||
@ -119,35 +149,28 @@ func NewUpgrader(ctx context.Context, outWriter io.Writer, log debugLog) (*Upgra
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("setting up terraform upgrader: %w", err)
|
return nil, fmt.Errorf("setting up terraform upgrader: %w", err)
|
||||||
}
|
}
|
||||||
|
u.tfUpgrader = tfUpgrader
|
||||||
|
|
||||||
return &Upgrader{
|
return u, nil
|
||||||
stableInterface: &stableClient{client: kubeClient},
|
|
||||||
dynamicInterface: &NodeVersionClient{client: unstructuredClient},
|
|
||||||
helmClient: helmClient,
|
|
||||||
imageFetcher: imagefetcher.New(),
|
|
||||||
outWriter: outWriter,
|
|
||||||
tfUpgrader: tfUpgrader,
|
|
||||||
log: log,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTerraformMigrations checks whether Terraform migrations are possible in the current workspace.
|
// CheckTerraformMigrations checks whether Terraform migrations are possible in the current workspace.
|
||||||
// If the files that will be written during the upgrade already exist, it returns an error.
|
// If the files that will be written during the upgrade already exist, it returns an error.
|
||||||
func (u *Upgrader) CheckTerraformMigrations(fileHandler file.Handler) error {
|
func (u *Upgrader) CheckTerraformMigrations(fileHandler file.Handler) error {
|
||||||
return u.tfUpgrader.CheckTerraformMigrations(fileHandler)
|
return u.tfUpgrader.CheckTerraformMigrations(fileHandler, u.upgradeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CleanUpTerraformMigrations cleans up the Terraform migration workspace, for example when an upgrade is
|
// CleanUpTerraformMigrations cleans up the Terraform migration workspace, for example when an upgrade is
|
||||||
// aborted by the user.
|
// aborted by the user.
|
||||||
func (u *Upgrader) CleanUpTerraformMigrations(fileHandler file.Handler) error {
|
func (u *Upgrader) CleanUpTerraformMigrations(fileHandler file.Handler) error {
|
||||||
return u.tfUpgrader.CleanUpTerraformMigrations(fileHandler)
|
return u.tfUpgrader.CleanUpTerraformMigrations(fileHandler, u.upgradeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlanTerraformMigrations prepares the upgrade workspace and plans the Terraform migrations for the Constellation upgrade.
|
// PlanTerraformMigrations prepares the upgrade workspace and plans the Terraform migrations for the Constellation upgrade.
|
||||||
// If a diff exists, it's being written to the upgrader's output writer. It also returns
|
// If a diff exists, it's being written to the upgrader's output writer. It also returns
|
||||||
// a bool indicating whether a diff exists.
|
// a bool indicating whether a diff exists.
|
||||||
func (u *Upgrader) PlanTerraformMigrations(ctx context.Context, opts upgrade.TerraformUpgradeOptions) (bool, error) {
|
func (u *Upgrader) PlanTerraformMigrations(ctx context.Context, opts upgrade.TerraformUpgradeOptions) (bool, error) {
|
||||||
return u.tfUpgrader.PlanTerraformMigrations(ctx, opts)
|
return u.tfUpgrader.PlanTerraformMigrations(ctx, opts, u.upgradeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyTerraformMigrations applies the migerations planned by PlanTerraformMigrations.
|
// ApplyTerraformMigrations applies the migerations planned by PlanTerraformMigrations.
|
||||||
@ -155,12 +178,12 @@ func (u *Upgrader) PlanTerraformMigrations(ctx context.Context, opts upgrade.Ter
|
|||||||
// In case of a successful upgrade, the output will be written to the specified file and the old Terraform directory is replaced
|
// In case of a successful upgrade, the output will be written to the specified file and the old Terraform directory is replaced
|
||||||
// By the new one.
|
// By the new one.
|
||||||
func (u *Upgrader) ApplyTerraformMigrations(ctx context.Context, fileHandler file.Handler, opts upgrade.TerraformUpgradeOptions) error {
|
func (u *Upgrader) ApplyTerraformMigrations(ctx context.Context, fileHandler file.Handler, opts upgrade.TerraformUpgradeOptions) error {
|
||||||
return u.tfUpgrader.ApplyTerraformMigrations(ctx, fileHandler, opts)
|
return u.tfUpgrader.ApplyTerraformMigrations(ctx, fileHandler, opts, u.upgradeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpgradeHelmServices upgrade helm services.
|
// UpgradeHelmServices upgrade helm services.
|
||||||
func (u *Upgrader) UpgradeHelmServices(ctx context.Context, config *config.Config, timeout time.Duration, allowDestructive bool) error {
|
func (u *Upgrader) UpgradeHelmServices(ctx context.Context, config *config.Config, timeout time.Duration, allowDestructive bool) error {
|
||||||
return u.helmClient.Upgrade(ctx, config, timeout, allowDestructive)
|
return u.helmClient.Upgrade(ctx, config, timeout, allowDestructive, u.upgradeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpgradeNodeVersion upgrades the cluster's NodeVersion object and in turn triggers image & k8s version upgrades.
|
// UpgradeNodeVersion upgrades the cluster's NodeVersion object and in turn triggers image & k8s version upgrades.
|
||||||
@ -526,7 +549,7 @@ func joinConfigMigration(existingConf *corev1.ConfigMap, attestVariant variant.V
|
|||||||
}
|
}
|
||||||
|
|
||||||
type helmInterface interface {
|
type helmInterface interface {
|
||||||
Upgrade(ctx context.Context, config *config.Config, timeout time.Duration, allowDestructive bool) error
|
Upgrade(ctx context.Context, config *config.Config, timeout time.Duration, allowDestructive bool, upgradeID string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type debugLog interface {
|
type debugLog interface {
|
||||||
|
@ -16,7 +16,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
@ -36,11 +35,11 @@ func prepareWorkspace(rootDir string, fileHandler file.Handler, workingDir strin
|
|||||||
|
|
||||||
// prepareUpgradeWorkspace takes the Terraform state file from the old workspace and the
|
// prepareUpgradeWorkspace takes the Terraform state file from the old workspace and the
|
||||||
// embedded Terraform files and writes them into the new workspace.
|
// embedded Terraform files and writes them into the new workspace.
|
||||||
func prepareUpgradeWorkspace(rootDir string, fileHandler file.Handler, oldWorkingDir, newWorkingDir string) error {
|
func prepareUpgradeWorkspace(rootDir string, fileHandler file.Handler, oldWorkingDir, newWorkingDir, backupDir string) error {
|
||||||
// backup old workspace
|
// backup old workspace
|
||||||
if err := fileHandler.CopyDir(
|
if err := fileHandler.CopyDir(
|
||||||
oldWorkingDir,
|
oldWorkingDir,
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeBackupDir),
|
backupDir,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return fmt.Errorf("backing up old workspace: %w", err)
|
return fmt.Errorf("backing up old workspace: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -133,6 +133,7 @@ func TestPrepareUpgradeWorkspace(t *testing.T) {
|
|||||||
provider cloudprovider.Provider
|
provider cloudprovider.Provider
|
||||||
oldWorkingDir string
|
oldWorkingDir string
|
||||||
newWorkingDir string
|
newWorkingDir string
|
||||||
|
backupDir string
|
||||||
oldWorkspaceFiles []string
|
oldWorkspaceFiles []string
|
||||||
newWorkspaceFiles []string
|
newWorkspaceFiles []string
|
||||||
expectedFiles []string
|
expectedFiles []string
|
||||||
@ -144,6 +145,7 @@ func TestPrepareUpgradeWorkspace(t *testing.T) {
|
|||||||
provider: cloudprovider.AWS,
|
provider: cloudprovider.AWS,
|
||||||
oldWorkingDir: "old",
|
oldWorkingDir: "old",
|
||||||
newWorkingDir: "new",
|
newWorkingDir: "new",
|
||||||
|
backupDir: "backup",
|
||||||
oldWorkspaceFiles: []string{"terraform.tfstate"},
|
oldWorkspaceFiles: []string{"terraform.tfstate"},
|
||||||
expectedFiles: []string{
|
expectedFiles: []string{
|
||||||
"main.tf",
|
"main.tf",
|
||||||
@ -158,6 +160,7 @@ func TestPrepareUpgradeWorkspace(t *testing.T) {
|
|||||||
provider: cloudprovider.AWS,
|
provider: cloudprovider.AWS,
|
||||||
oldWorkingDir: "old",
|
oldWorkingDir: "old",
|
||||||
newWorkingDir: "new",
|
newWorkingDir: "new",
|
||||||
|
backupDir: "backup",
|
||||||
oldWorkspaceFiles: []string{},
|
oldWorkspaceFiles: []string{},
|
||||||
expectedFiles: []string{},
|
expectedFiles: []string{},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
@ -167,6 +170,7 @@ func TestPrepareUpgradeWorkspace(t *testing.T) {
|
|||||||
provider: cloudprovider.AWS,
|
provider: cloudprovider.AWS,
|
||||||
oldWorkingDir: "old",
|
oldWorkingDir: "old",
|
||||||
newWorkingDir: "new",
|
newWorkingDir: "new",
|
||||||
|
backupDir: "backup",
|
||||||
oldWorkspaceFiles: []string{"terraform.tfstate"},
|
oldWorkspaceFiles: []string{"terraform.tfstate"},
|
||||||
newWorkspaceFiles: []string{"main.tf"},
|
newWorkspaceFiles: []string{"main.tf"},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
@ -185,7 +189,7 @@ func TestPrepareUpgradeWorkspace(t *testing.T) {
|
|||||||
createFiles(t, file, tc.oldWorkspaceFiles, tc.oldWorkingDir)
|
createFiles(t, file, tc.oldWorkspaceFiles, tc.oldWorkingDir)
|
||||||
createFiles(t, file, tc.newWorkspaceFiles, tc.newWorkingDir)
|
createFiles(t, file, tc.newWorkspaceFiles, tc.newWorkingDir)
|
||||||
|
|
||||||
err := prepareUpgradeWorkspace(path, file, tc.oldWorkingDir, tc.newWorkingDir)
|
err := prepareUpgradeWorkspace(path, file, tc.oldWorkingDir, tc.newWorkingDir, tc.backupDir)
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
require.Error(err)
|
require.Error(err)
|
||||||
@ -194,7 +198,7 @@ func TestPrepareUpgradeWorkspace(t *testing.T) {
|
|||||||
}
|
}
|
||||||
checkFiles(t, file, func(err error) { assert.NoError(err) }, tc.newWorkingDir, tc.expectedFiles)
|
checkFiles(t, file, func(err error) { assert.NoError(err) }, tc.newWorkingDir, tc.expectedFiles)
|
||||||
checkFiles(t, file, func(err error) { assert.NoError(err) },
|
checkFiles(t, file, func(err error) { assert.NoError(err) },
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeBackupDir),
|
tc.backupDir,
|
||||||
tc.oldWorkspaceFiles,
|
tc.oldWorkspaceFiles,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -87,8 +87,8 @@ func (c *Client) PrepareWorkspace(path string, vars Variables) error {
|
|||||||
|
|
||||||
// PrepareUpgradeWorkspace prepares a Terraform workspace for a Constellation version upgrade.
|
// PrepareUpgradeWorkspace prepares a Terraform workspace for a Constellation version upgrade.
|
||||||
// It copies the Terraform state from the old working dir and the embedded Terraform files into the new working dir.
|
// It copies the Terraform state from the old working dir and the embedded Terraform files into the new working dir.
|
||||||
func (c *Client) PrepareUpgradeWorkspace(path, oldWorkingDir, newWorkingDir string, vars Variables) error {
|
func (c *Client) PrepareUpgradeWorkspace(path, oldWorkingDir, newWorkingDir, backupDir string, vars Variables) error {
|
||||||
if err := prepareUpgradeWorkspace(path, c.file, oldWorkingDir, newWorkingDir); err != nil {
|
if err := prepareUpgradeWorkspace(path, c.file, oldWorkingDir, newWorkingDir, backupDir); err != nil {
|
||||||
return fmt.Errorf("prepare upgrade workspace: %w", err)
|
return fmt.Errorf("prepare upgrade workspace: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,11 +54,11 @@ type TerraformUpgradeOptions struct {
|
|||||||
|
|
||||||
// CheckTerraformMigrations checks whether Terraform migrations are possible in the current workspace.
|
// CheckTerraformMigrations checks whether Terraform migrations are possible in the current workspace.
|
||||||
// If the files that will be written during the upgrade already exist, it returns an error.
|
// If the files that will be written during the upgrade already exist, it returns an error.
|
||||||
func (u *TerraformUpgrader) CheckTerraformMigrations(fileHandler file.Handler) error {
|
func (u *TerraformUpgrader) CheckTerraformMigrations(fileHandler file.Handler, upgradeID string) error {
|
||||||
var existingFiles []string
|
var existingFiles []string
|
||||||
filesToCheck := []string{
|
filesToCheck := []string{
|
||||||
constants.TerraformMigrationOutputFile,
|
constants.TerraformMigrationOutputFile,
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeBackupDir),
|
filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeBackupDir),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range filesToCheck {
|
for _, f := range filesToCheck {
|
||||||
@ -90,11 +90,12 @@ func checkFileExists(fileHandler file.Handler, existingFiles *[]string, filename
|
|||||||
// PlanTerraformMigrations prepares the upgrade workspace and plans the Terraform migrations for the Constellation upgrade.
|
// PlanTerraformMigrations prepares the upgrade workspace and plans the Terraform migrations for the Constellation upgrade.
|
||||||
// If a diff exists, it's being written to the upgrader's output writer. It also returns
|
// If a diff exists, it's being written to the upgrader's output writer. It also returns
|
||||||
// a bool indicating whether a diff exists.
|
// a bool indicating whether a diff exists.
|
||||||
func (u *TerraformUpgrader) PlanTerraformMigrations(ctx context.Context, opts TerraformUpgradeOptions) (bool, error) {
|
func (u *TerraformUpgrader) PlanTerraformMigrations(ctx context.Context, opts TerraformUpgradeOptions, upgradeID string) (bool, error) {
|
||||||
err := u.tf.PrepareUpgradeWorkspace(
|
err := u.tf.PrepareUpgradeWorkspace(
|
||||||
filepath.Join("terraform", strings.ToLower(opts.CSP.String())),
|
filepath.Join("terraform", strings.ToLower(opts.CSP.String())),
|
||||||
constants.TerraformWorkingDir,
|
constants.TerraformWorkingDir,
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeWorkingDir),
|
filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir),
|
||||||
|
filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeBackupDir),
|
||||||
opts.Vars,
|
opts.Vars,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -117,10 +118,9 @@ func (u *TerraformUpgrader) PlanTerraformMigrations(ctx context.Context, opts Te
|
|||||||
|
|
||||||
// CleanUpTerraformMigrations cleans up the Terraform migration workspace, for example when an upgrade is
|
// CleanUpTerraformMigrations cleans up the Terraform migration workspace, for example when an upgrade is
|
||||||
// aborted by the user.
|
// aborted by the user.
|
||||||
func (u *TerraformUpgrader) CleanUpTerraformMigrations(fileHandler file.Handler) error {
|
func (u *TerraformUpgrader) CleanUpTerraformMigrations(fileHandler file.Handler, upgradeID string) error {
|
||||||
cleanupFiles := []string{
|
cleanupFiles := []string{
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeBackupDir),
|
filepath.Join(constants.UpgradeDir, upgradeID),
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeWorkingDir),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range cleanupFiles {
|
for _, f := range cleanupFiles {
|
||||||
@ -136,7 +136,7 @@ func (u *TerraformUpgrader) CleanUpTerraformMigrations(fileHandler file.Handler)
|
|||||||
// If PlanTerraformMigrations has not been executed before, it will return an error.
|
// If PlanTerraformMigrations has not been executed before, it will return an error.
|
||||||
// In case of a successful upgrade, the output will be written to the specified file and the old Terraform directory is replaced
|
// In case of a successful upgrade, the output will be written to the specified file and the old Terraform directory is replaced
|
||||||
// By the new one.
|
// By the new one.
|
||||||
func (u *TerraformUpgrader) ApplyTerraformMigrations(ctx context.Context, fileHandler file.Handler, opts TerraformUpgradeOptions) error {
|
func (u *TerraformUpgrader) ApplyTerraformMigrations(ctx context.Context, fileHandler file.Handler, opts TerraformUpgradeOptions, upgradeID string) error {
|
||||||
tfOutput, err := u.tf.CreateCluster(ctx, opts.LogLevel, opts.Targets...)
|
tfOutput, err := u.tf.CreateCluster(ctx, opts.LogLevel, opts.Targets...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("terraform apply: %w", err)
|
return fmt.Errorf("terraform apply: %w", err)
|
||||||
@ -161,11 +161,11 @@ func (u *TerraformUpgrader) ApplyTerraformMigrations(ctx context.Context, fileHa
|
|||||||
return fmt.Errorf("removing old terraform directory: %w", err)
|
return fmt.Errorf("removing old terraform directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := fileHandler.CopyDir(filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeWorkingDir), constants.TerraformWorkingDir); err != nil {
|
if err := fileHandler.CopyDir(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir), constants.TerraformWorkingDir); err != nil {
|
||||||
return fmt.Errorf("replacing old terraform directory with new one: %w", err)
|
return fmt.Errorf("replacing old terraform directory with new one: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := fileHandler.RemoveAll(filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeWorkingDir)); err != nil {
|
if err := fileHandler.RemoveAll(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir)); err != nil {
|
||||||
return fmt.Errorf("removing terraform upgrade directory: %w", err)
|
return fmt.Errorf("removing terraform upgrade directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ func (u *TerraformUpgrader) ApplyTerraformMigrations(ctx context.Context, fileHa
|
|||||||
|
|
||||||
// a tfClient performs the Terraform interactions in an upgrade.
|
// a tfClient performs the Terraform interactions in an upgrade.
|
||||||
type tfClient interface {
|
type tfClient interface {
|
||||||
PrepareUpgradeWorkspace(path, oldWorkingDir, newWorkingDir string, vars terraform.Variables) error
|
PrepareUpgradeWorkspace(path, oldWorkingDir, newWorkingDir, upgradeID string, vars terraform.Variables) error
|
||||||
ShowPlan(ctx context.Context, logLevel terraform.LogLevel, planFilePath string, output io.Writer) error
|
ShowPlan(ctx context.Context, logLevel terraform.LogLevel, planFilePath string, output io.Writer) error
|
||||||
Plan(ctx context.Context, logLevel terraform.LogLevel, planFile string, targets ...string) (bool, error)
|
Plan(ctx context.Context, logLevel terraform.LogLevel, planFile string, targets ...string) (bool, error)
|
||||||
CreateCluster(ctx context.Context, logLevel terraform.LogLevel, targets ...string) (terraform.CreateOutput, error)
|
CreateCluster(ctx context.Context, logLevel terraform.LogLevel, targets ...string) (terraform.CreateOutput, error)
|
||||||
|
@ -40,18 +40,22 @@ func TestCheckTerraformMigrations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
|
upgradeID string
|
||||||
workspace file.Handler
|
workspace file.Handler
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"success": {
|
"success": {
|
||||||
|
upgradeID: "1234",
|
||||||
workspace: workspace(nil),
|
workspace: workspace(nil),
|
||||||
},
|
},
|
||||||
"migration output file already exists": {
|
"migration output file already exists": {
|
||||||
|
upgradeID: "1234",
|
||||||
workspace: workspace([]string{constants.TerraformMigrationOutputFile}),
|
workspace: workspace([]string{constants.TerraformMigrationOutputFile}),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"terraform backup dir already exists": {
|
"terraform backup dir already exists": {
|
||||||
workspace: workspace([]string{filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeBackupDir)}),
|
upgradeID: "1234",
|
||||||
|
workspace: workspace([]string{filepath.Join(constants.UpgradeDir, "1234", constants.TerraformUpgradeBackupDir)}),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -59,7 +63,7 @@ func TestCheckTerraformMigrations(t *testing.T) {
|
|||||||
for name, tc := range testCases {
|
for name, tc := range testCases {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
u := upgrader()
|
u := upgrader()
|
||||||
err := u.CheckTerraformMigrations(tc.workspace)
|
err := u.CheckTerraformMigrations(tc.workspace, tc.upgradeID)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
@ -79,20 +83,24 @@ func TestPlanTerraformMigrations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
tf tfClient
|
upgradeID string
|
||||||
want bool
|
tf tfClient
|
||||||
wantErr bool
|
want bool
|
||||||
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"success no diff": {
|
"success no diff": {
|
||||||
tf: &stubTerraformClient{},
|
upgradeID: "1234",
|
||||||
|
tf: &stubTerraformClient{},
|
||||||
},
|
},
|
||||||
"success diff": {
|
"success diff": {
|
||||||
|
upgradeID: "1234",
|
||||||
tf: &stubTerraformClient{
|
tf: &stubTerraformClient{
|
||||||
hasDiff: true,
|
hasDiff: true,
|
||||||
},
|
},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
"prepare workspace error": {
|
"prepare workspace error": {
|
||||||
|
upgradeID: "1234",
|
||||||
tf: &stubTerraformClient{
|
tf: &stubTerraformClient{
|
||||||
prepareWorkspaceErr: assert.AnError,
|
prepareWorkspaceErr: assert.AnError,
|
||||||
},
|
},
|
||||||
@ -105,11 +113,13 @@ func TestPlanTerraformMigrations(t *testing.T) {
|
|||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"show plan error no diff": {
|
"show plan error no diff": {
|
||||||
|
upgradeID: "1234",
|
||||||
tf: &stubTerraformClient{
|
tf: &stubTerraformClient{
|
||||||
showErr: assert.AnError,
|
showErr: assert.AnError,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"show plan error diff": {
|
"show plan error diff": {
|
||||||
|
upgradeID: "1234",
|
||||||
tf: &stubTerraformClient{
|
tf: &stubTerraformClient{
|
||||||
showErr: assert.AnError,
|
showErr: assert.AnError,
|
||||||
hasDiff: true,
|
hasDiff: true,
|
||||||
@ -130,7 +140,7 @@ func TestPlanTerraformMigrations(t *testing.T) {
|
|||||||
Vars: &terraform.QEMUVariables{},
|
Vars: &terraform.QEMUVariables{},
|
||||||
}
|
}
|
||||||
|
|
||||||
diff, err := u.PlanTerraformMigrations(context.Background(), opts)
|
diff, err := u.PlanTerraformMigrations(context.Background(), opts, tc.upgradeID)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
require.Error(err)
|
require.Error(err)
|
||||||
} else {
|
} else {
|
||||||
@ -149,11 +159,11 @@ func TestApplyTerraformMigrations(t *testing.T) {
|
|||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
fileHandler := func(existingFiles ...string) file.Handler {
|
fileHandler := func(upgradeID string, existingFiles ...string) file.Handler {
|
||||||
fh := file.NewHandler(afero.NewMemMapFs())
|
fh := file.NewHandler(afero.NewMemMapFs())
|
||||||
require.NoError(t,
|
require.NoError(t,
|
||||||
fh.Write(
|
fh.Write(
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeWorkingDir, "someFile"),
|
filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir, "someFile"),
|
||||||
[]byte("some content"),
|
[]byte("some content"),
|
||||||
))
|
))
|
||||||
for _, f := range existingFiles {
|
for _, f := range existingFiles {
|
||||||
@ -163,6 +173,7 @@ func TestApplyTerraformMigrations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
|
upgradeID string
|
||||||
tf tfClient
|
tf tfClient
|
||||||
policyPatcher stubPolicyPatcher
|
policyPatcher stubPolicyPatcher
|
||||||
fs file.Handler
|
fs file.Handler
|
||||||
@ -170,38 +181,43 @@ func TestApplyTerraformMigrations(t *testing.T) {
|
|||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"success": {
|
"success": {
|
||||||
|
upgradeID: "1234",
|
||||||
tf: &stubTerraformClient{},
|
tf: &stubTerraformClient{},
|
||||||
fs: fileHandler(),
|
fs: fileHandler("1234"),
|
||||||
policyPatcher: stubPolicyPatcher{},
|
policyPatcher: stubPolicyPatcher{},
|
||||||
outputFileName: "test.json",
|
outputFileName: "test.json",
|
||||||
},
|
},
|
||||||
"create cluster error": {
|
"create cluster error": {
|
||||||
|
upgradeID: "1234",
|
||||||
tf: &stubTerraformClient{
|
tf: &stubTerraformClient{
|
||||||
CreateClusterErr: assert.AnError,
|
CreateClusterErr: assert.AnError,
|
||||||
},
|
},
|
||||||
fs: fileHandler(),
|
fs: fileHandler("1234"),
|
||||||
policyPatcher: stubPolicyPatcher{},
|
policyPatcher: stubPolicyPatcher{},
|
||||||
outputFileName: "test.json",
|
outputFileName: "test.json",
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"patch error": {
|
"patch error": {
|
||||||
tf: &stubTerraformClient{},
|
upgradeID: "1234",
|
||||||
fs: fileHandler(),
|
tf: &stubTerraformClient{},
|
||||||
|
fs: fileHandler("1234"),
|
||||||
policyPatcher: stubPolicyPatcher{
|
policyPatcher: stubPolicyPatcher{
|
||||||
patchErr: assert.AnError,
|
patchErr: assert.AnError,
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"empty file name": {
|
"empty file name": {
|
||||||
|
upgradeID: "1234",
|
||||||
tf: &stubTerraformClient{},
|
tf: &stubTerraformClient{},
|
||||||
fs: fileHandler(),
|
fs: fileHandler("1234"),
|
||||||
policyPatcher: stubPolicyPatcher{},
|
policyPatcher: stubPolicyPatcher{},
|
||||||
outputFileName: "",
|
outputFileName: "",
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"file already exists": {
|
"file already exists": {
|
||||||
|
upgradeID: "1234",
|
||||||
tf: &stubTerraformClient{},
|
tf: &stubTerraformClient{},
|
||||||
fs: fileHandler("test.json"),
|
fs: fileHandler("1234", "test.json"),
|
||||||
policyPatcher: stubPolicyPatcher{},
|
policyPatcher: stubPolicyPatcher{},
|
||||||
outputFileName: "test.json",
|
outputFileName: "test.json",
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
@ -221,7 +237,7 @@ func TestApplyTerraformMigrations(t *testing.T) {
|
|||||||
OutputFile: tc.outputFileName,
|
OutputFile: tc.outputFileName,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := u.ApplyTerraformMigrations(context.Background(), tc.fs, opts)
|
err := u.ApplyTerraformMigrations(context.Background(), tc.fs, opts, tc.upgradeID)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
require.Error(err)
|
require.Error(err)
|
||||||
} else {
|
} else {
|
||||||
@ -249,33 +265,47 @@ func TestCleanUpTerraformMigrations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
workspace file.Handler
|
upgradeID string
|
||||||
wantFiles []string
|
workspaceFiles []string
|
||||||
wantErr bool
|
wantFiles []string
|
||||||
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"no files": {
|
"no files": {
|
||||||
workspace: workspace(nil),
|
upgradeID: "1234",
|
||||||
wantFiles: []string{},
|
workspaceFiles: nil,
|
||||||
|
wantFiles: []string{},
|
||||||
},
|
},
|
||||||
"clean backup dir": {
|
"clean backup dir": {
|
||||||
workspace: workspace([]string{
|
upgradeID: "1234",
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeBackupDir),
|
workspaceFiles: []string{
|
||||||
}),
|
filepath.Join(constants.UpgradeDir, "1234", constants.TerraformUpgradeBackupDir),
|
||||||
|
},
|
||||||
wantFiles: []string{},
|
wantFiles: []string{},
|
||||||
},
|
},
|
||||||
"clean working dir": {
|
"clean working dir": {
|
||||||
workspace: workspace([]string{
|
upgradeID: "1234",
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeWorkingDir),
|
workspaceFiles: []string{
|
||||||
}),
|
filepath.Join(constants.UpgradeDir, "1234", constants.TerraformUpgradeWorkingDir),
|
||||||
|
},
|
||||||
wantFiles: []string{},
|
wantFiles: []string{},
|
||||||
},
|
},
|
||||||
"clean backup dir leave other files": {
|
"clean all": {
|
||||||
workspace: workspace([]string{
|
upgradeID: "1234",
|
||||||
filepath.Join(constants.UpgradeDir, constants.TerraformUpgradeBackupDir),
|
workspaceFiles: []string{
|
||||||
filepath.Join(constants.UpgradeDir, "someFile"),
|
filepath.Join(constants.UpgradeDir, "1234", constants.TerraformUpgradeBackupDir),
|
||||||
}),
|
filepath.Join(constants.UpgradeDir, "1234", constants.TerraformUpgradeWorkingDir),
|
||||||
|
filepath.Join(constants.UpgradeDir, "1234", "abc"),
|
||||||
|
},
|
||||||
|
wantFiles: []string{},
|
||||||
|
},
|
||||||
|
"leave other files": {
|
||||||
|
upgradeID: "1234",
|
||||||
|
workspaceFiles: []string{
|
||||||
|
filepath.Join(constants.UpgradeDir, "1234", constants.TerraformUpgradeBackupDir),
|
||||||
|
filepath.Join(constants.UpgradeDir, "other"),
|
||||||
|
},
|
||||||
wantFiles: []string{
|
wantFiles: []string{
|
||||||
filepath.Join(constants.UpgradeDir, "someFile"),
|
filepath.Join(constants.UpgradeDir, "other"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -284,8 +314,10 @@ func TestCleanUpTerraformMigrations(t *testing.T) {
|
|||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
|
workspace := workspace(tc.workspaceFiles)
|
||||||
u := upgrader()
|
u := upgrader()
|
||||||
err := u.CleanUpTerraformMigrations(tc.workspace)
|
|
||||||
|
err := u.CleanUpTerraformMigrations(workspace, tc.upgradeID)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
require.Error(err)
|
require.Error(err)
|
||||||
return
|
return
|
||||||
@ -293,9 +325,16 @@ func TestCleanUpTerraformMigrations(t *testing.T) {
|
|||||||
|
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
for _, f := range tc.wantFiles {
|
for _, haveFile := range tc.workspaceFiles {
|
||||||
_, err := tc.workspace.Stat(f)
|
for _, wantFile := range tc.wantFiles {
|
||||||
require.NoError(err, "file %s should exist", f)
|
if haveFile == wantFile {
|
||||||
|
_, err := workspace.Stat(wantFile)
|
||||||
|
require.NoError(err, "file %s should exist", wantFile)
|
||||||
|
} else {
|
||||||
|
_, err := workspace.Stat(haveFile)
|
||||||
|
require.Error(err, "file %s should not exist", haveFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -309,7 +348,7 @@ type stubTerraformClient struct {
|
|||||||
CreateClusterErr error
|
CreateClusterErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *stubTerraformClient) PrepareUpgradeWorkspace(string, string, string, terraform.Variables) error {
|
func (u *stubTerraformClient) PrepareUpgradeWorkspace(string, string, string, string, terraform.Variables) error {
|
||||||
return u.prepareWorkspaceErr
|
return u.prepareWorkspaceErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user