From c227972c12e146680eb8f8cf8108b866b43c3900 Mon Sep 17 00:00:00 2001 From: decentral1se Date: Wed, 3 Nov 2021 09:20:40 +0100 Subject: [PATCH] WIP: make "abra app deploy" callable by code Closes https://git.coopcloud.tech/coop-cloud/organising/issues/212. --- cli/app/deploy.go | 184 +------------------------------------ cli/app/rollback.go | 2 +- cli/app/undeploy.go | 2 +- cli/app/upgrade.go | 2 +- cli/internal/deploy.go | 191 +++++++++++++++++++++++++++++++++++++++ cli/internal/new.go | 2 +- cli/internal/validate.go | 10 +- cli/server/add.go | 6 +- 8 files changed, 210 insertions(+), 189 deletions(-) create mode 100644 cli/internal/deploy.go diff --git a/cli/app/deploy.go b/cli/app/deploy.go index abf913eb4..60bbd0287 100644 --- a/cli/app/deploy.go +++ b/cli/app/deploy.go @@ -2,16 +2,9 @@ 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" "coopcloud.tech/abra/pkg/config" - "coopcloud.tech/abra/pkg/recipe" - stack "coopcloud.tech/abra/pkg/upstream/stack" - "github.com/AlecAivazis/survey/v2" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) @@ -36,7 +29,7 @@ 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: DeployAction, + Action: internal.DeployAction, BashComplete: func(c *cli.Context) { appNames, err := config.GetAppNames() if err != nil { @@ -50,178 +43,3 @@ recipes. } }, } - -// DeployAction is the main command-line action for this package -func DeployAction(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.Debugf("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 version == "" && !internal.Chaos { - logrus.Debugf("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, "continue with deployment?"); err != nil { - logrus.Fatal(err) - } - - if err := stack.RunDeploy(cl, deployOpts, compose); err != nil { - logrus.Fatal(err) - } - - return nil -} - -// DeployOverview shows a deployment overview -func DeployOverview(app config.App, version, message string) error { - if internal.NoInput { - return nil - } - - 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: message, - } - - 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 { - if internal.NoInput { - return nil - } - - 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 -} diff --git a/cli/app/rollback.go b/cli/app/rollback.go index c5a4a3a02..a1acb198f 100644 --- a/cli/app/rollback.go +++ b/cli/app/rollback.go @@ -163,7 +163,7 @@ recipes. } if !internal.Force { - if err := NewVersionOverview(app, deployedVersion, chosenDowngrade); err != nil { + if err := internal.NewVersionOverview(app, deployedVersion, chosenDowngrade); err != nil { logrus.Fatal(err) } } diff --git a/cli/app/undeploy.go b/cli/app/undeploy.go index d052c40b3..a016db101 100644 --- a/cli/app/undeploy.go +++ b/cli/app/undeploy.go @@ -40,7 +40,7 @@ volumes as eligiblef or pruning once undeployed. logrus.Fatalf("'%s' is not deployed?", stackName) } - if err := DeployOverview(app, deployedVersion, "continue with undeploy?"); err != nil { + if err := internal.DeployOverview(app, deployedVersion, "continue with undeploy?"); err != nil { logrus.Fatal(err) } diff --git a/cli/app/upgrade.go b/cli/app/upgrade.go index 66557c2f0..4c8609edf 100644 --- a/cli/app/upgrade.go +++ b/cli/app/upgrade.go @@ -154,7 +154,7 @@ recipes. logrus.Fatal(err) } - if err := NewVersionOverview(app, deployedVersion, chosenUpgrade); err != nil { + if err := internal.NewVersionOverview(app, deployedVersion, chosenUpgrade); err != nil { logrus.Fatal(err) } diff --git a/cli/internal/deploy.go b/cli/internal/deploy.go new file mode 100644 index 000000000..c4514e42a --- /dev/null +++ b/cli/internal/deploy.go @@ -0,0 +1,191 @@ +package internal + +import ( + "fmt" + "strings" + + abraFormatter "coopcloud.tech/abra/cli/formatter" + "coopcloud.tech/abra/pkg/catalogue" + "coopcloud.tech/abra/pkg/client" + "coopcloud.tech/abra/pkg/config" + "coopcloud.tech/abra/pkg/recipe" + "coopcloud.tech/abra/pkg/upstream/stack" + "github.com/AlecAivazis/survey/v2" + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" +) + +// DeployAction is the main command-line action for this package +func DeployAction(c *cli.Context) error { + app := 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 Force { + logrus.Warnf("'%s' already deployed but continuing (--force)", stackName) + } else if Chaos { + logrus.Warnf("'%s' already deployed but continuing (--chaos)", stackName) + } else { + logrus.Fatalf("'%s' is already deployed", stackName) + } + } + + version := deployedVersion + if version == "" && !Chaos { + versions, err := catalogue.GetRecipeCatalogueVersions(app.Type) + if err != nil { + logrus.Fatal(err) + } + if len(versions) > 0 { + version = versions[len(versions)-1] + logrus.Debugf("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 version == "" && !Chaos { + logrus.Debugf("choosing '%s' as version to deploy", version) + if err := recipe.EnsureVersion(app.Type, version); err != nil { + logrus.Fatal(err) + } + } + + if 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, "continue with deployment?"); err != nil { + logrus.Fatal(err) + } + + if err := stack.RunDeploy(cl, deployOpts, compose); err != nil { + logrus.Fatal(err) + } + + return nil +} + +// DeployOverview shows a deployment overview +func DeployOverview(app config.App, version, message 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() + + if NoInput { + return nil + } + + response := false + prompt := &survey.Confirm{ + Message: message, + } + + 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() + + if NoInput { + return nil + } + + 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 +} diff --git a/cli/internal/new.go b/cli/internal/new.go index 07a096225..f8ce7fcc6 100644 --- a/cli/internal/new.go +++ b/cli/internal/new.go @@ -42,7 +42,7 @@ var NewAppNameFlag = &cli.StringFlag{ Destination: &NewAppName, } -// RecipeName is used for configuring NewAction programmatically +// RecipeName is used for configuring recipe name programmatically var RecipeName string // createSecrets creates all secrets for a new app. diff --git a/cli/internal/validate.go b/cli/internal/validate.go index fb12c7b06..9c3a3d51d 100644 --- a/cli/internal/validate.go +++ b/cli/internal/validate.go @@ -13,6 +13,9 @@ import ( "github.com/urfave/cli/v2" ) +// AppName is used for configuring app name programmatically +var AppName string + // ValidateRecipe ensures the recipe arg is valid. func ValidateRecipe(c *cli.Context) recipe.Recipe { recipeName := c.Args().First() @@ -59,7 +62,7 @@ func ValidateRecipeWithPrompt(c *cli.Context) recipe.Recipe { logrus.Debugf("programmatically setting recipe name to %s", recipeName) } - if recipeName == "" && RecipeName == "" { + if recipeName == "" { ShowSubcommandHelpAndError(c, errors.New("no recipe provided")) } @@ -77,6 +80,11 @@ func ValidateRecipeWithPrompt(c *cli.Context) recipe.Recipe { func ValidateApp(c *cli.Context) config.App { appName := c.Args().First() + if appName == "" && AppName != "" { + appName = AppName + logrus.Debugf("programmatically setting app name to %s", appName) + } + if appName == "" { ShowSubcommandHelpAndError(c, errors.New("no app provided")) } diff --git a/cli/server/add.go b/cli/server/add.go index 198519804..0d0e4592d 100644 --- a/cli/server/add.go +++ b/cli/server/add.go @@ -338,7 +338,11 @@ func deployTraefik(c *cli.Context, cl *dockerClient.Client, domainName string) e logrus.Fatal(err) } - // TODO: run app deploy with all args passed through + internal.AppName = domainName + if err := internal.DeployAction(c); err != nil { + logrus.Fatal(err) + } + return nil }