fix: improved offline support
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
Closes coop-cloud/organising#471.
This commit is contained in:
parent
ab64eb2e8d
commit
3dc5662821
|
@ -41,6 +41,7 @@ var appBackupCommand = cli.Command{
|
|||
ArgsUsage: "<domain> [<service>]",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
|
@ -71,8 +72,8 @@ This file is a compressed archive which contains all backup paths. To see paths,
|
|||
This single file can be used to restore your app. See "abra app restore" for more.
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New()
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
|
@ -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"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
@ -19,10 +20,12 @@ var appCheckCommand = cli.Command{
|
|||
ArgsUsage: "<domain>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
envSamplePath := path.Join(config.RECIPES_DIR, app.Recipe, ".env.sample")
|
||||
if _, err := os.Stat(envSamplePath); err != nil {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
@ -38,11 +39,13 @@ Example:
|
|||
internal.LocalCmdFlag,
|
||||
internal.RemoteUserFlag,
|
||||
internal.TtyFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
|
@ -20,6 +20,7 @@ var appConfigCommand = cli.Command{
|
|||
ArgsUsage: "<domain>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/container"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
|
@ -27,6 +28,7 @@ var appCpCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Copy files to/from a running app service",
|
||||
|
@ -42,7 +44,8 @@ And if you want to copy that file back to your current working directory locally
|
|||
abra app cp <domain> app:/myfile.txt .
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
|
@ -18,7 +19,6 @@ 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"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
|
@ -38,6 +38,7 @@ var appDeployCommand = cli.Command{
|
|||
internal.ChaosFlag,
|
||||
internal.NoDomainChecksFlag,
|
||||
internal.DontWaitConvergeFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
@ -53,9 +54,9 @@ recipes.
|
|||
`,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
stackName := app.StackName()
|
||||
conf := runtime.New()
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
@ -94,7 +95,7 @@ recipes.
|
|||
|
||||
version := deployedVersion
|
||||
if version == "unknown" && !internal.Chaos {
|
||||
catl, err := recipe.ReadRecipeCatalogue()
|
||||
catl, err := recipe.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -51,12 +51,13 @@ the logs.
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.WatchFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New()
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"coopcloud.tech/tagcmp"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
|
@ -79,9 +80,12 @@ can take some time.
|
|||
statusFlag,
|
||||
listAppServerFlag,
|
||||
recipeFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
|
||||
appFiles, err := config.LoadAppFiles(listAppServer)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
|
@ -109,7 +113,7 @@ can take some time.
|
|||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
catl, err = recipe.ReadRecipeCatalogue()
|
||||
catl, err = recipe.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -79,11 +79,13 @@ var appLogsCommand = cli.Command{
|
|||
internal.StdErrOnlyFlag,
|
||||
internal.SinceLogsFlag,
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c, runtime.WithEnsureRecipeExists(false))
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
211
cli/app/new.go
211
cli/app/new.go
|
@ -1,8 +1,23 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"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"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
|
@ -38,9 +53,199 @@ var appNewCommand = cli.Command{
|
|||
internal.DomainFlag,
|
||||
internal.PassFlag,
|
||||
internal.SecretsFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "[<recipe>]",
|
||||
Action: func(c *cli.Context) error {
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
recipe := internal.ValidateRecipeWithPrompt(c, conf)
|
||||
|
||||
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ensureServerFlag(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ensureDomainFlag(recipe, internal.NewAppServer); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
sanitisedAppName := config.SanitiseAppName(internal.Domain)
|
||||
logrus.Debugf("%s sanitised as %s for new app", internal.Domain, sanitisedAppName)
|
||||
|
||||
if err := config.TemplateAppEnvSample(
|
||||
recipe.Name,
|
||||
internal.Domain,
|
||||
internal.NewAppServer,
|
||||
internal.Domain,
|
||||
); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := promptForSecrets(internal.Domain); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
cl, err := client.New(internal.NewAppServer)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
var secrets AppSecrets
|
||||
var secretTable *jsontable.JSONTable
|
||||
if internal.Secrets {
|
||||
secrets, err := createSecrets(cl, sanitisedAppName)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
secretCols := []string{"Name", "Value"}
|
||||
secretTable = formatter.CreateTable(secretCols)
|
||||
for secret := range secrets {
|
||||
secretTable.Append([]string{secret, secrets[secret]})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if internal.NewAppServer == "default" {
|
||||
internal.NewAppServer = "local"
|
||||
}
|
||||
|
||||
tableCol := []string{"server", "recipe", "domain"}
|
||||
table := formatter.CreateTable(tableCol)
|
||||
table.Append([]string{internal.NewAppServer, recipe.Name, internal.Domain})
|
||||
|
||||
fmt.Println("")
|
||||
fmt.Println(fmt.Sprintf("A new %s app has been created! Here is an overview:", recipe.Name))
|
||||
fmt.Println("")
|
||||
table.Render()
|
||||
fmt.Println("")
|
||||
fmt.Println("You can configure this app by running the following:")
|
||||
fmt.Println(fmt.Sprintf("\n abra app config %s", internal.Domain))
|
||||
fmt.Println("")
|
||||
fmt.Println("You can deploy this app by running the following:")
|
||||
fmt.Println(fmt.Sprintf("\n abra app deploy %s", internal.Domain))
|
||||
fmt.Println("")
|
||||
|
||||
if len(secrets) > 0 {
|
||||
fmt.Println("Here are your generated secrets:")
|
||||
fmt.Println("")
|
||||
secretTable.Render()
|
||||
fmt.Println("")
|
||||
logrus.Warn("generated secrets are not shown again, please take note of them *now*")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "[<recipe>]",
|
||||
Action: internal.NewAction,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
}
|
||||
|
||||
// AppSecrets represents all app secrest
|
||||
type AppSecrets map[string]string
|
||||
|
||||
// createSecrets creates all secrets for a new app.
|
||||
func createSecrets(cl *dockerClient.Client, sanitisedAppName string) (AppSecrets, error) {
|
||||
appEnvPath := path.Join(
|
||||
config.ABRA_DIR,
|
||||
"servers",
|
||||
internal.NewAppServer,
|
||||
fmt.Sprintf("%s.env", internal.Domain),
|
||||
)
|
||||
|
||||
appEnv, err := config.ReadEnv(appEnvPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secretEnvVars := secret.ReadSecretEnvVars(appEnv)
|
||||
secrets, err := secret.GenerateSecrets(cl, secretEnvVars, sanitisedAppName, internal.NewAppServer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if internal.Pass {
|
||||
for secretName := range secrets {
|
||||
secretValue := secrets[secretName]
|
||||
if err := secret.PassInsertSecret(
|
||||
secretValue,
|
||||
secretName,
|
||||
internal.Domain,
|
||||
internal.NewAppServer,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return secrets, nil
|
||||
}
|
||||
|
||||
// ensureDomainFlag checks if the domain flag was used. if not, asks the user for it/
|
||||
func ensureDomainFlag(recipe recipe.Recipe, server string) error {
|
||||
if internal.Domain == "" && !internal.NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "Specify app domain",
|
||||
Default: fmt.Sprintf("%s.%s", recipe.Name, server),
|
||||
}
|
||||
if err := survey.AskOne(prompt, &internal.Domain); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if internal.Domain == "" {
|
||||
return fmt.Errorf("no domain provided")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// promptForSecrets asks if we should generate secrets for a new app.
|
||||
func promptForSecrets(appName string) error {
|
||||
app, err := app.Get(appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secretEnvVars := secret.ReadSecretEnvVars(app.Env)
|
||||
if len(secretEnvVars) == 0 {
|
||||
logrus.Debugf("%s has no secrets to generate, skipping...", app.Recipe)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !internal.Secrets && !internal.NoInput {
|
||||
prompt := &survey.Confirm{
|
||||
Message: "Generate app secrets?",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &internal.Secrets); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureServerFlag checks if the server flag was used. if not, asks the user for it.
|
||||
func ensureServerFlag() error {
|
||||
servers, err := config.GetServers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if internal.NewAppServer == "" && !internal.NoInput {
|
||||
prompt := &survey.Select{
|
||||
Message: "Select app server:",
|
||||
Options: servers,
|
||||
}
|
||||
if err := survey.AskOne(prompt, &internal.NewAppServer); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if internal.NewAppServer == "" {
|
||||
return fmt.Errorf("no server provided")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"coopcloud.tech/abra/pkg/service"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/buger/goterm"
|
||||
|
@ -29,11 +30,13 @@ var appPsCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.WatchFlag,
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -43,11 +44,13 @@ flag.
|
|||
internal.ForceFlag,
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
if !internal.Force && !internal.NoInput {
|
||||
response := false
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
upstream "coopcloud.tech/abra/pkg/upstream/service"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -21,12 +22,14 @@ var appRestartCommand = cli.Command{
|
|||
ArgsUsage: "<domain>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `This command restarts a service within a deployed app.`,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
serviceNameShort := c.Args().Get(1)
|
||||
if serviceNameShort == "" {
|
||||
|
|
|
@ -35,6 +35,7 @@ var appRestoreCommand = cli.Command{
|
|||
ArgsUsage: "<domain> <service> <file>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
|
@ -55,8 +56,8 @@ Example:
|
|||
abra app restore example.com app ~/.abra/backups/example_com_app_609341138.tar.gz
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New()
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
|
@ -31,6 +31,7 @@ var appRollbackCommand = cli.Command{
|
|||
internal.ChaosFlag,
|
||||
internal.NoDomainChecksFlag,
|
||||
internal.DontWaitConvergeFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
@ -48,9 +49,9 @@ recipes.
|
|||
`,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
stackName := app.StackName()
|
||||
conf := runtime.New()
|
||||
|
||||
if !internal.Chaos {
|
||||
if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil {
|
||||
|
@ -83,7 +84,7 @@ recipes.
|
|||
logrus.Fatalf("%s is not deployed?", app.Name)
|
||||
}
|
||||
|
||||
catl, err := recipe.ReadRecipeCatalogue()
|
||||
catl, err := recipe.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
containerPkg "coopcloud.tech/abra/pkg/container"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"coopcloud.tech/abra/pkg/upstream/container"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -37,13 +38,15 @@ var appRunCommand = cli.Command{
|
|||
internal.DebugFlag,
|
||||
noTTYFlag,
|
||||
userFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "<domain> <service> <args>...",
|
||||
Usage: "Run a command in a service container",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
if len(c.Args()) < 2 {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no <service> provided?"))
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"coopcloud.tech/abra/pkg/secret"
|
||||
"github.com/docker/docker/api/types"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
|
@ -42,11 +43,13 @@ var appSecretGenerateCommand = cli.Command{
|
|||
internal.DebugFlag,
|
||||
allSecretsFlag,
|
||||
internal.PassFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
@ -121,6 +124,7 @@ var appSecretInsertCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.PassFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "<domain> <secret-name> <version> <data>",
|
||||
|
@ -138,7 +142,8 @@ Example:
|
|||
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
@ -198,6 +203,7 @@ var appSecretRmCommand = cli.Command{
|
|||
internal.NoInputFlag,
|
||||
rmAllSecretsFlag,
|
||||
internal.PassRemoveFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "<domain> [<secret-name>]",
|
||||
|
@ -210,7 +216,8 @@ Example:
|
|||
abra app secret remove myapp db_pass
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
secrets := secret.ReadSecretEnvVars(app.Env)
|
||||
|
||||
if c.Args().Get(1) != "" && rmAllSecrets {
|
||||
|
@ -288,11 +295,13 @@ var appSecretLsCommand = cli.Command{
|
|||
Aliases: []string{"ls"},
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List all secrets",
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
secrets := secret.ReadSecretEnvVars(app.Env)
|
||||
|
||||
tableCol := []string{"Name", "Version", "Generated Name", "Created On Server"}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"coopcloud.tech/abra/pkg/service"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -23,11 +24,13 @@ var appServicesCommand = cli.Command{
|
|||
ArgsUsage: "<domain>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
|
@ -86,6 +87,7 @@ var appUndeployCommand = cli.Command{
|
|||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
pruneFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Undeploy an app",
|
||||
|
@ -99,8 +101,10 @@ 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)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
stackName := app.StackName()
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
|
|
|
@ -30,6 +30,7 @@ var appUpgradeCommand = cli.Command{
|
|||
internal.ChaosFlag,
|
||||
internal.NoDomainChecksFlag,
|
||||
internal.DontWaitConvergeFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
@ -51,9 +52,9 @@ including unstaged changes and can be useful for live hacking and testing new
|
|||
recipes.
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
stackName := app.StackName()
|
||||
conf := runtime.New()
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
@ -86,7 +87,7 @@ recipes.
|
|||
logrus.Fatalf("%s is not deployed?", app.Name)
|
||||
}
|
||||
|
||||
catl, err := recipe.ReadRecipeCatalogue()
|
||||
catl, err := recipe.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ var appVersionCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Show app versions",
|
||||
|
@ -47,9 +48,9 @@ the individual image names, tags and digests. But also the Co-op Cloud recipe
|
|||
version.
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
stackName := app.StackName()
|
||||
conf := runtime.New()
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
|
@ -19,12 +20,14 @@ var appVolumeListCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List volumes associated with an app",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
@ -80,10 +83,12 @@ Passing "--force/-f" will select all volumes for removal. Be careful.
|
|||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.ForceFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
app := internal.ValidateApp(c, conf)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
|
|
|
@ -29,6 +29,7 @@ var catalogueGenerateCommand = cli.Command{
|
|||
internal.PublishFlag,
|
||||
internal.DryFlag,
|
||||
internal.SkipUpdatesFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
@ -54,18 +55,18 @@ keys configured on your account.
|
|||
`,
|
||||
ArgsUsage: "[<recipe>]",
|
||||
Action: func(c *cli.Context) error {
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
recipeName := c.Args().First()
|
||||
conf := runtime.New()
|
||||
|
||||
if recipeName != "" {
|
||||
internal.ValidateRecipe(c)
|
||||
internal.ValidateRecipe(c, conf)
|
||||
}
|
||||
|
||||
if err := catalogue.EnsureUpToDate(); err != nil {
|
||||
if err := catalogue.EnsureUpToDate(conf); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
repos, err := recipe.ReadReposMetadata()
|
||||
repos, err := recipe.ReadReposMetadata(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
@ -136,7 +137,7 @@ keys configured on your account.
|
|||
logrus.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
catlFS, err := recipe.ReadRecipeCatalogue()
|
||||
catlFS, err := recipe.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -253,6 +253,16 @@ var DebugFlag = &cli.BoolFlag{
|
|||
Usage: "Show DEBUG messages",
|
||||
}
|
||||
|
||||
// Offline stores the variable from OfflineFlag.
|
||||
var Offline bool
|
||||
|
||||
// DebugFlag turns on/off offline mode.
|
||||
var OfflineFlag = &cli.BoolFlag{
|
||||
Name: "offline, o",
|
||||
Destination: &Offline,
|
||||
Usage: "Prefer offline & filesystem access when possible",
|
||||
}
|
||||
|
||||
// MachineReadable stores the variable from MachineReadableFlag
|
||||
var MachineReadable bool
|
||||
|
||||
|
@ -270,7 +280,7 @@ var RC bool
|
|||
var RCFlag = &cli.BoolFlag{
|
||||
Name: "rc, r",
|
||||
Destination: &RC,
|
||||
Usage: "Insatll the latest release candidate",
|
||||
Usage: "Install the latest release candidate",
|
||||
}
|
||||
|
||||
var Major bool
|
||||
|
|
|
@ -1,199 +0,0 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"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"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// AppSecrets represents all app secrest
|
||||
type AppSecrets map[string]string
|
||||
|
||||
// RecipeName is used for configuring recipe name programmatically
|
||||
var RecipeName string
|
||||
|
||||
// createSecrets creates all secrets for a new app.
|
||||
func createSecrets(cl *dockerClient.Client, sanitisedAppName string) (AppSecrets, error) {
|
||||
appEnvPath := path.Join(config.ABRA_DIR, "servers", NewAppServer, fmt.Sprintf("%s.env", Domain))
|
||||
appEnv, err := config.ReadEnv(appEnvPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secretEnvVars := secret.ReadSecretEnvVars(appEnv)
|
||||
secrets, err := secret.GenerateSecrets(cl, secretEnvVars, sanitisedAppName, NewAppServer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if Pass {
|
||||
for secretName := range secrets {
|
||||
secretValue := secrets[secretName]
|
||||
if err := secret.PassInsertSecret(secretValue, secretName, Domain, NewAppServer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return secrets, nil
|
||||
}
|
||||
|
||||
// ensureDomainFlag checks if the domain flag was used. if not, asks the user for it/
|
||||
func ensureDomainFlag(recipe recipe.Recipe, server string) error {
|
||||
if Domain == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "Specify app domain",
|
||||
Default: fmt.Sprintf("%s.%s", recipe.Name, server),
|
||||
}
|
||||
if err := survey.AskOne(prompt, &Domain); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if Domain == "" {
|
||||
return fmt.Errorf("no domain provided")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// promptForSecrets asks if we should generate secrets for a new app.
|
||||
func promptForSecrets(appName string) error {
|
||||
app, err := app.Get(appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secretEnvVars := secret.ReadSecretEnvVars(app.Env)
|
||||
if len(secretEnvVars) == 0 {
|
||||
logrus.Debugf("%s has no secrets to generate, skipping...", app.Recipe)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !Secrets && !NoInput {
|
||||
prompt := &survey.Confirm{
|
||||
Message: "Generate app secrets?",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &Secrets); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureServerFlag checks if the server flag was used. if not, asks the user for it.
|
||||
func ensureServerFlag() error {
|
||||
servers, err := config.GetServers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if NewAppServer == "" && !NoInput {
|
||||
prompt := &survey.Select{
|
||||
Message: "Select app server:",
|
||||
Options: servers,
|
||||
}
|
||||
if err := survey.AskOne(prompt, &NewAppServer); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if NewAppServer == "" {
|
||||
return fmt.Errorf("no server provided")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewAction is the new app creation logic
|
||||
func NewAction(c *cli.Context) error {
|
||||
recipe := ValidateRecipeWithPrompt(c)
|
||||
conf := runtime.New()
|
||||
|
||||
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ensureServerFlag(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ensureDomainFlag(recipe, NewAppServer); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
sanitisedAppName := config.SanitiseAppName(Domain)
|
||||
logrus.Debugf("%s sanitised as %s for new app", Domain, sanitisedAppName)
|
||||
|
||||
if err := config.TemplateAppEnvSample(recipe.Name, Domain, NewAppServer, Domain); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := promptForSecrets(Domain); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
cl, err := client.New(NewAppServer)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
var secrets AppSecrets
|
||||
var secretTable *jsontable.JSONTable
|
||||
if Secrets {
|
||||
secrets, err := createSecrets(cl, sanitisedAppName)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
secretCols := []string{"Name", "Value"}
|
||||
secretTable = formatter.CreateTable(secretCols)
|
||||
for secret := range secrets {
|
||||
secretTable.Append([]string{secret, secrets[secret]})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if NewAppServer == "default" {
|
||||
NewAppServer = "local"
|
||||
}
|
||||
|
||||
tableCol := []string{"server", "recipe", "domain"}
|
||||
table := formatter.CreateTable(tableCol)
|
||||
table.Append([]string{NewAppServer, recipe.Name, Domain})
|
||||
|
||||
fmt.Println("")
|
||||
fmt.Println(fmt.Sprintf("A new %s app has been created! Here is an overview:", recipe.Name))
|
||||
fmt.Println("")
|
||||
table.Render()
|
||||
fmt.Println("")
|
||||
fmt.Println("You can configure this app by running the following:")
|
||||
fmt.Println(fmt.Sprintf("\n abra app config %s", Domain))
|
||||
fmt.Println("")
|
||||
fmt.Println("You can deploy this app by running the following:")
|
||||
fmt.Println(fmt.Sprintf("\n abra app deploy %s", Domain))
|
||||
fmt.Println("")
|
||||
|
||||
if len(secrets) > 0 {
|
||||
fmt.Println("Here are your generated secrets:")
|
||||
fmt.Println("")
|
||||
secretTable.Render()
|
||||
fmt.Println("")
|
||||
logrus.Warn("generated secrets are not shown again, please take note of them *now*")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -15,13 +15,9 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// AppName is used for configuring app name programmatically
|
||||
var AppName string
|
||||
|
||||
// ValidateRecipe ensures the recipe arg is valid.
|
||||
func ValidateRecipe(c *cli.Context, opts ...runtime.Option) recipe.Recipe {
|
||||
func ValidateRecipe(c *cli.Context, conf *runtime.Config) recipe.Recipe {
|
||||
recipeName := c.Args().First()
|
||||
conf := runtime.New(opts...)
|
||||
|
||||
if recipeName == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no recipe name provided"))
|
||||
|
@ -53,14 +49,13 @@ func ValidateRecipe(c *cli.Context, opts ...runtime.Option) recipe.Recipe {
|
|||
|
||||
// ValidateRecipeWithPrompt ensures a recipe argument is present before
|
||||
// validating, asking for input if required.
|
||||
func ValidateRecipeWithPrompt(c *cli.Context, opts ...runtime.Option) recipe.Recipe {
|
||||
func ValidateRecipeWithPrompt(c *cli.Context, conf *runtime.Config) recipe.Recipe {
|
||||
recipeName := c.Args().First()
|
||||
conf := runtime.New(opts...)
|
||||
|
||||
if recipeName == "" && !NoInput {
|
||||
var recipes []string
|
||||
|
||||
catl, err := recipe.ReadRecipeCatalogue()
|
||||
catl, err := recipe.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
@ -94,11 +89,6 @@ func ValidateRecipeWithPrompt(c *cli.Context, opts ...runtime.Option) recipe.Rec
|
|||
}
|
||||
}
|
||||
|
||||
if RecipeName != "" {
|
||||
recipeName = RecipeName
|
||||
logrus.Debugf("programmatically setting recipe name to %s", recipeName)
|
||||
}
|
||||
|
||||
if recipeName == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no recipe name provided"))
|
||||
}
|
||||
|
@ -118,14 +108,8 @@ func ValidateRecipeWithPrompt(c *cli.Context, opts ...runtime.Option) recipe.Rec
|
|||
}
|
||||
|
||||
// ValidateApp ensures the app name arg is valid.
|
||||
func ValidateApp(c *cli.Context, opts ...runtime.Option) config.App {
|
||||
func ValidateApp(c *cli.Context, conf *runtime.Config) config.App {
|
||||
appName := c.Args().First()
|
||||
conf := runtime.New(opts...)
|
||||
|
||||
if AppName != "" {
|
||||
appName = AppName
|
||||
logrus.Debugf("programmatically setting app name to %s", appName)
|
||||
}
|
||||
|
||||
if appName == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no app provided"))
|
||||
|
|
|
@ -17,19 +17,20 @@ var recipeFetchCommand = cli.Command{
|
|||
Description: "Fetchs all recipes without arguments.",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
recipeName := c.Args().First()
|
||||
conf := runtime.New()
|
||||
|
||||
if recipeName != "" {
|
||||
internal.ValidateRecipe(c)
|
||||
internal.ValidateRecipe(c, conf)
|
||||
return nil // ValidateRecipe ensures latest checkout
|
||||
}
|
||||
|
||||
repos, err := recipe.ReadReposMetadata()
|
||||
repos, err := recipe.ReadReposMetadata(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -21,12 +21,13 @@ var recipeLintCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OnlyErrorFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipe(c)
|
||||
conf := runtime.New()
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
recipe := internal.ValidateRecipe(c, conf)
|
||||
|
||||
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
|
||||
logrus.Fatal(err)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
@ -29,10 +30,13 @@ var recipeListCommand = cli.Command{
|
|||
internal.DebugFlag,
|
||||
internal.MachineReadableFlag,
|
||||
patternFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
catl, err := recipe.ReadRecipeCatalogue()
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
|
||||
catl, err := recipe.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err.Error())
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ var recipeNewCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Create a new recipe",
|
||||
|
|
|
@ -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"
|
||||
|
@ -54,11 +55,13 @@ your SSH keys configured on your account.
|
|||
internal.MinorFlag,
|
||||
internal.PatchFlag,
|
||||
internal.PublishFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipeWithPrompt(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
recipe := internal.ValidateRecipeWithPrompt(c, conf)
|
||||
|
||||
imagesTmp, err := getImageVersions(recipe)
|
||||
if err != nil {
|
||||
|
|
|
@ -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"
|
||||
|
@ -28,6 +29,7 @@ var recipeSyncCommand = cli.Command{
|
|||
internal.MajorFlag,
|
||||
internal.MinorFlag,
|
||||
internal.PatchFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
@ -41,7 +43,8 @@ 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)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
recipe := internal.ValidateRecipeWithPrompt(c, conf)
|
||||
|
||||
mainApp, err := internal.GetMainAppImage(recipe)
|
||||
if err != nil {
|
||||
|
|
|
@ -68,11 +68,12 @@ You may invoke this command in "wizard" mode and be prompted for input:
|
|||
internal.MajorFlag,
|
||||
internal.MachineReadableFlag,
|
||||
internal.AllTagsFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipeWithPrompt(c)
|
||||
conf := runtime.New()
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
recipe := internal.ValidateRecipeWithPrompt(c, conf)
|
||||
|
||||
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
|
||||
logrus.Fatal(err)
|
||||
|
@ -184,7 +185,7 @@ You may invoke this command in "wizard" mode and be prompted for input:
|
|||
continue // skip on to the next tag and don't update any compose files
|
||||
}
|
||||
|
||||
catlVersions, err := recipePkg.VersionsOfService(recipe.Name, service.Name)
|
||||
catlVersions, err := recipePkg.VersionsOfService(recipe.Name, service.Name, conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
@ -16,13 +17,15 @@ var recipeVersionCommand = cli.Command{
|
|||
ArgsUsage: "<recipe>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipe(c)
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
recipe := internal.ValidateRecipe(c, conf)
|
||||
|
||||
catalogue, err := recipePkg.ReadRecipeCatalogue()
|
||||
catalogue, err := recipePkg.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ var RecordListCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.DNSProviderFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
|
|
@ -30,6 +30,7 @@ var RecordNewCommand = cli.Command{
|
|||
internal.DNSValueFlag,
|
||||
internal.DNSTTLFlag,
|
||||
internal.DNSPriorityFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
|
|
@ -27,6 +27,7 @@ var RecordRemoveCommand = cli.Command{
|
|||
internal.DNSProviderFlag,
|
||||
internal.DNSTypeFlag,
|
||||
internal.DNSNameFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
|
|
@ -118,6 +118,7 @@ developer machine.
|
|||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
localFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "<domain>",
|
||||
|
|
|
@ -28,6 +28,7 @@ var serverListCommand = cli.Command{
|
|||
problemsFilterFlag,
|
||||
internal.DebugFlag,
|
||||
internal.MachineReadableFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
|
|
|
@ -222,6 +222,7 @@ API tokens are read from the environment if specified, e.g.
|
|||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.ServerProviderFlag,
|
||||
internal.OfflineFlag,
|
||||
|
||||
// Capsul
|
||||
internal.CapsulInstanceURLFlag,
|
||||
|
|
|
@ -43,6 +43,7 @@ also be removed. This can result in unwanted data loss if not used carefully.
|
|||
allFilterFlag,
|
||||
volumesFilterFlag,
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.ServerNameComplete,
|
||||
|
|
|
@ -120,6 +120,7 @@ like tears in rain.
|
|||
internal.NoInputFlag,
|
||||
rmServerFlag,
|
||||
internal.ServerProviderFlag,
|
||||
internal.OfflineFlag,
|
||||
|
||||
// Hetzner
|
||||
internal.HetznerCloudNameFlag,
|
||||
|
|
|
@ -49,6 +49,7 @@ var Notify = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
majorFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
@ -57,6 +58,8 @@ catalogue. If a new patch/minor version is available, a notification is
|
|||
printed. To include major versions use the --major flag.
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
|
||||
cl, err := client.New("default")
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
|
@ -75,7 +78,7 @@ printed. To include major versions use the --major flag.
|
|||
}
|
||||
|
||||
if recipeName != "" {
|
||||
_, err = getLatestUpgrade(cl, stackName, recipeName)
|
||||
_, err = getLatestUpgrade(cl, stackName, recipeName, conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
@ -97,6 +100,7 @@ var UpgradeApp = cli.Command{
|
|||
internal.ChaosFlag,
|
||||
majorFlag,
|
||||
allFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
|
@ -109,13 +113,13 @@ break things. Only apps that are not deployed with "--chaos" are upgraded, to
|
|||
update chaos deployments use the "--chaos" flag. Use it with care.
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
conf := runtime.New(runtime.WithOffline(internal.Offline))
|
||||
|
||||
cl, err := client.New("default")
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
conf := runtime.New()
|
||||
|
||||
if !updateAll {
|
||||
stackName := c.Args().Get(0)
|
||||
recipeName := c.Args().Get(1)
|
||||
|
@ -223,13 +227,14 @@ func getEnv(cl *dockerclient.Client, stackName string) (config.AppEnv, error) {
|
|||
|
||||
// getLatestUpgrade returns the latest available version for an app respecting
|
||||
// the "--major" flag if it is newer than the currently deployed version.
|
||||
func getLatestUpgrade(cl *dockerclient.Client, stackName string, recipeName string) (string, error) {
|
||||
func getLatestUpgrade(cl *dockerclient.Client, stackName string,
|
||||
recipeName string, conf *runtime.Config) (string, error) {
|
||||
deployedVersion, err := getDeployedVersion(cl, stackName, recipeName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
availableUpgrades, err := getAvailableUpgrades(cl, stackName, recipeName, deployedVersion)
|
||||
availableUpgrades, err := getAvailableUpgrades(cl, stackName, recipeName, deployedVersion, conf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -272,8 +277,8 @@ func getDeployedVersion(cl *dockerclient.Client, stackName string, recipeName st
|
|||
// than the deployed version. It only includes major upgrades if the "--major"
|
||||
// flag is set.
|
||||
func getAvailableUpgrades(cl *dockerclient.Client, stackName string, recipeName string,
|
||||
deployedVersion string) ([]string, error) {
|
||||
catl, err := recipe.ReadRecipeCatalogue()
|
||||
deployedVersion string, conf *runtime.Config) ([]string, error) {
|
||||
catl, err := recipe.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -389,7 +394,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, recipeName string, conf *runtime.Config) error {
|
||||
if recipeName == "" {
|
||||
logrus.Debugf("Don't update %s due to missing recipe name", stackName)
|
||||
logrus.Debugf("don't update %s due to missing recipe name", stackName)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -399,7 +404,7 @@ func tryUpgrade(cl *dockerclient.Client, stackName, recipeName string, conf *run
|
|||
}
|
||||
|
||||
if chaos && !internal.Chaos {
|
||||
logrus.Debugf("Don't update %s due to chaos deployment.", stackName)
|
||||
logrus.Debugf("don't update %s due to chaos deployment", stackName)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -409,17 +414,17 @@ func tryUpgrade(cl *dockerclient.Client, stackName, recipeName string, conf *run
|
|||
}
|
||||
|
||||
if !updatesEnabled {
|
||||
logrus.Debugf("Don't update %s due to disabled auto updates or missing ENABLE_AUTO_UPDATE env.", stackName)
|
||||
logrus.Debugf("don't update %s due to disabled auto updates or missing ENABLE_AUTO_UPDATE env", stackName)
|
||||
return nil
|
||||
}
|
||||
|
||||
upgradeVersion, err := getLatestUpgrade(cl, stackName, recipeName)
|
||||
upgradeVersion, err := getLatestUpgrade(cl, stackName, recipeName, conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if upgradeVersion == "" {
|
||||
logrus.Debugf("Don't update %s due to no new version.", stackName)
|
||||
logrus.Debugf("don't update %s due to no new version", stackName)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -429,7 +434,8 @@ func tryUpgrade(cl *dockerclient.Client, stackName, recipeName string, conf *run
|
|||
}
|
||||
|
||||
// upgrade performs all necessary steps to upgrade an app.
|
||||
func upgrade(cl *dockerclient.Client, stackName, recipeName, upgradeVersion string, conf *runtime.Config) error {
|
||||
func upgrade(cl *dockerclient.Client, stackName, recipeName,
|
||||
upgradeVersion string, conf *runtime.Config) error {
|
||||
env, err := getEnv(cl, stackName)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -455,7 +461,7 @@ func upgrade(cl *dockerclient.Client, stackName, recipeName, upgradeVersion stri
|
|||
return err
|
||||
}
|
||||
|
||||
logrus.Infof("Upgrade %s (%s) to version %s", stackName, recipeName, upgradeVersion)
|
||||
logrus.Infof("upgrade %s (%s) to version %s", stackName, recipeName, upgradeVersion)
|
||||
|
||||
err = stack.RunDeploy(cl, deployOpts, compose, stackName, true)
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
@ -27,7 +28,12 @@ func AppNameComplete(c *cli.Context) {
|
|||
|
||||
// RecipeNameComplete completes recipe names.
|
||||
func RecipeNameComplete(c *cli.Context) {
|
||||
catl, err := recipe.ReadRecipeCatalogue()
|
||||
// defaults since we can't take arguments here... this means auto-completion
|
||||
// of recipe names always access the network if e.g. the catalogue needs
|
||||
// cloning / updating
|
||||
conf := runtime.New()
|
||||
|
||||
catl, err := recipe.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
gitPkg "coopcloud.tech/abra/pkg/git"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -52,9 +53,13 @@ var CatalogueSkipList = map[string]bool{
|
|||
}
|
||||
|
||||
// EnsureCatalogue ensures that the catalogue is cloned locally & present.
|
||||
func EnsureCatalogue() error {
|
||||
func EnsureCatalogue(conf *runtime.Config) error {
|
||||
catalogueDir := path.Join(config.ABRA_DIR, "catalogue")
|
||||
if _, err := os.Stat(catalogueDir); err != nil && os.IsNotExist(err) {
|
||||
if conf.Offline {
|
||||
return fmt.Errorf("no local copy of the catalogue available, network access required")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, config.CATALOGUE_JSON_REPO_NAME)
|
||||
if err := gitPkg.Clone(catalogueDir, url); err != nil {
|
||||
return err
|
||||
|
@ -68,7 +73,7 @@ func EnsureCatalogue() error {
|
|||
|
||||
// EnsureUpToDate ensures that the local catalogue has no unstaged changes as
|
||||
// is up to date. This is useful to run before doing catalogue generation.
|
||||
func EnsureUpToDate() error {
|
||||
func EnsureUpToDate(conf *runtime.Config) error {
|
||||
isClean, err := gitPkg.IsClean(config.CATALOGUE_DIR)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -79,6 +84,11 @@ func EnsureUpToDate() error {
|
|||
return fmt.Errorf(msg, config.CATALOGUE_DIR)
|
||||
}
|
||||
|
||||
if conf.Offline {
|
||||
logrus.Debug("attempting to use local catalogue without access network (\"--offline\")")
|
||||
return nil
|
||||
}
|
||||
|
||||
repo, err := git.PlainOpen(config.CATALOGUE_DIR)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
||||
"coopcloud.tech/abra/pkg/runtime"
|
||||
"coopcloud.tech/tagcmp"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/go-git/go-git/v5"
|
||||
|
@ -333,7 +334,11 @@ func LintImagePresent(recipe recipe.Recipe) (bool, error) {
|
|||
}
|
||||
|
||||
func LintHasPublishedVersion(recipe recipe.Recipe) (bool, error) {
|
||||
catl, err := recipePkg.ReadRecipeCatalogue()
|
||||
// defaults since we can't take arguments here... this means this lint rule
|
||||
// always access the network if e.g. the catalogue needs cloning / updating
|
||||
conf := runtime.New()
|
||||
|
||||
catl, err := recipePkg.ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -252,13 +252,13 @@ func Get(recipeName string, conf *runtime.Config) (Recipe, error) {
|
|||
|
||||
// EnsureExists ensures that a recipe is locally cloned
|
||||
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) {
|
||||
if conf.Offline {
|
||||
return fmt.Errorf("no local copy of %s available, network access required", recipeName)
|
||||
}
|
||||
|
||||
logrus.Debugf("%s does not exist, attemmpting to clone", recipeDir)
|
||||
url := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, recipeName)
|
||||
if err := gitPkg.Clone(recipeDir, url); err != nil {
|
||||
|
@ -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)
|
||||
|
@ -588,10 +584,6 @@ 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
|
||||
}
|
||||
|
||||
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
|
||||
|
||||
isClean, err := gitPkg.IsClean(recipeDir)
|
||||
|
@ -604,6 +596,11 @@ func EnsureUpToDate(recipeName string, conf *runtime.Config) error {
|
|||
return fmt.Errorf(msg, recipeName, recipeDir)
|
||||
}
|
||||
|
||||
if conf.Offline {
|
||||
logrus.Debug("attempting to use local recipe without access network (\"--offline\")")
|
||||
return nil
|
||||
}
|
||||
|
||||
repo, err := git.PlainOpen(recipeDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to open %s: %s", recipeDir, err)
|
||||
|
@ -659,14 +656,14 @@ func EnsureUpToDate(recipeName string, conf *runtime.Config) error {
|
|||
}
|
||||
|
||||
// ReadRecipeCatalogue reads the recipe catalogue.
|
||||
func ReadRecipeCatalogue() (RecipeCatalogue, error) {
|
||||
func ReadRecipeCatalogue(conf *runtime.Config) (RecipeCatalogue, error) {
|
||||
recipes := make(RecipeCatalogue)
|
||||
|
||||
if err := catalogue.EnsureCatalogue(); err != nil {
|
||||
if err := catalogue.EnsureCatalogue(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := catalogue.EnsureUpToDate(); err != nil {
|
||||
if err := catalogue.EnsureUpToDate(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -694,10 +691,10 @@ func readRecipeCatalogueFS(target interface{}) error {
|
|||
}
|
||||
|
||||
// VersionsOfService lists the version of a service.
|
||||
func VersionsOfService(recipe, serviceName string) ([]string, error) {
|
||||
func VersionsOfService(recipe, serviceName string, conf *runtime.Config) ([]string, error) {
|
||||
var versions []string
|
||||
|
||||
catalogue, err := ReadRecipeCatalogue()
|
||||
catalogue, err := ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -724,7 +721,7 @@ func VersionsOfService(recipe, serviceName string) ([]string, error) {
|
|||
|
||||
// GetRecipeMeta retrieves the recipe metadata from the recipe catalogue.
|
||||
func GetRecipeMeta(recipeName string, conf *runtime.Config) (RecipeMeta, error) {
|
||||
catl, err := ReadRecipeCatalogue()
|
||||
catl, err := ReadRecipeCatalogue(conf)
|
||||
if err != nil {
|
||||
return RecipeMeta{}, err
|
||||
}
|
||||
|
@ -821,7 +818,11 @@ type InternalTracker struct {
|
|||
type RepoCatalogue map[string]RepoMeta
|
||||
|
||||
// ReadReposMetadata retrieves coop-cloud/... repo metadata from Gitea.
|
||||
func ReadReposMetadata() (RepoCatalogue, error) {
|
||||
func ReadReposMetadata(conf *runtime.Config) (RepoCatalogue, error) {
|
||||
if conf.Offline {
|
||||
return nil, fmt.Errorf("network access required to query recipes metadata")
|
||||
}
|
||||
|
||||
reposMeta := make(RepoCatalogue)
|
||||
|
||||
pageIdx := 1
|
||||
|
@ -1002,6 +1003,10 @@ 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 {
|
||||
if conf.Offline {
|
||||
return fmt.Errorf("network access required to update recipes")
|
||||
}
|
||||
|
||||
var barLength int
|
||||
if recipeName != "" {
|
||||
barLength = 1
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package runtime
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
type Config struct {
|
||||
Offline bool
|
||||
}
|
||||
|
||||
type Option func(c *Config)
|
||||
|
||||
func New(opts ...Option) *Config {
|
||||
conf := &Config{Offline: false}
|
||||
|
||||
for _, optFunc := range opts {
|
||||
optFunc(conf)
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
||||
func WithOffline(offline bool) Option {
|
||||
return func(c *Config) {
|
||||
if offline {
|
||||
logrus.Debugf("runtime config: attempting to run in offline mode")
|
||||
}
|
||||
c.Offline = offline
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
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 modifies a Config. The convention for passing an Option to a function
|
||||
// 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 Config.
|
||||
func New(opts ...Option) *Config {
|
||||
conf := &Config{
|
||||
EnsureRecipeExists: true,
|
||||
EnsureRecipeLatest: 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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue