0
0
forked from toolshed/abra
Files
.chglog
.gitea
cli
app
app.go
backup.go
check.go
config.go
cp.go
deploy.go
list.go
logs.go
new.go
ps.go
remove.go
restore.go
rollback.go
run.go
secret.go
undeploy.go
upgrade.go
version.go
volume.go
catalogue
formatter
internal
recipe
server
cli.go
upgrade.go
version.go
cmd
pkg
scripts
tests
.drone.yml
.envrc.sample
.gitignore
.goreleaser.yml
Makefile
README.md
go.mod
go.sum
abra/cli/app/rollback.go

159 lines
4.0 KiB
Go

package app
import (
"fmt"
"coopcloud.tech/abra/pkg/catalogue"
stack "coopcloud.tech/abra/pkg/client/stack"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/tagcmp"
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/client"
"github.com/AlecAivazis/survey/v2"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
var appRollbackCommand = &cli.Command{
Name: "rollback",
Usage: "Roll an app back to a previous version",
Aliases: []string{"r", "downgrade"},
ArgsUsage: "<app>",
Flags: []cli.Flag{
internal.ForceFlag,
},
Description: `
This command rolls an app back to a previous version if one exists.
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 or your doing
some live hacking.
This action could be destructive, please ensure you have a copy of your app
data beforehand - see "abra app backup <app>" for more.
`,
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)
}
},
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 deployedVersion == "" {
logrus.Fatalf("failed to determine version of deployed '%s'", app.Name)
}
if !isDeployed {
logrus.Fatalf("'%s' is not deployed?", app.Name)
}
versions, err := catalogue.GetRecipeCatalogueVersions(app.Type)
if err != nil {
logrus.Fatal(err)
}
var availableDowngrades []string
for _, version := range versions {
parsedDeployedVersion, err := tagcmp.Parse(deployedVersion)
if err != nil {
logrus.Fatal(err)
}
parsedVersion, err := tagcmp.Parse(version)
if err != nil {
logrus.Fatal(err)
}
if parsedVersion != parsedDeployedVersion && parsedVersion.IsLessThan(parsedDeployedVersion) {
availableDowngrades = append(availableDowngrades, version)
}
}
if len(availableDowngrades) == 0 {
logrus.Fatal("no available downgrades, you're on latest")
}
// FIXME: jeezus golang why do you not have a list reverse function
for i, j := 0, len(availableDowngrades)-1; i < j; i, j = i+1, j-1 {
availableDowngrades[i], availableDowngrades[j] = availableDowngrades[j], availableDowngrades[i]
}
var chosenDowngrade string
if !internal.Force {
prompt := &survey.Select{
Message: fmt.Sprintf("Please select a downgrade (current version: '%s'):", deployedVersion),
Options: availableDowngrades,
}
if err := survey.AskOne(prompt, &chosenDowngrade); err != nil {
return err
}
}
if internal.Force {
chosenDowngrade = availableDowngrades[0]
logrus.Debugf("choosing '%s' as version to downgrade to", chosenDowngrade)
}
if err := recipe.EnsureVersion(app.Type, chosenDowngrade); 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 !internal.Force {
if err := NewVersionOverview(app, deployedVersion, chosenDowngrade); err != nil {
logrus.Fatal(err)
}
}
if err := stack.RunDeploy(cl, deployOpts, compose); err != nil {
logrus.Fatal(err)
}
return nil
},
}