Compare commits
	
		
			2 Commits
		
	
	
		
			0.7.0-rc3-
			...
			prune
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0d8191bc3e | |||
| 20cdfe7a72 | 
@ -5,11 +5,9 @@
 | 
			
		||||
 | 
			
		||||
- 3wordchant
 | 
			
		||||
- cassowary
 | 
			
		||||
- codegod100
 | 
			
		||||
- decentral1se
 | 
			
		||||
- frando
 | 
			
		||||
- kawaiipunk
 | 
			
		||||
- knoflook
 | 
			
		||||
- moritz
 | 
			
		||||
- roxxers
 | 
			
		||||
- yksflip
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,7 @@ recipes.
 | 
			
		||||
		conf := runtime.New()
 | 
			
		||||
 | 
			
		||||
		if !internal.Chaos {
 | 
			
		||||
			if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil {
 | 
			
		||||
			if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -8,11 +8,8 @@ import (
 | 
			
		||||
	"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"
 | 
			
		||||
)
 | 
			
		||||
@ -25,56 +22,47 @@ var pruneFlag = &cli.BoolFlag{
 | 
			
		||||
	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()
 | 
			
		||||
 | 
			
		||||
func cleanup(c *cli.Context) error {
 | 
			
		||||
	for {
 | 
			
		||||
		logrus.Debugf("polling for %s stack, waiting to be undeployed...", stackName)
 | 
			
		||||
 | 
			
		||||
		services, err := stack.GetStackServices(ctx, cl, stackName)
 | 
			
		||||
		if !prune {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
		stackName := app.StackName()
 | 
			
		||||
		cl, err := client.New(app.Server)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		ctx := context.Background()
 | 
			
		||||
 | 
			
		||||
		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
 | 
			
		||||
		pruneFilters := filters.NewArgs()
 | 
			
		||||
		stackSearch := fmt.Sprintf("%s*", stackName)
 | 
			
		||||
		pruneFilters.Add("label", stackSearch)
 | 
			
		||||
		cr, err := cl.ContainersPrune(ctx, pruneFilters)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Errorf(err.Error())
 | 
			
		||||
			time.Sleep(time.Second)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		logrus.Infof("Containers deleted: %s; Space reclaimed: %v", cr.ContainersDeleted, cr.SpaceReclaimed)
 | 
			
		||||
 | 
			
		||||
		time.Sleep(time.Second)
 | 
			
		||||
		nr, err := cl.NetworksPrune(ctx, pruneFilters)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Errorf(err.Error())
 | 
			
		||||
			time.Sleep(time.Second)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		logrus.Infof("Networks deleted %s", nr.NetworksDeleted)
 | 
			
		||||
 | 
			
		||||
		ir, err := cl.ImagesPrune(ctx, pruneFilters)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Errorf(err.Error())
 | 
			
		||||
			time.Sleep(time.Second)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		logrus.Infof("Images deleted: %s; Space reclaimed: %v", ir.ImagesDeleted, ir.SpaceReclaimed)
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -87,16 +75,12 @@ var appUndeployCommand = cli.Command{
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		pruneFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Usage:        "Undeploy an app",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Usage:  "Undeploy an app",
 | 
			
		||||
	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 eligible for pruning once undeployed.
 | 
			
		||||
 | 
			
		||||
Passing "-p/--prune" does not remove those volumes.
 | 
			
		||||
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.
 | 
			
		||||
`,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
@ -125,13 +109,8 @@ Passing "-p/--prune" does not remove those volumes.
 | 
			
		||||
		if err := stack.RunRemove(context.Background(), cl, rmOpts); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if prune {
 | 
			
		||||
			if err := pruneApp(c, cl, app); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cleanup(c)
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -61,7 +61,7 @@ recipes.
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !internal.Chaos {
 | 
			
		||||
			if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil {
 | 
			
		||||
			if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,6 @@ 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"
 | 
			
		||||
@ -55,8 +54,6 @@ 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)
 | 
			
		||||
		}
 | 
			
		||||
@ -82,7 +79,7 @@ keys configured on your account.
 | 
			
		||||
 | 
			
		||||
		if !internal.SkipUpdates {
 | 
			
		||||
			logrus.Warn(logMsg)
 | 
			
		||||
			if err := recipe.UpdateRepositories(repos, recipeName, conf); err != nil {
 | 
			
		||||
			if err := recipe.UpdateRepositories(repos, recipeName); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -100,7 +97,7 @@ keys configured on your account.
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			versions, err := recipe.GetRecipeVersions(recipeMeta.Name, conf)
 | 
			
		||||
			versions, err := recipe.GetRecipeVersions(recipeMeta.Name)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Warn(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ func DeployAction(c *cli.Context) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !Chaos {
 | 
			
		||||
		if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil {
 | 
			
		||||
		if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -122,8 +122,7 @@ func ensureServerFlag() error {
 | 
			
		||||
func NewAction(c *cli.Context) error {
 | 
			
		||||
	recipe := ValidateRecipeWithPrompt(c, runtime.WithEnsureRecipeLatest(false))
 | 
			
		||||
 | 
			
		||||
	conf := runtime.New(runtime.WithEnsureRecipeLatest(false))
 | 
			
		||||
	if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
 | 
			
		||||
	if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -42,8 +42,10 @@ func ValidateRecipe(c *cli.Context, opts ...runtime.Option) recipe.Recipe {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := recipe.EnsureLatest(recipeName, conf); err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	if conf.EnsureRecipeLatest {
 | 
			
		||||
		if err := recipe.EnsureLatest(recipeName, conf); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("validated %s as recipe argument", recipeName)
 | 
			
		||||
@ -108,8 +110,10 @@ func ValidateRecipeWithPrompt(c *cli.Context, opts ...runtime.Option) recipe.Rec
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := recipe.EnsureLatest(recipeName, conf); err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	if conf.EnsureRecipeLatest {
 | 
			
		||||
		if err := recipe.EnsureLatest(recipeName, conf); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("validated %s as recipe argument", recipeName)
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,6 @@ 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"
 | 
			
		||||
)
 | 
			
		||||
@ -22,8 +21,6 @@ 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)
 | 
			
		||||
			return nil // ValidateRecipe ensures latest checkout
 | 
			
		||||
@ -34,7 +31,7 @@ var recipeFetchCommand = cli.Command{
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := recipe.UpdateRepositories(repos, recipeName, conf); err != nil {
 | 
			
		||||
		if err := recipe.UpdateRepositories(repos, recipeName); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,6 @@ 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"
 | 
			
		||||
)
 | 
			
		||||
@ -26,9 +25,8 @@ var recipeLintCommand = cli.Command{
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(c)
 | 
			
		||||
		conf := runtime.New()
 | 
			
		||||
 | 
			
		||||
		if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
 | 
			
		||||
		if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,6 @@ 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"
 | 
			
		||||
@ -61,9 +60,8 @@ 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)
 | 
			
		||||
		conf := runtime.New()
 | 
			
		||||
 | 
			
		||||
		if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
 | 
			
		||||
		if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,11 @@ 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)
 | 
			
		||||
@ -80,16 +84,6 @@ 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
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,9 +4,7 @@ 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"
 | 
			
		||||
@ -24,75 +22,60 @@ var volunesFilter bool
 | 
			
		||||
 | 
			
		||||
var volumesFilterFlag = &cli.BoolFlag{
 | 
			
		||||
	Name:        "volumes, v",
 | 
			
		||||
	Usage:       "Prune volumes. This will remove app data, Be Careful!",
 | 
			
		||||
	Usage:       "Prune volumes",
 | 
			
		||||
	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>]",
 | 
			
		||||
	Name:        "prune",
 | 
			
		||||
	Aliases:     []string{"p"},
 | 
			
		||||
	Usage:       "Prune a managed server; Runs a docker system prune",
 | 
			
		||||
	Description: "Prunes unused containers, networks, and dangling images",
 | 
			
		||||
	ArgsUsage:   "[<server>]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		allFilterFlag,
 | 
			
		||||
		volumesFilterFlag,
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.ServerNameComplete,
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		// Leaving filters empty for now
 | 
			
		||||
		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)
 | 
			
		||||
		logrus.Infof("Containers deleted: %s; Space reclaimed: %v", cr.ContainersDeleted, cr.SpaceReclaimed)
 | 
			
		||||
 | 
			
		||||
		nr, err := cl.NetworksPrune(ctx, args)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		logrus.Infof("networks pruned: %d", len(nr.NetworksDeleted))
 | 
			
		||||
		logrus.Infof("Networks deleted %s", 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)
 | 
			
		||||
		logrus.Infof("Images deleted: %s; Space reclaimed: %v", ir.ImagesDeleted, ir.SpaceReclaimed)
 | 
			
		||||
 | 
			
		||||
		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)
 | 
			
		||||
			logrus.Infof("Volumes deleted: %s; Space reclaimed: %v", vr.VolumesDeleted, vr.SpaceReclaimed)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,6 @@ 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"
 | 
			
		||||
@ -125,8 +124,7 @@ like tears in rain.
 | 
			
		||||
		internal.HetznerCloudNameFlag,
 | 
			
		||||
		internal.HetznerCloudAPITokenFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.ServerNameComplete,
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		serverName := internal.ValidateServer(c)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -321,7 +321,7 @@ func processRecipeRepoVersion(recipeName, version string, conf *runtime.Config)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := recipe.EnsureUpToDate(recipeName, conf); err != nil {
 | 
			
		||||
	if err := recipe.EnsureUpToDate(recipeName); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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,23 +41,7 @@ func RecipeNameComplete(c *cli.Context) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
// SubcommandComplete completes subcommands.
 | 
			
		||||
func SubcommandComplete(c *cli.Context) {
 | 
			
		||||
	if c.NArg() > 0 {
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
package formatter
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
@ -71,21 +70,3 @@ 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])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -339,10 +339,6 @@ func EnsureVersion(recipeName, version string) error {
 | 
			
		||||
 | 
			
		||||
// EnsureLatest makes sure the latest commit is checked out for a local recipe repository
 | 
			
		||||
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)
 | 
			
		||||
@ -587,11 +583,7 @@ 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, conf *runtime.Config) error {
 | 
			
		||||
	if !conf.EnsureRecipeLatest {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
func EnsureUpToDate(recipeName string) error {
 | 
			
		||||
	recipeDir := path.Join(config.RECIPES_DIR, recipeName)
 | 
			
		||||
 | 
			
		||||
	isClean, err := gitPkg.IsClean(recipeDir)
 | 
			
		||||
@ -936,8 +928,10 @@ func ReadReposMetadata() (RepoCatalogue, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRecipeVersions retrieves all recipe versions.
 | 
			
		||||
func GetRecipeVersions(recipeName string, conf *runtime.Config) (RecipeVersions, error) {
 | 
			
		||||
func GetRecipeVersions(recipeName string, opts ...runtime.Option) (RecipeVersions, error) {
 | 
			
		||||
	versions := RecipeVersions{}
 | 
			
		||||
	conf := runtime.New(opts...)
 | 
			
		||||
 | 
			
		||||
	recipeDir := path.Join(config.RECIPES_DIR, recipeName)
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("attempting to open git repository in %s", recipeDir)
 | 
			
		||||
@ -1039,7 +1033,7 @@ func GetRecipeCatalogueVersions(recipeName string, catl RecipeCatalogue) ([]stri
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateRepositories clones and updates all recipe repositories locally.
 | 
			
		||||
func UpdateRepositories(repos RepoCatalogue, recipeName string, conf *runtime.Config) error {
 | 
			
		||||
func UpdateRepositories(repos RepoCatalogue, recipeName string) error {
 | 
			
		||||
	var barLength int
 | 
			
		||||
	if recipeName != "" {
 | 
			
		||||
		barLength = 1
 | 
			
		||||
@ -1073,7 +1067,7 @@ func UpdateRepositories(repos RepoCatalogue, recipeName string, conf *runtime.Co
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err := EnsureUpToDate(rm.Name, conf); err != nil {
 | 
			
		||||
			if err := EnsureUpToDate(rm.Name); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,10 +11,7 @@ type Config struct {
 | 
			
		||||
	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.
 | 
			
		||||
// Option modified a Config.
 | 
			
		||||
type Option func(c *Config)
 | 
			
		||||
 | 
			
		||||
// New instantiates a new Config.
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
ABRA_VERSION="0.6.0-beta"
 | 
			
		||||
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$ABRA_VERSION"
 | 
			
		||||
RC_VERSION="0.7.0-rc3-beta"
 | 
			
		||||
RC_VERSION="0.7.0-rc2-beta"
 | 
			
		||||
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$RC_VERSION"
 | 
			
		||||
 | 
			
		||||
for arg in "$@"; do
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user