Compare commits

...

44 Commits

Author SHA1 Message Date
edff63b446 Revert "review: change label autoupdate -> auto-update"
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
This reverts commit 74baa76f5ee5e5dd7b71b1f14be97cc40dfc611b.
2023-03-07 13:24:46 +01:00
d5979436c1 review: merge chaos + chaos_version column 2023-03-07 13:24:46 +01:00
cb33edaac3 review: change label autoupdate -> auto-update 2023-03-07 13:24:46 +01:00
e9879e2226 review: label convention chaos_version -> chaos-version 2023-03-07 13:24:46 +01:00
5428ebf43b review: avoid stackName recalculation 2023-03-07 13:24:46 +01:00
d120299929 feat(list): show autoupdate state 2023-03-07 13:24:46 +01:00
3753357ef8 feat(list): show chaos status and chaos version 2023-03-07 13:24:46 +01:00
611430aab2 Set chaos version label for each deployed or upgraded app 2023-03-07 13:24:46 +01:00
f29278f80a chore: go mod tidy
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-06 15:04:15 +01:00
a9a294cbb7 chore(deps): update module golang.org/x/sys to v0.6.0
Some checks failed
renovate/artifacts Artifact file update failure
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is failing
2023-03-06 08:02:17 +00:00
73004789a4 chore: go mod tidy
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-04 08:50:24 +01:00
440aba77d5 chore(deps): update module github.com/go-git/go-git/v5 to v5.6.0
Some checks failed
renovate/artifacts Artifact file update failure
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is failing
2023-03-01 08:02:11 +00:00
e4a89bcc4f fix(kadabra): only warn if a deployed app has no published release
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-28 15:34:27 +01:00
eb07617e73 chore: publish new release 0.7.0-beta
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-02-22 08:47:43 +01:00
9fca4e56fb docs: add comrade vera [ci skip] 2023-02-19 11:00:43 +01:00
f17523010a chore: publish next tag 0.7.0-rc3-beta
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-19 10:51:10 +01:00
3058178d84 fix: if all servers good, don't show empty table
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-19 10:34:47 +01:00
d62c4e3400 refactor: improved logging on pruning
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-19 10:28:18 +01:00
5739758c3a fix: give more time to tear down state [ci skip] 2023-02-17 11:11:28 +01:00
a6b5566fa6 refactor: clarify prune scope, not system wide [ci skip] 2023-02-17 11:09:44 +01:00
4dbe1362a8 docs: more clarity on prune functionality
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-17 11:00:02 +01:00
98fc36c830 refactor: hopefully more robust prune logic, docs 2023-02-17 10:59:06 +01:00
b8abc8705c docs: volumes pruning docs - more warnings 2023-02-17 10:42:38 +01:00
636261934f refactor: pass args in, docs, rename, lower-case logs 2023-02-17 10:23:00 +01:00
6381b73a6a chore: use lower-case like elsewhere 2023-02-17 10:21:56 +01:00
1a72e27045 refactor: add server auto-complete & cosmetics 2023-02-17 10:12:46 +01:00
9754c1b2d1 feat: server auto-complete on remove sub-command
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-17 10:10:48 +01:00
b14ec0cda4 review cleanups
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-17 08:53:43 +00:00
c7730ba604 Adding server prune and undeploy prune 2023-02-17 08:53:43 +00:00
47c61df444 docs: add comrade yksflip [ci skip] 2023-02-15 11:26:20 +01:00
312b93e794 fix: no gitops on recipe for "app new"
All checks were successful
continuous-integration/drone/push Build is passing
Closes coop-cloud/organising#408
2023-02-15 00:49:22 +01:00
992e675921 refactor: use passed down conf to decide 2023-02-15 00:35:33 +01:00
d4f3a7be31 docs: add comrade codegod100 [ci skip] 2023-02-14 17:16:25 +01:00
d619f399e7 Update 'cli/app/undeploy.go'
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-14 13:59:35 +00:00
96a8cb7aff chore: go mod tidy
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-14 14:29:25 +01:00
9b51d22c20 chore(deps): update module github.com/hetznercloud/hcloud-go to v1.40.0
Some checks failed
renovate/artifacts Artifact file update failure
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is failing
2023-02-14 08:02:28 +00:00
d789830ce4 feat: adds --since flag for abra app logs
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-02-14 00:19:38 +01:00
e4b4084dfd fix: stream logs without hitting git.coopcloud.tech
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Medium-sized options refactor in here too!

See coop-cloud/organising#292.
2023-02-13 16:46:43 +01:00
ff58646cfc fix: better error message when network gone 2023-02-13 12:33:00 +01:00
eec6469ba1 fix: Change error message to reflect RECIPE -> TYPE
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is failing
Closes coop-cloud/organising#409
2023-02-12 16:40:48 +01:00
e94f947d20 fix: don't create clients twice per server
All checks were successful
continuous-integration/drone/push Build is passing
Closes coop-cloud/organising#407
2023-02-12 00:02:59 +01:00
cccbe4a2ec fix: typo [ci skip] 2023-02-11 23:53:42 +01:00
f53cfb6c36 fix: better error message when missing context [ci skip] 2023-02-11 23:49:01 +01:00
f55f01a25c build: verbose local builds to show progress 2023-02-11 23:40:47 +01:00
37 changed files with 535 additions and 131 deletions

View File

@ -5,9 +5,12 @@
- 3wordchant
- cassowary
- codegod100
- decentral1se
- frando
- kawaiipunk
- knoflook
- moritz
- roxxers
- vera
- yksflip

View File

@ -16,11 +16,11 @@ install:
@go install -ldflags=$(LDFLAGS) $(ABRA)
build-dev:
@go build -ldflags=$(LDFLAGS) $(ABRA)
@go build -v -ldflags=$(LDFLAGS) $(ABRA)
build:
@go build -ldflags=$(DIST_LDFLAGS) $(ABRA)
@go build -ldflags=$(DIST_LDFLAGS) $(KADABRA)
@go build -v -ldflags=$(DIST_LDFLAGS) $(ABRA)
@go build -v -ldflags=$(DIST_LDFLAGS) $(KADABRA)
clean:
@rm '$(GOPATH)/bin/abra'

View File

