package app import ( "fmt" "strings" abraFormatter "coopcloud.tech/abra/cli/formatter" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/catalogue" "coopcloud.tech/abra/pkg/client" stack "coopcloud.tech/abra/pkg/client/stack" "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/recipe" "github.com/AlecAivazis/survey/v2" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) var appDeployCommand = &cli.Command{ Name: "deploy", Aliases: []string{"d"}, Usage: "Deploy an app", Flags: []cli.Flag{ internal.ForceFlag, internal.ChaosFlag, }, Description: ` This command deploys a new instance of an app. It does not support changing the version of an existing deployed app, for this you need to look at the "abra app upgrade " command. You may pass "--force" to re-deploy the same version again. This can be useful if the container runtime has gotten into a weird state. Chas mode ("--chaos") will deploy your local checkout of a recipe as-is, including unstaged changes and can be useful for live hacking and testing new recipes. `, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) stackName := app.StackName() cl, err := client.New(app.Server) if err != nil { logrus.Fatal(err) } logrus.Debugf("checking whether '%s' is already deployed", stackName) isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, stackName) if err != nil { logrus.Fatal(err) } if isDeployed { if internal.Force { logrus.Warnf("'%s' already deployed but continuing (--force)", stackName) } else if internal.Chaos { logrus.Warnf("'%s' already deployed but continuing (--chaos)", stackName) } else { logrus.Fatalf("'%s' is already deployed", stackName) } } version := deployedVersion if version == "" && !internal.Chaos { versions, err := catalogue.GetRecipeCatalogueVersions(app.Type) if err != nil { logrus.Fatal(err) } if len(versions) > 0 { version = versions[len(versions)-1] logrus.Infof("choosing '%s' as version to deploy", version) if err := recipe.EnsureVersion(app.Type, version); err != nil { logrus.Fatal(err) } } else { version = "latest commit" logrus.Warn("no versions detected, using latest commit") if err := recipe.EnsureLatest(app.Type); err != nil { logrus.Fatal(err) } } } if !internal.Chaos { logrus.Infof("choosing '%s' as version to deploy", version) if err := recipe.EnsureVersion(app.Type, version); err != nil { logrus.Fatal(err) } } if internal.Chaos { logrus.Warnf("chaos mode engaged") var err error version, err = recipe.ChaosVersion(app.Type) if err != nil { logrus.Fatal(err) } } abraShPath := fmt.Sprintf("%s/%s/%s", config.APPS_DIR, app.Type, "abra.sh") abraShEnv, err := config.ReadAbraShEnvVars(abraShPath) if err != nil { logrus.Fatal(err) } for k, v := range abraShEnv { app.Env[k] = v } composeFiles, err := config.GetAppComposeFiles(app.Type, app.Env) if err != nil { logrus.Fatal(err) } deployOpts := stack.Deploy{ Composefiles: composeFiles, Namespace: stackName, Prune: false, ResolveImage: stack.ResolveImageAlways, } compose, err := config.GetAppComposeConfig(app.Name, deployOpts, app.Env) if err != nil { logrus.Fatal(err) } if err := DeployOverview(app, version); err != nil { logrus.Fatal(err) } if err := stack.RunDeploy(cl, deployOpts, compose); err != nil { logrus.Fatal(err) } return nil }, BashComplete: func(c *cli.Context) { appNames, err := config.GetAppNames() if err != nil { logrus.Warn(err) } if c.NArg() > 0 { return } for _, a := range appNames { fmt.Println(a) } }, } // DeployOverview shows a deployment overview func DeployOverview(app config.App, version string) error { tableCol := []string{"server", "compose", "domain", "stack", "version"} table := abraFormatter.CreateTable(tableCol) deployConfig := "compose.yml" if composeFiles, ok := app.Env["COMPOSE_FILE"]; ok { deployConfig = strings.Join(strings.Split(composeFiles, ":"), "\n") } server := app.Server if app.Server == "default" { server = "local" } table.Append([]string{server, deployConfig, app.Domain, app.StackName(), version}) table.Render() response := false prompt := &survey.Confirm{ Message: "continue with deployment?", } if err := survey.AskOne(prompt, &response); err != nil { return err } if !response { logrus.Fatal("exiting as requested") } return nil } // NewVersionOverview shows an upgrade or downgrade overview func NewVersionOverview(app config.App, currentVersion, newVersion string) error { tableCol := []string{"server", "compose", "domain", "stack", "current version", "to be deployed"} table := abraFormatter.CreateTable(tableCol) deployConfig := "compose.yml" if composeFiles, ok := app.Env["COMPOSE_FILE"]; ok { deployConfig = strings.Join(strings.Split(composeFiles, ":"), "\n") } server := app.Server if app.Server == "default" { server = "local" } table.Append([]string{server, deployConfig, app.Domain, app.StackName(), currentVersion, newVersion}) table.Render() response := false prompt := &survey.Confirm{ Message: "continue with deployment?", } if err := survey.AskOne(prompt, &response); err != nil { return err } if !response { logrus.Fatal("exiting as requested") } return nil }