diff --git a/cli/app/deploy.go b/cli/app/deploy.go index f398ee74..00e0dd43 100644 --- a/cli/app/deploy.go +++ b/cli/app/deploy.go @@ -37,10 +37,16 @@ var appDeployCommand = cli.Command{ Before: internal.SubCommandBefore, Description: `Deploy an app. -Use "--force" to re-deploy the same version again. +This command supports chaos operations. Use "--chaos" to deploy your recipe +checkout as-is. Recipe commit hashes are also supported values for +"[]". Please note, "upgrade"/"rollback" do not support chaos +operations. -Use "--chaos" to deploy your local checkout of a recipe as-is, including -unstaged changes.`, +EXAMPLE: + + abra app deploy foo.example.com + abra app deploy foo.example.com 1.2.3+3.2.1 + abra app deploy foo.example.com 1e83340e`, BashComplete: autocomplete.AppNameComplete, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) @@ -71,6 +77,9 @@ unstaged changes.`, log.Fatal(err) } + // NOTE(d1): handles " as git hash" use case + var isChaosCommit bool + // NOTE(d1): check out specific version before dealing with secrets. This // is because we need to deal with GetComposeFiles under the hood and these // files change from version to version which therefore affects which @@ -79,9 +88,17 @@ unstaged changes.`, if specificVersion != "" { version = specificVersion log.Debugf("choosing %s as version to deploy", version) - if err := app.Recipe.EnsureVersion(version); err != nil { + + var err error + isChaosCommit, err = app.Recipe.EnsureVersion(version) + if err != nil { log.Fatal(err) } + + if isChaosCommit { + log.Debugf("assuming '%s' is a chaos commit", version) + internal.Chaos = true + } } secStats, err := secret.PollSecretsStatus(cl, app) @@ -129,7 +146,7 @@ unstaged changes.`, if len(versions) > 0 && !internal.Chaos { version = versions[len(versions)-1] log.Debugf("choosing %s as version to deploy", version) - if err := app.Recipe.EnsureVersion(version); err != nil { + if _, err := app.Recipe.EnsureVersion(version); err != nil { log.Fatal(err) } } else { @@ -145,10 +162,20 @@ unstaged changes.`, chaosVersion := "false" if internal.Chaos { log.Warnf("chaos mode engaged") - var err error - chaosVersion, err = app.Recipe.ChaosVersion() - if err != nil { - log.Fatal(err) + + if isChaosCommit { + chaosVersion = specificVersion + versionLabelLocal, err := app.Recipe.GetVersionLabelLocal() + if err != nil { + log.Fatal(err) + } + version = versionLabelLocal + } else { + var err error + chaosVersion, err = app.Recipe.ChaosVersion() + if err != nil { + log.Fatal(err) + } } } diff --git a/cli/app/new.go b/cli/app/new.go index 4d21d158..2ef010bc 100644 --- a/cli/app/new.go +++ b/cli/app/new.go @@ -91,7 +91,7 @@ var appNewCommand = cli.Command{ version = tag } - if err := recipe.EnsureVersion(version); err != nil { + if _, err := recipe.EnsureVersion(version); err != nil { log.Fatal(err) } } else { @@ -100,7 +100,7 @@ var appNewCommand = cli.Command{ } } } else { - if err := recipe.EnsureVersion(c.Args().Get(1)); err != nil { + if _, err := recipe.EnsureVersion(c.Args().Get(1)); err != nil { log.Fatal(err) } } diff --git a/cli/app/ps.go b/cli/app/ps.go index 0af9b69c..537c4018 100644 --- a/cli/app/ps.go +++ b/cli/app/ps.go @@ -55,7 +55,7 @@ var appPsCommand = cli.Command{ if statusMeta, ok := statuses[app.StackName()]; ok { isChaos, exists := statusMeta["chaos"] if exists && isChaos == "false" { - if err := app.Recipe.EnsureVersion(deployMeta.Version); err != nil { + if _, err := app.Recipe.EnsureVersion(deployMeta.Version); err != nil { log.Fatal(err) } } else { diff --git a/cli/app/rollback.go b/cli/app/rollback.go index af1cdf78..4e7558e7 100644 --- a/cli/app/rollback.go +++ b/cli/app/rollback.go @@ -36,11 +36,16 @@ var appRollbackCommand = cli.Command{ Description: ` This command rolls an app back to a previous version. -You may pass "--force/-f" to downgrade to the same version again. This can be -useful if the container runtime has gotten into a weird state. +Unlike "deploy", chaos operations are not supported here. Only recipe versions +are supported values for "[]". -This action could be destructive, please ensure you have a copy of your app -data beforehand.`, +A rollback can be destructive, please ensure you have a copy of your app data +beforehand. + +EXAMPLE: + + abra app rollback foo.example.com + abra app rollback foo.example.com 1.2.3+3.2.1`, BashComplete: autocomplete.AppNameComplete, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) @@ -169,7 +174,7 @@ data beforehand.`, } log.Debugf("choosing %s as version to rollback", chosenDowngrade) - if err := app.Recipe.EnsureVersion(chosenDowngrade); err != nil { + if _, err := app.Recipe.EnsureVersion(chosenDowngrade); err != nil { log.Fatal(err) } diff --git a/cli/app/upgrade.go b/cli/app/upgrade.go index 3a33d72f..ee9c679c 100644 --- a/cli/app/upgrade.go +++ b/cli/app/upgrade.go @@ -36,8 +36,16 @@ var appUpgradeCommand = cli.Command{ Description: ` Upgrade an app. -This action could be destructive, please ensure you have a copy of your app -data beforehand.`, +Unlike "deploy", chaos operations are not supported here. Only recipe versions +are supported values for "[]". + +An upgrade can be destructive, please ensure you have a copy of your app data +beforehand. + +EXAMPLE: + + abra app upgrade foo.example.com + abra app upgrade foo.example.com 1.2.3+3.2.1`, BashComplete: autocomplete.AppNameComplete, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) @@ -192,7 +200,7 @@ data beforehand.`, } log.Debugf("choosing %s as version to upgrade", chosenUpgrade) - if err := app.Recipe.EnsureVersion(chosenUpgrade); err != nil { + if _, err := app.Recipe.EnsureVersion(chosenUpgrade); err != nil { log.Fatal(err) } diff --git a/cli/updater/updater.go b/cli/updater/updater.go index a3b763cd..fd2d321e 100644 --- a/cli/updater/updater.go +++ b/cli/updater/updater.go @@ -332,7 +332,7 @@ func processRecipeRepoVersion(r recipe.Recipe, version string) error { return err } - if err := r.EnsureVersion(version); err != nil { + if _, err := r.EnsureVersion(version); err != nil { return err } diff --git a/pkg/recipe/git.go b/pkg/recipe/git.go index 0d6ddc63..95cb87c9 100644 --- a/pkg/recipe/git.go +++ b/pkg/recipe/git.go @@ -57,21 +57,23 @@ func (r Recipe) EnsureExists() error { } // EnsureVersion checks whether a specific version exists for a recipe. -func (r Recipe) EnsureVersion(version string) error { +func (r Recipe) EnsureVersion(version string) (bool, error) { + isChaosCommit := false + recipeDir := path.Join(config.RECIPES_DIR, r.Name) if err := gitPkg.EnsureGitRepo(recipeDir); err != nil { - return err + return isChaosCommit, err } repo, err := git.PlainOpen(recipeDir) if err != nil { - return err + return isChaosCommit, err } tags, err := repo.Tags() if err != nil { - return nil + return isChaosCommit, err } var parsedTags []string @@ -83,7 +85,7 @@ func (r Recipe) EnsureVersion(version string) error { } return nil }); err != nil { - return err + return isChaosCommit, err } joinedTags := strings.Join(parsedTags, ", ") @@ -91,27 +93,33 @@ func (r Recipe) EnsureVersion(version string) error { log.Debugf("read %s as tags for recipe %s", joinedTags, r.Name) } + var opts *git.CheckoutOptions if tagRef.String() == "" { - return fmt.Errorf("the local copy of %s doesn't seem to have version %s available?", r.Name, version) + log.Debugf("attempting to checkout '%s' as chaos commit", version) + + hash, err := repo.ResolveRevision(plumbing.Revision(version)) + if err != nil { + log.Fatalf("unable to resolve '%s': %s", version, err) + } + + opts = &git.CheckoutOptions{Hash: *hash, Create: false, Force: true} + isChaosCommit = true + } else { + opts = &git.CheckoutOptions{Branch: tagRef, Create: false, Force: true} } worktree, err := repo.Worktree() if err != nil { - return err + return isChaosCommit, nil } - opts := &git.CheckoutOptions{ - Branch: tagRef, - Create: false, - Force: true, - } if err := worktree.Checkout(opts); err != nil { - return err + return isChaosCommit, nil } log.Debugf("successfully checked %s out to %s in %s", r.Name, tagRef.Short(), recipeDir) - return nil + return isChaosCommit, nil } // EnsureIsClean makes sure that the recipe repository has no unstaged changes. diff --git a/tests/integration/app_deploy.bats b/tests/integration/app_deploy.bats index 541c8405..57d0ad07 100644 --- a/tests/integration/app_deploy.bats +++ b/tests/integration/app_deploy.bats @@ -356,3 +356,12 @@ teardown(){ run $ABRA app secret rm "$TEST_APP_DOMAIN" --all --chaos assert_success } + +# bats test_tags=slow +@test "deploy chaos commit" { + tagHash=$(_get_tag_hash "0.1.0+1.20.0") + + run $ABRA app deploy "$TEST_APP_DOMAIN" "$tagHash" --no-input --no-converge-checks + assert_success + assert_output --partial 'chaos mode' +} diff --git a/tests/integration/app_rollback.bats b/tests/integration/app_rollback.bats index 0ee13a5e..5662336d 100644 --- a/tests/integration/app_rollback.bats +++ b/tests/integration/app_rollback.bats @@ -145,3 +145,14 @@ teardown(){ refute_output --partial "${tagHash:0:8}" assert_output --partial "false" } + +# bats test_tags=slow +@test "chaos commit rollback not possible" { + _deploy_app + + tagHash=$(_get_tag_hash "0.2.0+1.21.0") + + run $ABRA app rollback "$TEST_APP_DOMAIN" "$tagHash" --no-input --no-converge-checks + assert_failure + assert_output --partial "not a known version" +} diff --git a/tests/integration/app_upgrade.bats b/tests/integration/app_upgrade.bats index 4ca59f32..a970f07b 100644 --- a/tests/integration/app_upgrade.bats +++ b/tests/integration/app_upgrade.bats @@ -189,3 +189,15 @@ teardown(){ refute_output --partial "${tagHash:0:8}" assert_output --partial "false" } + +@test "chaos commit upgrade not possible" { + run $ABRA app deploy "$TEST_APP_DOMAIN" "0.1.0+1.20.0" --no-input --no-converge-checks + assert_success + assert_output --partial '0.1.0+1.20.0' + + tagHash=$(_get_tag_hash "0.2.0+1.21.0") + + run $ABRA app upgrade "$TEST_APP_DOMAIN" "$tagHash" --no-input --no-converge-checks + assert_failure + assert_output --partial "not a known version" +}