@ -16,6 +16,7 @@ import (
"coopcloud.tech/abra/pkg/config"
containerPkg "coopcloud.tech/abra/pkg/container"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/abra/pkg/upstream/container"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
@ -72,13 +73,14 @@ This single file can be used to restore your app. See "abra app restore" for mor
`,
Action: func(c *cli.Context) error {
app := internal.ValidateApp(c)
conf := runtime.New()
cl, err := client.New(app.Server)
if err != nil {
logrus.Fatal(err)
}
recipe, err := recipe.Get(app.Recipe)
recipe, err := recipe.Get(app.Recipe, conf)
if err != nil {
logrus.Fatal(err)
}

View File

@ -12,6 +12,7 @@ import (
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
stack "coopcloud.tech/abra/pkg/upstream/stack"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@ -55,6 +56,7 @@ the logs.
BashComplete: autocomplete.AppNameComplete,
Action: func(c *cli.Context) error {
app := internal.ValidateApp(c)
conf := runtime.New()
cl, err := client.New(app.Server)
if err != nil {
@ -71,14 +73,14 @@ the logs.
}
if !internal.Watch {
if err := checkErrors(c, cl, app); err != nil {
if err := checkErrors(c, cl, app, conf); err != nil {
logrus.Fatal(err)
}
return nil
}
for {
if err := checkErrors(c, cl, app); err != nil {
if err := checkErrors(c, cl, app, conf); err != nil {
logrus.Fatal(err)
}
time.Sleep(2 * time.Second)
@ -88,8 +90,8 @@ the logs.
},
}
func checkErrors(c *cli.Context, cl *dockerClient.Client, app config.App) error {
recipe, err := recipe.Get(app.Recipe)
func checkErrors(c *cli.Context, cl *dockerClient.Client, app config.App, conf *runtime.Config) error {
recipe, err := recipe.Get(app.Recipe, conf)
if err != nil {
return err
}

View File

@ -39,13 +39,16 @@ var listAppServerFlag = &cli.StringFlag{
}
type appStatus struct {
Server string `json:"server"`
Recipe string `json:"recipe"`
AppName string `json:"appName"`
Domain string `json:"domain"`
Status string `json:"status"`
Version string `json:"version"`
Upgrade string `json:"upgrade"`
Server string `json:"server"`
Recipe string `json:"recipe"`
AppName string `json:"appName"`
Domain string `json:"domain"`
Status string `json:"status"`
Chaos string `json:"chaos"`
ChaosVersion string `json:"chaosVersion"`
AutoUpdate string `json:"autoUpdate"`
Version string `json:"version"`
Upgrade string `json:"upgrade"`
}
type serverStatus struct {
@ -138,12 +141,24 @@ can take some time.
if status {
status := "unknown"
version := "unknown"
chaos := "unknown"
chaosVersion := "unknown"
autoUpdate := "unknown"
if statusMeta, ok := statuses[app.StackName()]; ok {
if currentVersion, exists := statusMeta["version"]; exists {
if currentVersion != "" {
version = currentVersion
}
}
if chaosDeploy, exists := statusMeta["chaos"]; exists {
chaos = chaosDeploy
}
if chaosDeployVersion, exists := statusMeta["chaosVersion"]; exists {
chaosVersion = chaosDeployVersion
}
if autoUpdateState, exists := statusMeta["autoUpdate"]; exists {
autoUpdate = autoUpdateState
}
if statusMeta["status"] != "" {
status = statusMeta["status"]
}
@ -153,7 +168,10 @@ can take some time.
}
appStats.Status = status
appStats.Chaos = chaos
appStats.ChaosVersion = chaosVersion
appStats.Version = version
appStats.AutoUpdate = autoUpdate
var newUpdates []string
if version != "unknown" {
@ -223,7 +241,7 @@ can take some time.
tableCol := []string{"recipe", "domain"}
if status {
tableCol = append(tableCol, []string{"status", "version", "upgrade"}...)
tableCol = append(tableCol, []string{"status", "chaos", "version", "upgrade", "autoupdate"}...)
}
table := formatter.CreateTable(tableCol)
@ -231,7 +249,13 @@ can take some time.
for _, appStat := range serverStat.Apps {
tableRow := []string{appStat.Recipe, appStat.Domain}
if status {
tableRow = append(tableRow, []string{appStat.Status, appStat.Version, appStat.Upgrade}...)
chaosStatus := "unknown"
if appStat.ChaosVersion != "unknown" {
chaosStatus = appStat.Chaos + appStat.ChaosVersion
} else {
chaosStatus = appStat.Chaos
}
tableRow = append(tableRow, []string{appStat.Status, chaosStatus, appStat.Version, appStat.Upgrade, appStat.AutoUpdate}...)
}
table.Append(tableRow)
}

View File

@ -11,6 +11,7 @@ import (
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/abra/pkg/service"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@ -20,12 +21,14 @@ import (
)
var logOpts = types.ContainerLogsOptions{
Details: false,
Follow: true,
ShowStderr: true,
ShowStdout: true,
Tail: "20",
Since: "",
Until: "",
Timestamps: true,
Follow: true,
Tail: "20",
Details: false,
}
// stackLogs lists logs for all stack services
@ -74,18 +77,21 @@ var appLogsCommand = cli.Command{
Usage: "Tail app logs",
Flags: []cli.Flag{
internal.StdErrOnlyFlag,
internal.SinceLogsFlag,
internal.DebugFlag,
},
Before: internal.SubCommandBefore,
BashComplete: autocomplete.AppNameComplete,
Action: func(c *cli.Context) error {
app := internal.ValidateApp(c)
app := internal.ValidateApp(c, runtime.WithEnsureRecipeExists(false))
cl, err := client.New(app.Server)
if err != nil {
logrus.Fatal(err)
}
logOpts.Since = internal.SinceLogs
serviceName := c.Args().Get(1)
if serviceName == "" {
logrus.Debugf("tailing logs for all %s services", app.Recipe)

View File

@ -12,6 +12,7 @@ import (
"coopcloud.tech/abra/pkg/config"
containerPkg "coopcloud.tech/abra/pkg/container"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/abra/pkg/upstream/container"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
@ -55,6 +56,7 @@ Example:
`,
Action: func(c *cli.Context) error {
app := internal.ValidateApp(c)
conf := runtime.New()
cl, err := client.New(app.Server)
if err != nil {
@ -77,7 +79,7 @@ Example:
}
}
recipe, err := recipe.Get(app.Recipe)
recipe, err := recipe.Get(app.Recipe, conf)
if err != nil {
logrus.Fatal(err)
}

View File

@ -8,6 +8,7 @@ import (
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/lint"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
stack "coopcloud.tech/abra/pkg/upstream/stack"
"coopcloud.tech/tagcmp"
@ -49,14 +50,15 @@ recipes.
Action: func(c *cli.Context) error {
app := internal.ValidateApp(c)
stackName := app.StackName()
conf := runtime.New()
if !internal.Chaos {
if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil {
logrus.Fatal(err)
}
}
r, err := recipe.Get(app.Recipe)
r, err := recipe.Get(app.Recipe, conf)
if err != nil {
logrus.Fatal(err)
}
@ -181,6 +183,7 @@ recipes.
config.ExposeAllEnv(stackName, compose, app.Env)
config.SetRecipeLabel(compose, stackName, app.Recipe)
config.SetChaosLabel(compose, stackName, internal.Chaos)
config.SetChaosVersionLabel(compose, stackName, chosenDowngrade)
config.SetUpdateLabel(compose, stackName, app.Env)
if !internal.Force {
@ -189,7 +192,7 @@ recipes.
}
}
if err := stack.RunDeploy(cl, deployOpts, compose, app.StackName(), internal.DontWaitConverge); err != nil {
if err := stack.RunDeploy(cl, deployOpts, compose, stackName, internal.DontWaitConverge); err != nil {
logrus.Fatal(err)
}

View File

@ -2,15 +2,82 @@ package app
import (
"context"
"fmt"
"time"
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/formatter"
stack "coopcloud.tech/abra/pkg/upstream/stack"
"github.com/docker/docker/api/types/filters"
dockerClient "github.com/docker/docker/client"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
var prune bool
var pruneFlag = &cli.BoolFlag{
Name: "prune, p",
Destination: &prune,
Usage: "Prunes unused containers, networks, and dangling images for an app",
}
// pruneApp runs the equivalent of a "docker system prune" but only filtering
// against resources connected with the app deployment. It is not a system wide
// prune. Volumes are not pruned to avoid unwated data loss.
func pruneApp(c *cli.Context, cl *dockerClient.Client, app config.App) error {
stackName := app.StackName()
ctx := context.Background()
for {
logrus.Debugf("polling for %s stack, waiting to be undeployed...", stackName)
services, err := stack.GetStackServices(ctx, cl, stackName)
if err != nil {
return err
}
if len(services) == 0 {
logrus.Debugf("%s undeployed, moving on with pruning logic", stackName)
time.Sleep(time.Second) // give runtime more time to tear down related state
break
}
time.Sleep(time.Second)
}
pruneFilters := filters.NewArgs()
stackSearch := fmt.Sprintf("%s*", stackName)
pruneFilters.Add("label", stackSearch)
cr, err := cl.ContainersPrune(ctx, pruneFilters)
if err != nil {
return err
}
cntSpaceReclaimed := formatter.ByteCountSI(cr.SpaceReclaimed)
logrus.Infof("containers pruned: %d; space reclaimed: %s", len(cr.ContainersDeleted), cntSpaceReclaimed)
nr, err := cl.NetworksPrune(ctx, pruneFilters)
if err != nil {
return err
}
logrus.Infof("networks pruned: %d", len(nr.NetworksDeleted))
ir, err := cl.ImagesPrune(ctx, pruneFilters)
if err != nil {
return err
}
imgSpaceReclaimed := formatter.ByteCountSI(ir.SpaceReclaimed)
logrus.Infof("images pruned: %d; space reclaimed: %s", len(ir.ImagesDeleted), imgSpaceReclaimed)
return nil
}
var appUndeployCommand = cli.Command{
Name: "undeploy",
Aliases: []string{"un"},
@ -18,18 +85,22 @@ var appUndeployCommand = cli.Command{
Flags: []cli.Flag{
internal.DebugFlag,
internal.NoInputFlag,
pruneFlag,
},
Before: internal.SubCommandBefore,
Usage: "Undeploy an app",
Before: internal.SubCommandBefore,
Usage: "Undeploy an app",
BashComplete: autocomplete.AppNameComplete,
Description: `
This does not destroy any of the application data. However, you should remain
vigilant, as your swarm installation will consider any previously attached
volumes as eligiblef or pruning once undeployed.
This does not destroy any of the application data.
However, you should remain vigilant, as your swarm installation will consider
any previously attached volumes as eligible for pruning once undeployed.
Passing "-p/--prune" does not remove those volumes.
`,
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)
@ -55,7 +126,12 @@ volumes as eligiblef or pruning once undeployed.
logrus.Fatal(err)
}
if prune {
if err := pruneApp(c, cl, app); err != nil {
logrus.Fatal(err)
}
}
return nil
},
BashComplete: autocomplete.AppNameComplete,
}

View File

@ -10,6 +10,7 @@ import (
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/lint"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
stack "coopcloud.tech/abra/pkg/upstream/stack"
"coopcloud.tech/tagcmp"
"github.com/AlecAivazis/survey/v2"
@ -52,6 +53,7 @@ recipes.
Action: func(c *cli.Context) error {
app := internal.ValidateApp(c)
stackName := app.StackName()
conf := runtime.New()
cl, err := client.New(app.Server)
if err != nil {
@ -59,12 +61,12 @@ recipes.
}
if !internal.Chaos {
if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil {
logrus.Fatal(err)
}
}
r, err := recipe.Get(app.Recipe)
r, err := recipe.Get(app.Recipe, conf)
if err != nil {
logrus.Fatal(err)
}
@ -192,13 +194,14 @@ recipes.
config.ExposeAllEnv(stackName, compose, app.Env)
config.SetRecipeLabel(compose, stackName, app.Recipe)
config.SetChaosLabel(compose, stackName, internal.Chaos)
config.SetChaosVersionLabel(compose, stackName, chosenUpgrade)
config.SetUpdateLabel(compose, stackName, app.Env)
if err := internal.NewVersionOverview(app, deployedVersion, chosenUpgrade, releaseNotes); err != nil {
logrus.Fatal(err)
}
if err := stack.RunDeploy(cl, deployOpts, compose, app.StackName(), internal.DontWaitConverge); err != nil {
if err := stack.RunDeploy(cl, deployOpts, compose, stackName, internal.DontWaitConverge); err != nil {
logrus.Fatal(err)
}

View File

@ -8,6 +8,7 @@ import (
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/abra/pkg/upstream/stack"
"github.com/docker/distribution/reference"
"github.com/sirupsen/logrus"
@ -48,6 +49,7 @@ version.
Action: func(c *cli.Context) error {
app := internal.ValidateApp(c)
stackName := app.StackName()
conf := runtime.New()
cl, err := client.New(app.Server)
if err != nil {
@ -69,7 +71,7 @@ version.
logrus.Fatalf("%s is not deployed?", app.Name)
}
recipeMeta, err := recipe.GetRecipeMeta(app.Recipe)
recipeMeta, err := recipe.GetRecipeMeta(app.Recipe, conf)
if err != nil {
logrus.Fatal(err)
}

View File

@ -13,6 +13,7 @@ import (
"coopcloud.tech/abra/pkg/formatter"
gitPkg "coopcloud.tech/abra/pkg/git"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"github.com/go-git/go-git/v5"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
@ -54,8 +55,10 @@ keys configured on your account.
ArgsUsage: "[<recipe>]",
Action: func(c *cli.Context) error {
recipeName := c.Args().First()
conf := runtime.New()
if recipeName != "" {
internal.ValidateRecipe(c, true)
internal.ValidateRecipe(c)
}
if err := catalogue.EnsureUpToDate(); err != nil {
@ -79,7 +82,7 @@ keys configured on your account.
if !internal.SkipUpdates {
logrus.Warn(logMsg)
if err := recipe.UpdateRepositories(repos, recipeName); err != nil {
if err := recipe.UpdateRepositories(repos, recipeName, conf); err != nil {
logrus.Fatal(err)
}
}
@ -97,7 +100,7 @@ keys configured on your account.
continue
}
versions, err := recipe.GetRecipeVersions(recipeMeta.Name)
versions, err := recipe.GetRecipeVersions(recipeMeta.Name, conf)
if err != nil {
logrus.Warn(err)
}

View File

@ -328,6 +328,14 @@ var StdErrOnlyFlag = &cli.BoolFlag{
Destination: &StdErrOnly,
}
var SinceLogs string
var SinceLogsFlag = &cli.StringFlag{
Name: "since, S",
Value: "",
Usage: "tail logs since YYYY-MM-DDTHH:MM:SSZ",
Destination: &SinceLogs,
}
var DontWaitConverge bool
var DontWaitConvergeFlag = &cli.BoolFlag{
Name: "no-converge-checks, c",

View File

@ -15,6 +15,7 @@ import (
"coopcloud.tech/abra/pkg/git"
"coopcloud.tech/abra/pkg/lint"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/abra/pkg/upstream/stack"
"github.com/AlecAivazis/survey/v2"
"github.com/sirupsen/logrus"
@ -24,6 +25,8 @@ import (
// DeployAction is the main command-line action for this package
func DeployAction(c *cli.Context) error {
app := ValidateApp(c)
stackName := app.StackName()
conf := runtime.New()
cl, err := client.New(app.Server)
if err != nil {
@ -31,12 +34,12 @@ func DeployAction(c *cli.Context) error {
}
if !Chaos {
if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil {
logrus.Fatal(err)
}
}
r, err := recipe.Get(app.Recipe)
r, err := recipe.Get(app.Recipe, conf)
if err != nil {
logrus.Fatal(err)
}
@ -45,9 +48,9 @@ func DeployAction(c *cli.Context) error {
logrus.Fatal(err)
}
logrus.Debugf("checking whether %s is already deployed", app.StackName())
logrus.Debugf("checking whether %s is already deployed", stackName)
isDeployed, deployedVersion, err := stack.IsDeployed(context.Background(), cl, app.StackName())
isDeployed, deployedVersion, err := stack.IsDeployed(context.Background(), cl, stackName)
if err != nil {
logrus.Fatal(err)
}
@ -83,7 +86,7 @@ func DeployAction(c *cli.Context) error {
}
version = formatter.SmallSHA(head.String())
logrus.Warn("no versions detected, using latest commit")
if err := recipe.EnsureLatest(app.Recipe); err != nil {
if err := recipe.EnsureLatest(app.Recipe, conf); err != nil {
logrus.Fatal(err)
}
}
@ -126,7 +129,7 @@ func DeployAction(c *cli.Context) error {
}
deployOpts := stack.Deploy{
Composefiles: composeFiles,
Namespace: app.StackName(),
Namespace: stackName,
Prune: false,
ResolveImage: stack.ResolveImageAlways,
}
@ -134,10 +137,11 @@ func DeployAction(c *cli.Context) error {
if err != nil {
logrus.Fatal(err)
}
config.ExposeAllEnv(app.StackName(), compose, app.Env)
config.SetRecipeLabel(compose, app.StackName(), app.Recipe)
config.SetChaosLabel(compose, app.StackName(), Chaos)
config.SetUpdateLabel(compose, app.StackName(), app.Env)
config.ExposeAllEnv(stackName, compose, app.Env)
config.SetRecipeLabel(compose, stackName, app.Recipe)
config.SetChaosLabel(compose, stackName, Chaos)
config.SetChaosVersionLabel(compose, stackName, version)
config.SetUpdateLabel(compose, stackName, app.Env)
if err := DeployOverview(app, version, "continue with deployment?"); err != nil {
logrus.Fatal(err)

View File

@ -11,6 +11,7 @@ import (
"coopcloud.tech/abra/pkg/jsontable"
"coopcloud.tech/abra/pkg/recipe"
recipePkg "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/abra/pkg/secret"
"github.com/AlecAivazis/survey/v2"
dockerClient "github.com/docker/docker/client"
@ -119,9 +120,10 @@ func ensureServerFlag() error {
// NewAction is the new app creation logic
func NewAction(c *cli.Context) error {
recipe := ValidateRecipeWithPrompt(c, false)
recipe := ValidateRecipeWithPrompt(c, runtime.WithEnsureRecipeLatest(false))
if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil {
conf := runtime.New(runtime.WithEnsureRecipeLatest(false))
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
logrus.Fatal(err)
}

View File

@ -9,6 +9,7 @@ import (
"coopcloud.tech/abra/pkg/app"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"github.com/AlecAivazis/survey/v2"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
@ -18,14 +19,15 @@ import (
var AppName string
// ValidateRecipe ensures the recipe arg is valid.
func ValidateRecipe(c *cli.Context, ensureLatest bool) recipe.Recipe {
func ValidateRecipe(c *cli.Context, opts ...runtime.Option) recipe.Recipe {
recipeName := c.Args().First()
conf := runtime.New(opts...)
if recipeName == "" {
ShowSubcommandHelpAndError(c, errors.New("no recipe name provided"))
}
chosenRecipe, err := recipe.Get(recipeName)
chosenRecipe, err := recipe.Get(recipeName, conf)
if err != nil {
if c.Command.Name == "generate" {
if strings.Contains(err.Error(), "missing a compose") {
@ -40,10 +42,8 @@ func ValidateRecipe(c *cli.Context, ensureLatest bool) recipe.Recipe {
}
}
if ensureLatest {
if err := recipe.EnsureLatest(recipeName); err != nil {
logrus.Fatal(err)
}
if err := recipe.EnsureLatest(recipeName, conf); err != nil {
logrus.Fatal(err)
}
logrus.Debugf("validated %s as recipe argument", recipeName)
@ -53,8 +53,9 @@ func ValidateRecipe(c *cli.Context, ensureLatest bool) recipe.Recipe {
// ValidateRecipeWithPrompt ensures a recipe argument is present before
// validating, asking for input if required.
func ValidateRecipeWithPrompt(c *cli.Context, ensureLatest bool) recipe.Recipe {
func ValidateRecipeWithPrompt(c *cli.Context, opts ...runtime.Option) recipe.Recipe {
recipeName := c.Args().First()
conf := runtime.New(opts...)
if recipeName == "" && !NoInput {
var recipes []string
@ -102,15 +103,13 @@ func ValidateRecipeWithPrompt(c *cli.Context, ensureLatest bool) recipe.Recipe {
ShowSubcommandHelpAndError(c, errors.New("no recipe name provided"))
}
chosenRecipe, err := recipe.Get(recipeName)
chosenRecipe, err := recipe.Get(recipeName, conf)
if err != nil {
logrus.Fatal(err)
}
if ensureLatest {
if err := recipe.EnsureLatest(recipeName); err != nil {
logrus.Fatal(err)
}
if err := recipe.EnsureLatest(recipeName, conf); err != nil {
logrus.Fatal(err)
}
logrus.Debugf("validated %s as recipe argument", recipeName)
@ -119,8 +118,9 @@ func ValidateRecipeWithPrompt(c *cli.Context, ensureLatest bool) recipe.Recipe {
}
// ValidateApp ensures the app name arg is valid.
func ValidateApp(c *cli.Context) config.App {
func ValidateApp(c *cli.Context, opts ...runtime.Option) config.App {
appName := c.Args().First()
conf := runtime.New(opts...)
if AppName != "" {
appName = AppName
@ -136,7 +136,7 @@ func ValidateApp(c *cli.Context) config.App {
logrus.Fatal(err)
}
if err := recipe.EnsureExists(app.Recipe); err != nil {
if err := recipe.EnsureExists(app.Recipe, conf); err != nil {
logrus.Fatal(err)
}

View File

@ -4,6 +4,7 @@ import (
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
@ -21,8 +22,10 @@ var recipeFetchCommand = cli.Command{
BashComplete: autocomplete.RecipeNameComplete,
Action: func(c *cli.Context) error {
recipeName := c.Args().First()
conf := runtime.New()
if recipeName != "" {
internal.ValidateRecipe(c, true)
internal.ValidateRecipe(c)
return nil // ValidateRecipe ensures latest checkout
}
@ -31,7 +34,7 @@ var recipeFetchCommand = cli.Command{
logrus.Fatal(err)
}
if err := recipe.UpdateRepositories(repos, recipeName); err != nil {
if err := recipe.UpdateRepositories(repos, recipeName, conf); err != nil {
logrus.Fatal(err)
}

View File

@ -8,6 +8,7 @@ import (
"coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/lint"
recipePkg "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
@ -24,9 +25,10 @@ var recipeLintCommand = cli.Command{
Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete,
Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipe(c, true)
recipe := internal.ValidateRecipe(c)
conf := runtime.New()
if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil {
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
logrus.Fatal(err)
}

View File

@ -13,6 +13,7 @@ import (
gitPkg "coopcloud.tech/abra/pkg/git"
"coopcloud.tech/abra/pkg/recipe"
recipePkg "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/tagcmp"
"github.com/AlecAivazis/survey/v2"
"github.com/docker/distribution/reference"
@ -58,7 +59,7 @@ your SSH keys configured on your account.
Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete,
Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipeWithPrompt(c, false)
recipe := internal.ValidateRecipeWithPrompt(c, runtime.WithEnsureRecipeLatest(false))
imagesTmp, err := getImageVersions(recipe)
if err != nil {

View File

@ -8,6 +8,7 @@ import (
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/tagcmp"
"github.com/AlecAivazis/survey/v2"
"github.com/go-git/go-git/v5"
@ -41,7 +42,7 @@ auto-generate it for you. The <recipe> configuration will be updated on the
local file system.
`,
Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipeWithPrompt(c, false)
recipe := internal.ValidateRecipeWithPrompt(c, runtime.WithEnsureRecipeLatest(false))
mainApp, err := internal.GetMainAppImage(recipe)
if err != nil {

View File

@ -14,6 +14,7 @@ import (
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/formatter"
recipePkg "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/tagcmp"
"github.com/AlecAivazis/survey/v2"
"github.com/docker/distribution/reference"
@ -59,9 +60,10 @@ You may invoke this command in "wizard" mode and be prompted for input:
},
Before: internal.SubCommandBefore,
Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipeWithPrompt(c, true)
recipe := internal.ValidateRecipeWithPrompt(c)
conf := runtime.New()
if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil {
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
logrus.Fatal(err)
}

View File

@ -5,6 +5,7 @@ import (
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/formatter"
recipePkg "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
@ -20,7 +21,7 @@ var recipeVersionCommand = cli.Command{
Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete,
Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipe(c, false)
recipe := internal.ValidateRecipe(c, runtime.WithEnsureRecipeLatest(false))
catalogue, err := recipePkg.ReadRecipeCatalogue()
if err != nil {

View File

@ -39,11 +39,7 @@ var serverListCommand = cli.Command{
tableColumns := []string{"name", "host", "user", "port"}
table := formatter.CreateTable(tableColumns)
if internal.MachineReadable {
defer table.JSONRender()
} else {
defer table.Render()
}
serverNames, err := config.ReadServerNames()
if err != nil {
logrus.Fatal(err)
@ -84,6 +80,16 @@ var serverListCommand = cli.Command{
}
}
if internal.MachineReadable {
table.JSONRender()
} else {
if problemsFilter && table.NumLines() == 0 {
logrus.Info("all servers wired up correctly 👏")
} else {
table.Render()
}
}
return nil
},
}

100
cli/server/prune.go Normal file
View File

@ -0,0 +1,100 @@
package server
import (
"context"
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/formatter"
"github.com/docker/docker/api/types/filters"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
var allFilter bool
var allFilterFlag = &cli.BoolFlag{
Name: "all, a",
Usage: "Remove all unused images not just dangling ones",
Destination: &allFilter,
}
var volunesFilter bool
var volumesFilterFlag = &cli.BoolFlag{
Name: "volumes, v",
Usage: "Prune volumes. This will remove app data, Be Careful!",
Destination: &volunesFilter,
}
var serverPruneCommand = cli.Command{
Name: "prune",
Aliases: []string{"p"},
Usage: "Prune a managed server; Runs a docker system prune",
Description: `
Prunes unused containers, networks, and dangling images.
If passing "-v/--volumes" then volumes not connected with a deployed app will
also be removed. This can result in unwanted data loss if not used carefully.
`,
ArgsUsage: "[<server>]",
Flags: []cli.Flag{
allFilterFlag,
volumesFilterFlag,
internal.DebugFlag,
},
Before: internal.SubCommandBefore,
BashComplete: autocomplete.ServerNameComplete,
Action: func(c *cli.Context) error {
var args filters.Args
serverName := internal.ValidateServer(c)
cl, err := client.New(serverName)
if err != nil {
logrus.Fatal(err)
}
ctx := context.Background()
cr, err := cl.ContainersPrune(ctx, args)
if err != nil {
logrus.Fatal(err)
}
cntSpaceReclaimed := formatter.ByteCountSI(cr.SpaceReclaimed)
logrus.Infof("containers pruned: %d; space reclaimed: %s", len(cr.ContainersDeleted), cntSpaceReclaimed)
nr, err := cl.NetworksPrune(ctx, args)
if err != nil {
logrus.Fatal(err)
}
logrus.Infof("networks pruned: %d", len(nr.NetworksDeleted))
pruneFilters := filters.NewArgs()
if allFilter {
pruneFilters.Add("dangling", "false")
}
ir, err := cl.ImagesPrune(ctx, pruneFilters)
if err != nil {
logrus.Fatal(err)
}
imgSpaceReclaimed := formatter.ByteCountSI(ir.SpaceReclaimed)
logrus.Infof("images pruned: %d; space reclaimed: %s", len(ir.ImagesDeleted), imgSpaceReclaimed)
if volunesFilter {
vr, err := cl.VolumesPrune(ctx, args)
if err != nil {
logrus.Fatal(err)
}
volSpaceReclaimed := formatter.ByteCountSI(vr.SpaceReclaimed)
logrus.Infof("volumes pruned: %d; space reclaimed: %s", len(vr.VolumesDeleted), volSpaceReclaimed)
}
return nil
},
}

View File

@ -7,6 +7,7 @@ import (
"path/filepath"
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/formatter"
@ -124,7 +125,8 @@ like tears in rain.
internal.HetznerCloudNameFlag,
internal.HetznerCloudAPITokenFlag,
},
Before: internal.SubCommandBefore,
Before: internal.SubCommandBefore,
BashComplete: autocomplete.ServerNameComplete,
Action: func(c *cli.Context) error {
serverName := internal.ValidateServer(c)

View File

@ -22,5 +22,6 @@ recipes, see available flags on "abra server add" for more.
serverAddCommand,
serverListCommand,
serverRemoveCommand,
serverPruneCommand,
},
}

View File

@ -12,6 +12,7 @@ import (
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/lint"
"coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/abra/pkg/upstream/convert"
"coopcloud.tech/abra/pkg/upstream/stack"
"coopcloud.tech/tagcmp"
@ -113,10 +114,12 @@ update chaos deployments use the "--chaos" flag. Use it with care.
logrus.Fatal(err)
}
conf := runtime.New()
if !updateAll {
stackName := c.Args().Get(0)
recipeName := c.Args().Get(1)
err = tryUpgrade(cl, stackName, recipeName)
err = tryUpgrade(cl, stackName, recipeName, conf)
if err != nil {
logrus.Fatal(err)
}
@ -136,7 +139,7 @@ update chaos deployments use the "--chaos" flag. Use it with care.
logrus.Fatal(err)
}
err = tryUpgrade(cl, stackName, recipeName)
err = tryUpgrade(cl, stackName, recipeName, conf)
if err != nil {
logrus.Fatal(err)
}
@ -281,7 +284,8 @@ func getAvailableUpgrades(cl *dockerclient.Client, stackName string, recipeName
}
if len(versions) == 0 {
return nil, fmt.Errorf("no published releases for %s in the recipe catalogue?", recipeName)
logrus.Warnf("no published releases for %s in the recipe catalogue?", recipeName)
return nil, nil
}
var availableUpgrades []string
@ -313,12 +317,12 @@ func getAvailableUpgrades(cl *dockerclient.Client, stackName string, recipeName
// processRecipeRepoVersion clones, pulls, checks out the version and lints the
// recipe repository.
func processRecipeRepoVersion(recipeName string, version string) error {
if err := recipe.EnsureExists(recipeName); err != nil {
func processRecipeRepoVersion(recipeName, version string, conf *runtime.Config) error {
if err := recipe.EnsureExists(recipeName, conf); err != nil {
return err
}
if err := recipe.EnsureUpToDate(recipeName); err != nil {
if err := recipe.EnsureUpToDate(recipeName, conf); err != nil {
return err
}
@ -326,7 +330,7 @@ func processRecipeRepoVersion(recipeName string, version string) error {
return err
}
if r, err := recipe.Get(recipeName); err != nil {
if r, err := recipe.Get(recipeName, conf); err != nil {
return err
} else if err := lint.LintForErrors(r); err != nil {
return err
@ -383,7 +387,7 @@ func createDeployConfig(recipeName string, stackName string, env config.AppEnv)
}
// tryUpgrade performs the upgrade if all the requirements are fulfilled.
func tryUpgrade(cl *dockerclient.Client, stackName string, recipeName string) error {
func tryUpgrade(cl *dockerclient.Client, stackName, recipeName string, conf *runtime.Config) error {
if recipeName == "" {
logrus.Debugf("Don't update %s due to missing recipe name", stackName)
return nil
@ -419,13 +423,13 @@ func tryUpgrade(cl *dockerclient.Client, stackName string, recipeName string) er
return nil
}
err = upgrade(cl, stackName, recipeName, upgradeVersion)
err = upgrade(cl, stackName, recipeName, upgradeVersion, conf)
return err
}
// upgrade performs all necessary steps to upgrade an app.
func upgrade(cl *dockerclient.Client, stackName string, recipeName string, upgradeVersion string) error {
func upgrade(cl *dockerclient.Client, stackName, recipeName, upgradeVersion string, conf *runtime.Config) error {
env, err := getEnv(cl, stackName)
if err != nil {
return err
@ -438,7 +442,7 @@ func upgrade(cl *dockerclient.Client, stackName string, recipeName string, upgra
Env: env,
}
if err = processRecipeRepoVersion(recipeName, upgradeVersion); err != nil {
if err = processRecipeRepoVersion(recipeName, upgradeVersion, conf); err != nil {
return err
}

6
go.mod
View File

@ -11,8 +11,8 @@ require (
github.com/docker/distribution v2.8.1+incompatible
github.com/docker/docker v20.10.23+incompatible
github.com/docker/go-units v0.5.0
github.com/go-git/go-git/v5 v5.5.2
github.com/hetznercloud/hcloud-go v1.39.0
github.com/go-git/go-git/v5 v5.6.0
github.com/hetznercloud/hcloud-go v1.40.0
github.com/moby/sys/signal v0.7.0
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
github.com/olekukonko/tablewriter v0.0.5
@ -46,5 +46,5 @@ require (
github.com/urfave/cli v1.22.9
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/sys v0.5.0
golang.org/x/sys v0.6.0
)

25
go.sum
View File

@ -414,8 +414,8 @@ github.com/go-git/go-billy/v5 v5.4.0 h1:Vaw7LaSTRJOUric7pe4vnzBSgyuf2KrLsu2Y4ZpQ
github.com/go-git/go-billy/v5 v5.4.0/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ=
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
github.com/go-git/go-git/v5 v5.5.2 h1:v8lgZa5k9ylUw+OR/roJHTxR4QItsNFI5nKtAXFuynw=
github.com/go-git/go-git/v5 v5.5.2/go.mod h1:BE5hUJ5yaV2YMxhmaP4l6RBQ08kMxKSPD4BlxtH7OjI=
github.com/go-git/go-git/v5 v5.6.0 h1:JvBdYfcttd+0kdpuWO7KTu0FYgCf5W0t5VwkWGobaa4=
github.com/go-git/go-git/v5 v5.6.0/go.mod h1:6nmJ0tJ3N4noMV1Omv7rC5FG3/o8Cm51TB4CJp7mRmE=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -605,8 +605,8 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hetznercloud/hcloud-go v1.39.0 h1:RUlzI458nGnPR6dlcZlrsGXYC1hQlFbKdm8tVtEQQB0=
github.com/hetznercloud/hcloud-go v1.39.0/go.mod h1:mepQwR6va27S3UQthaEPGS86jtzSY9xWL1e9dyxXpgA=
github.com/hetznercloud/hcloud-go v1.40.0 h1:rchS+LVd80GuAOQUM5pLs0Fn7tb4PflPCuxskLYc1JQ=
github.com/hetznercloud/hcloud-go v1.40.0/go.mod h1:jcKomw7kDIjrJ9FI72S/RdRPK8X8arYzEnXjRM/uXT8=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@ -744,6 +744,7 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM=
github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM=
@ -833,8 +834,8 @@ github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrap
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pjbgf/sha1cd v0.2.3 h1:uKQP/7QOzNtKYH7UTohZLcjF5/55EnTw0jO/Ru4jZwI=
github.com/pjbgf/sha1cd v0.2.3/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -1045,6 +1046,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -1069,6 +1071,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
@ -1109,6 +1112,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1164,6 +1168,7 @@ golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
@ -1310,16 +1315,18 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
@ -1407,6 +1414,7 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1652,6 +1660,7 @@ k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAG
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=

View File

@ -9,7 +9,7 @@ import (
"github.com/urfave/cli"
)
// AppNameComplete copletes app names
// AppNameComplete copletes app names.
func AppNameComplete(c *cli.Context) {
appNames, err := config.GetAppNames()
if err != nil {
@ -25,7 +25,7 @@ func AppNameComplete(c *cli.Context) {
}
}
// RecipeNameComplete completes recipe names
// RecipeNameComplete completes recipe names.
func RecipeNameComplete(c *cli.Context) {
catl, err := recipe.ReadRecipeCatalogue()
if err != nil {
@ -41,7 +41,23 @@ func RecipeNameComplete(c *cli.Context) {
}
}
// SubcommandComplete completes subcommands.
// ServerNameComplete completes server names.
func ServerNameComplete(c *cli.Context) {
files, err := config.LoadAppFiles("")
if err != nil {
logrus.Fatal(err)
}
if c.NArg() > 0 {
return
}
for _, appFile := range files {
fmt.Println(appFile.Server)
}
}
// SubcommandComplete completes sub-commands.
func SubcommandComplete(c *cli.Context) {
if c.NArg() > 0 {
return

View File

@ -26,7 +26,7 @@ func New(serverName string) (*client.Client, error) {
if serverName != "default" {
context, err := GetContext(serverName)
if err != nil {
return nil, err
return nil, fmt.Errorf("unknown server, run \"abra server add %s\"?", serverName)
}
ctxEndpoint, err := contextPkg.GetContextEndpoint(context)

View File

@ -173,7 +173,7 @@ func newApp(env AppEnv, name string, appFile AppFile) (App, error) {
if !exists {
recipe, exists = env["TYPE"]
if !exists {
return App{}, fmt.Errorf("%s is missing the RECIPE env var", name)
return App{}, fmt.Errorf("%s is missing the TYPE env var?", name)
}
}
@ -369,13 +369,6 @@ func GetAppStatuses(apps []App, MachineReadable bool) (map[string]map[string]str
}
}
for server := range servers {
// validate that all server connections work
if _, err := client.New(server); err != nil {
return statuses, err
}
}
var bar *progressbar.ProgressBar
if !MachineReadable {
bar = formatter.CreateProgressbar(len(servers), "querying remote servers...")
@ -410,7 +403,25 @@ func GetAppStatuses(apps []App, MachineReadable bool) (map[string]map[string]str
result["status"] = "deployed"
}
labelKey := fmt.Sprintf("coop-cloud.%s.version", name)
labelKey := fmt.Sprintf("coop-cloud.%s.chaos", name)
chaos, ok := service.Spec.Labels[labelKey]
if ok {
result["chaos"] = chaos
}
labelKey = fmt.Sprintf("coop-cloud.%s.chaos-version", name)
if chaosVersion, ok := service.Spec.Labels[labelKey]; ok {
result["chaosVersion"] = chaosVersion
}
labelKey = fmt.Sprintf("coop-cloud.%s.autoupdate", name)
if autoUpdate, ok := service.Spec.Labels[labelKey]; ok {
result["autoUpdate"] = autoUpdate
} else {
result["autoUpdate"] = "false"
}
labelKey = fmt.Sprintf("coop-cloud.%s.version", name)
if version, ok := service.Spec.Labels[labelKey]; ok {
result["version"] = version
} else {
@ -506,6 +517,17 @@ func SetChaosLabel(compose *composetypes.Config, stackName string, chaos bool) {
}
}
// SetChaosVersionLabel adds the label 'coop-cloud.${STACK_NAME}.chaos-version=$(GIT_COMMIT)' to the app container
func SetChaosVersionLabel(compose *composetypes.Config, stackName string, chaosVersion string) {
for _, service := range compose.Services {
if service.Name == "app" {
logrus.Debugf("set label 'coop-cloud.%s.chaos-version' to %v for %s", stackName, chaosVersion, stackName)
labelKey := fmt.Sprintf("coop-cloud.%s.chaos-version", stackName)
service.Deploy.Labels[labelKey] = chaosVersion
}
}
}
// SetUpdateLabel adds env ENABLE_AUTO_UPDATE as label to enable/disable the
// auto update process for this app. The default if this variable is not set is to disable
// the auto update process.

View File

@ -1,6 +1,7 @@
package formatter
import (
"fmt"
"os"
"strings"
"time"
@ -70,3 +71,21 @@ func StripTagMeta(image string) string {
return image
}
// ByteCountSI presents a human friendly representation of a byte count. See
// https://yourbasic.org/golang/formatting-byte-size-to-human-readable-format.
func ByteCountSI(b uint64) string {
const unit = 1000
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := uint64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
}

View File

@ -18,6 +18,7 @@ import (
"coopcloud.tech/abra/pkg/formatter"
gitPkg "coopcloud.tech/abra/pkg/git"
"coopcloud.tech/abra/pkg/limit"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/abra/pkg/upstream/stack"
loader "coopcloud.tech/abra/pkg/upstream/stack"
"coopcloud.tech/abra/pkg/web"
@ -206,8 +207,8 @@ func (r Recipe) Tags() ([]string, error) {
}
// Get retrieves a recipe.
func Get(recipeName string) (Recipe, error) {
if err := EnsureExists(recipeName); err != nil {
func Get(recipeName string, conf *runtime.Config) (Recipe, error) {
if err := EnsureExists(recipeName, conf); err != nil {
return Recipe{}, err
}
@ -233,7 +234,7 @@ func Get(recipeName string) (Recipe, error) {
return Recipe{}, err
}
meta, err := GetRecipeMeta(recipeName)
meta, err := GetRecipeMeta(recipeName, conf)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
meta = RecipeMeta{}
@ -250,7 +251,11 @@ func Get(recipeName string) (Recipe, error) {
}
// EnsureExists ensures that a recipe is locally cloned
func EnsureExists(recipeName string) error {
func EnsureExists(recipeName string, conf *runtime.Config) error {
if !conf.EnsureRecipeExists {
return nil
}
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
if _, err := os.Stat(recipeDir); os.IsNotExist(err) {
@ -333,7 +338,11 @@ func EnsureVersion(recipeName, version string) error {
}
// EnsureLatest makes sure the latest commit is checked out for a local recipe repository
func EnsureLatest(recipeName string) error {
func EnsureLatest(recipeName string, conf *runtime.Config) error {
if !conf.EnsureRecipeLatest {
return nil
}
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
isClean, err := gitPkg.IsClean(recipeDir)
@ -361,7 +370,7 @@ func EnsureLatest(recipeName string) error {
return err
}
meta, err := GetRecipeMeta(recipeName)
meta, err := GetRecipeMeta(recipeName, conf)
if err != nil {
return err
}
@ -578,7 +587,11 @@ func GetStringInBetween(recipeName, str, start, end string) (result string, err
}
// EnsureUpToDate ensures that the local repo is synced to the remote
func EnsureUpToDate(recipeName string) error {
func EnsureUpToDate(recipeName string, conf *runtime.Config) error {
if !conf.EnsureRecipeLatest {
return nil
}
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
isClean, err := gitPkg.IsClean(recipeDir)
@ -790,7 +803,7 @@ func VersionsOfService(recipe, serviceName string) ([]string, error) {
}
// GetRecipeMeta retrieves the recipe metadata from the recipe catalogue.
func GetRecipeMeta(recipeName string) (RecipeMeta, error) {
func GetRecipeMeta(recipeName string, conf *runtime.Config) (RecipeMeta, error) {
catl, err := ReadRecipeCatalogue()
if err != nil {
return RecipeMeta{}, err
@ -801,7 +814,7 @@ func GetRecipeMeta(recipeName string) (RecipeMeta, error) {
return RecipeMeta{}, fmt.Errorf("recipe %s does not exist?", recipeName)
}
if err := EnsureExists(recipeName); err != nil {
if err := EnsureExists(recipeName, conf); err != nil {
return RecipeMeta{}, err
}
@ -923,9 +936,8 @@ func ReadReposMetadata() (RepoCatalogue, error) {
}
// GetRecipeVersions retrieves all recipe versions.
func GetRecipeVersions(recipeName string) (RecipeVersions, error) {
func GetRecipeVersions(recipeName string, conf *runtime.Config) (RecipeVersions, error) {
versions := RecipeVersions{}
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
logrus.Debugf("attempting to open git repository in %s", recipeDir)
@ -962,7 +974,7 @@ func GetRecipeVersions(recipeName string) (RecipeVersions, error) {
logrus.Debugf("successfully checked out %s in %s", ref.Name(), recipeDir)
recipe, err := Get(recipeName)
recipe, err := Get(recipeName, conf)
if err != nil {
return err
}
@ -1027,7 +1039,7 @@ func GetRecipeCatalogueVersions(recipeName string, catl RecipeCatalogue) ([]stri
}
// UpdateRepositories clones and updates all recipe repositories locally.
func UpdateRepositories(repos RepoCatalogue, recipeName string) error {
func UpdateRepositories(repos RepoCatalogue, recipeName string, conf *runtime.Config) error {
var barLength int
if recipeName != "" {
barLength = 1
@ -1061,7 +1073,7 @@ func UpdateRepositories(repos RepoCatalogue, recipeName string) error {
logrus.Fatal(err)
}
if err := EnsureUpToDate(rm.Name); err != nil {
if err := EnsureUpToDate(rm.Name, conf); err != nil {
logrus.Fatal(err)
}

61
pkg/runtime/runtime.go Normal file
View File

@ -0,0 +1,61 @@
package runtime
import "github.com/sirupsen/logrus"
// Config is an internal configuration modifier. It can be instantiated on a
// command call and can be changed on the fly to help make decisions further
// down in the internals, e.g. whether or not to clone the recipe locally or
// not.
type Config struct {
EnsureRecipeExists bool // ensure that the recipe is cloned locally
EnsureRecipeLatest bool // ensure the local recipe has latest changes
}
// Option modified a Config. The convetion for passing Options to functions is
// so far, only used in internal/validate.go. A Config is then constructed and
// passed down further into the code. This may change in the future but this is
// at least the abstraction so far.
type Option func(c *Config)
// New instantiates a new Config.
func New(opts ...Option) *Config {
conf := &Config{
EnsureRecipeExists: true,
}
for _, optFunc := range opts {
optFunc(conf)
}
return conf
}
// WithEnsureRecipeExists determines whether or not we should be cloning the
// local recipe or not. This can be useful for being more adaptable to offline
// scenarios.
func WithEnsureRecipeExists(ensureRecipeExists bool) Option {
return func(c *Config) {
if ensureRecipeExists {
logrus.Debugf("runtime config: EnsureRecipeExists = %v, ensuring recipes are cloned", ensureRecipeExists)
} else {
logrus.Debugf("runtime config: EnsureRecipeExists = %v, not cloning recipes", ensureRecipeExists)
}
c.EnsureRecipeExists = ensureRecipeExists
}
}
// WithEnsureRecipeLatest determines whether we should update the local recipes
// remotely via Git. This can be useful when e.g. ensuring we have the latest
// changes before making new ones.
func WithEnsureRecipeLatest(ensureRecipeLatest bool) Option {
return func(c *Config) {
if ensureRecipeLatest {
logrus.Debugf("runtime config: EnsureRecipeLatest = %v, ensuring recipes have latest changes", ensureRecipeLatest)
} else {
logrus.Debugf("runtime config: EnsureRecipeLatest = %v, leaving recipes alone", ensureRecipeLatest)
}
c.EnsureRecipeLatest = ensureRecipeLatest
}
}

View File

@ -77,6 +77,8 @@ func Fatal(hostname string, err error) error {
return fmt.Errorf("connection timed out for %s", hostname)
} else if strings.Contains(out, "Permission denied") {
return fmt.Errorf("ssh auth: permission denied for %s", hostname)
} else if strings.Contains(out, "Network is unreachable") {
return fmt.Errorf("unable to connect to %s, network is unreachable?", hostname)
} else {
return err
}

View File

@ -1,8 +1,8 @@
#!/usr/bin/env bash
ABRA_VERSION="0.6.0-beta"
ABRA_VERSION="0.7.0-beta"
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$ABRA_VERSION"
RC_VERSION="0.7.0-rc2-beta"
RC_VERSION="0.7.0-beta"
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$RC_VERSION"
for arg in "$@"; do