@ -2,10 +2,10 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/envfile"
|
||||
@ -18,6 +18,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/lint"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -27,9 +28,9 @@ var AppDeployCommand = &cobra.Command{
|
||||
Short: "Deploy an app",
|
||||
Long: `Deploy an app.
|
||||
|
||||
This command supports chaos operations. Use "--chaos/-c" to deploy your recipe
|
||||
checkout as-is. Recipe commit hashes are also supported values for "[version]".
|
||||
Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
This command supports chaos operations. Use "--chaos/-C" to deploy your recipe
|
||||
checkout as-is. Recipe commit hashes are also supported as values for
|
||||
"[version]". Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
Example: ` # standard deployment
|
||||
abra app deploy 1312.net
|
||||
|
||||
@ -61,29 +62,20 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
}
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var warnMessages []string
|
||||
var (
|
||||
deployWarnMessages []string
|
||||
toDeployVersion string
|
||||
isChaosCommit bool
|
||||
toDeployChaosVersion = config.CHAOS_DEFAULT
|
||||
)
|
||||
|
||||
app := internal.ValidateApp(args)
|
||||
stackName := app.StackName()
|
||||
|
||||
ok, err := validateChaosXORVersion(args)
|
||||
if !ok {
|
||||
log.Fatalf(err.Error())
|
||||
if err := validateArgsAndFlags(args); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
specificVersion := getSpecifiedVersion(args)
|
||||
|
||||
if specificVersion != "" {
|
||||
log.Debugf("overriding env file version (%s) with %s", app.Recipe.Version, specificVersion)
|
||||
app.Recipe.Version = specificVersion
|
||||
}
|
||||
|
||||
if specificVersion == "" && app.Recipe.Version != "" && !internal.Chaos {
|
||||
log.Debugf("retrieved %s as version from env file", app.Recipe.Version)
|
||||
specificVersion = app.Recipe.Version
|
||||
}
|
||||
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
if err := app.Recipe.Ensure(internal.GetEnsureContext()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@ -91,96 +83,66 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("checking whether %s is already deployed", stackName)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
deployMeta, err := stack.IsDeployed(context.Background(), cl, stackName)
|
||||
log.Debugf("checking whether %s is already deployed", app.StackName())
|
||||
|
||||
deployMeta, err := stack.IsDeployed(context.Background(), cl, app.StackName())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// NOTE(d1): handles "[version] 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
|
||||
// secrets might be generated
|
||||
toDeployVersion := deployMeta.Version
|
||||
if specificVersion != "" {
|
||||
toDeployVersion = specificVersion
|
||||
log.Debugf("choosing %s as version to deploy", toDeployVersion)
|
||||
|
||||
var err error
|
||||
isChaosCommit, err = app.Recipe.EnsureVersion(toDeployVersion)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if isChaosCommit {
|
||||
log.Debugf("assuming '%s' is a chaos commit", toDeployVersion)
|
||||
internal.Chaos = true
|
||||
}
|
||||
}
|
||||
|
||||
secStats, err := secret.PollSecretsStatus(cl, app)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, secStat := range secStats {
|
||||
if !secStat.CreatedOnRemote {
|
||||
log.Fatalf("unable to deploy, secrets not generated (%s)?", secStat.LocalName)
|
||||
}
|
||||
}
|
||||
|
||||
if deployMeta.IsDeployed && !(internal.Force || internal.Chaos) {
|
||||
log.Fatalf("%s is already deployed", app.Name)
|
||||
}
|
||||
|
||||
if !internal.Chaos && specificVersion == "" {
|
||||
versions, err := app.Recipe.Tags()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if len(args) == 2 && args[1] != "" {
|
||||
toDeployVersion = args[1]
|
||||
}
|
||||
|
||||
if len(versions) > 0 && !internal.Chaos {
|
||||
toDeployVersion = versions[len(versions)-1]
|
||||
log.Debugf("choosing %s as version to deploy", toDeployVersion)
|
||||
if _, err := app.Recipe.EnsureVersion(toDeployVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
head, err := app.Recipe.Head()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
toDeployVersion = formatter.SmallSHA(head.String())
|
||||
if !deployMeta.IsDeployed &&
|
||||
toDeployVersion == "" &&
|
||||
app.Recipe.EnvVersion != "" && !internal.IgnoreEnvVersion {
|
||||
log.Debugf("new deployment, choosing .env version: %s", app.Recipe.EnvVersion)
|
||||
toDeployVersion = app.Recipe.EnvVersion
|
||||
}
|
||||
|
||||
if !internal.Chaos && toDeployVersion == "" {
|
||||
if err := getLatestVersionOrCommit(app, &toDeployVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
toDeployChaosVersion := config.CHAOS_DEFAULT
|
||||
if internal.Chaos {
|
||||
if isChaosCommit {
|
||||
toDeployChaosVersion = specificVersion
|
||||
versionLabelLocal, err := app.Recipe.GetVersionLabelLocal()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
toDeployVersion = versionLabelLocal
|
||||
} else {
|
||||
var err error
|
||||
toDeployChaosVersion, err = app.Recipe.ChaosVersion()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := getChaosVersion(app, &toDeployVersion, &toDeployChaosVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
isChaosCommit, err = app.Recipe.EnsureVersion(toDeployVersion)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if isChaosCommit {
|
||||
log.Debugf("assuming chaos commit: %s", toDeployVersion)
|
||||
|
||||
internal.Chaos = true
|
||||
toDeployChaosVersion = toDeployVersion
|
||||
|
||||
toDeployVersion, err = app.Recipe.GetVersionLabelLocal()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateSecrets(cl, app); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
abraShEnv, err := envfile.ReadAbraShEnvVars(app.Recipe.AbraShPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -194,6 +156,7 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
stackName := app.StackName()
|
||||
deployOpts := stack.Deploy{
|
||||
Composefiles: composeFiles,
|
||||
Namespace: stackName,
|
||||
@ -224,23 +187,22 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
|
||||
for _, envVar := range envVars {
|
||||
if !envVar.Present {
|
||||
warnMessages = append(warnMessages,
|
||||
fmt.Sprintf("env var %s missing from %s.env, present in recipe .env.sample", envVar.Name, app.Domain),
|
||||
deployWarnMessages = append(deployWarnMessages,
|
||||
fmt.Sprintf("%s missing from %s.env", envVar.Name, app.Domain),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if !internal.NoDomainChecks {
|
||||
domainName, ok := app.Env["DOMAIN"]
|
||||
if ok {
|
||||
if domainName, ok := app.Env["DOMAIN"]; ok {
|
||||
if _, err = dns.EnsureDomainsResolveSameIPv4(domainName, app.Server); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
log.Debug("skipping domain checks as no DOMAIN=... configured for app")
|
||||
log.Debug("skipping domain checks, no DOMAIN=... configured")
|
||||
}
|
||||
} else {
|
||||
log.Debug("skipping domain checks as requested")
|
||||
log.Debug("skipping domain checks")
|
||||
}
|
||||
|
||||
deployedVersion := config.NO_VERSION_DEFAULT
|
||||
@ -248,13 +210,20 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
deployedVersion = deployMeta.Version
|
||||
}
|
||||
|
||||
toWriteVersion := toDeployVersion
|
||||
if internal.Chaos || isChaosCommit {
|
||||
toWriteVersion = toDeployChaosVersion
|
||||
}
|
||||
|
||||
if err := internal.DeployOverview(
|
||||
app,
|
||||
warnMessages,
|
||||
deployWarnMessages,
|
||||
deployedVersion,
|
||||
deployMeta.ChaosVersion,
|
||||
toDeployVersion,
|
||||
toDeployChaosVersion); err != nil {
|
||||
toDeployChaosVersion,
|
||||
toWriteVersion,
|
||||
); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@ -262,7 +231,8 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Debugf("set waiting timeout to %d s", stack.WaitTimeout)
|
||||
|
||||
log.Debugf("set waiting timeout to %d second(s)", stack.WaitTimeout)
|
||||
|
||||
if err := stack.RunDeploy(cl, deployOpts, compose, app.Name, internal.DontWaitConverge); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -276,30 +246,77 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
}
|
||||
}
|
||||
|
||||
app.Recipe.Version = toDeployVersion
|
||||
if toDeployChaosVersion != config.CHAOS_DEFAULT {
|
||||
app.Recipe.Version = toDeployChaosVersion
|
||||
}
|
||||
if err := app.WriteRecipeVersion(app.Recipe.Version, false); err != nil {
|
||||
log.Fatalf("writing new recipe version in env file: %s", err)
|
||||
if err := app.WriteRecipeVersion(toWriteVersion, false); err != nil {
|
||||
log.Fatalf("writing recipe version failed: %s", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// validateChaosXORVersion xor checks version/chaos mode
|
||||
func validateChaosXORVersion(args []string) (bool, error) {
|
||||
if getSpecifiedVersion(args) != "" && internal.Chaos {
|
||||
return false, errors.New("cannot use [version] and --chaos together")
|
||||
func getChaosVersion(app app.App, toDeployVersion, toDeployChaosVersion *string) error {
|
||||
var err error
|
||||
*toDeployChaosVersion, err = app.Recipe.ChaosVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return true, nil
|
||||
|
||||
*toDeployVersion, err = app.Recipe.GetVersionLabelLocal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getSpecifiedVersion retrieves the specific version if available
|
||||
func getSpecifiedVersion(args []string) string {
|
||||
if len(args) >= 2 {
|
||||
return args[1]
|
||||
func getLatestVersionOrCommit(app app.App, toDeployVersion *string) error {
|
||||
versions, err := app.Recipe.Tags()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ""
|
||||
|
||||
if len(versions) > 0 && !internal.Chaos {
|
||||
*toDeployVersion = versions[len(versions)-1]
|
||||
|
||||
log.Debugf("choosing %s as version to deploy", *toDeployVersion)
|
||||
|
||||
if _, err := app.Recipe.EnsureVersion(*toDeployVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
head, err := app.Recipe.Head()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*toDeployVersion = formatter.SmallSHA(head.String())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateArgsAndFlags ensures compatible args/flags.
|
||||
func validateArgsAndFlags(args []string) error {
|
||||
if len(args) == 2 && args[1] != "" && internal.Chaos {
|
||||
return fmt.Errorf("cannot use [version] and --chaos together")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateSecrets(cl *dockerClient.Client, app app.App) error {
|
||||
secStats, err := secret.PollSecretsStatus(cl, app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, secStat := range secStats {
|
||||
if !secStat.CreatedOnRemote {
|
||||
return fmt.Errorf("secret not generated: %s", secStat.LocalName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -332,6 +349,6 @@ func init() {
|
||||
"no-converge-checks",
|
||||
"c",
|
||||
false,
|
||||
"do not wait for converge logic checks",
|
||||
"disable converge logic checks",
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user