Compare commits
16 Commits
0.4.0-alph
...
0.4.0-alph
Author | SHA1 | Date | |
---|---|---|---|
cff7534bf9
|
|||
13e582349c
|
|||
b1b9612e01
|
|||
afeee1270e
|
|||
cb210d0c81
|
|||
9f2bb3f74f
|
|||
a33767f848
|
|||
a1abe5c6be
|
|||
672b44f965
|
|||
6d9573ec7e
|
|||
53cd3b8b71
|
|||
b9ec41647b
|
|||
f4b563528f
|
|||
f9a2c1d58f
|
|||
7a66a90ecb
|
|||
0e688f1407
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,4 +4,5 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
abra
|
abra
|
||||||
dist/
|
dist/
|
||||||
|
tests/integration/.abra/catalogue
|
||||||
vendor/
|
vendor/
|
||||||
|
12
Makefile
12
Makefile
@ -43,15 +43,3 @@ loc-author:
|
|||||||
sort -f | \
|
sort -f | \
|
||||||
uniq -ic | \
|
uniq -ic | \
|
||||||
sort -n
|
sort -n
|
||||||
|
|
||||||
int-core:
|
|
||||||
@docker run \
|
|
||||||
-v $$(pwd):/src \
|
|
||||||
--env-file .e2e.env \
|
|
||||||
debian:bullseye-slim \
|
|
||||||
sh -c "\
|
|
||||||
apt update && apt install -y wget curl git; echo ""; echo ""; \
|
|
||||||
git config --global user.email 'e2e@coopcloud.tech'; \
|
|
||||||
git config --global user.name 'e2e'; \
|
|
||||||
cd /src/tests/integration && bash core.sh -- --dev \
|
|
||||||
"
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
The Co-op Cloud utility belt 🎩🐇
|
The Co-op Cloud utility belt 🎩🐇
|
||||||
|
|
||||||
`abra` is a command-line tool for managing your own [Co-op Cloud](https://coopcloud.tech). It can provision new servers, create apps, deploy them, run backup and restore operations and a whole lot of other things. Please see [docs.coopcloud.tech](https://docs.coopcloud.tech) for more extensive documentation.
|
`abra` is a command-line tool for managing your own [Co-op Cloud](https://coopcloud.tech). It can provision new servers, create apps, deploy them and a whole lot of other things. Please see [docs.coopcloud.tech](https://docs.coopcloud.tech) for more extensive documentation.
|
||||||
|
|
||||||
## Quick install
|
## Quick install
|
||||||
|
|
||||||
|
@ -1,29 +1,22 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AppCommand defines the `abra app` command and ets subcommands
|
var AppCommand = cli.Command{
|
||||||
var AppCommand = &cli.Command{
|
|
||||||
Name: "app",
|
Name: "app",
|
||||||
Usage: "Manage apps",
|
|
||||||
Aliases: []string{"a"},
|
Aliases: []string{"a"},
|
||||||
|
Usage: "Manage apps",
|
||||||
ArgsUsage: "<app>",
|
ArgsUsage: "<app>",
|
||||||
Description: `
|
Description: "This command provides functionality for managing the life cycle of your apps",
|
||||||
This command provides all the functionality you need to manage the life cycle
|
Subcommands: []cli.Command{
|
||||||
of your apps. From initial deployment, day-2 operations (e.g. backup/restore)
|
|
||||||
to scaling apps up and spinning them down.
|
|
||||||
`,
|
|
||||||
Subcommands: []*cli.Command{
|
|
||||||
appNewCommand,
|
appNewCommand,
|
||||||
appConfigCommand,
|
appConfigCommand,
|
||||||
appRestartCommand,
|
appRestartCommand,
|
||||||
appDeployCommand,
|
appDeployCommand,
|
||||||
appUpgradeCommand,
|
appUpgradeCommand,
|
||||||
appUndeployCommand,
|
appUndeployCommand,
|
||||||
appBackupCommand,
|
|
||||||
appRestoreCommand,
|
|
||||||
appRemoveCommand,
|
appRemoveCommand,
|
||||||
appCheckCommand,
|
appCheckCommand,
|
||||||
appListCommand,
|
appListCommand,
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"coopcloud.tech/abra/cli/internal"
|
|
||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
|
||||||
"coopcloud.tech/abra/pkg/config"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var backupAllServices bool
|
|
||||||
var backupAllServicesFlag = &cli.BoolFlag{
|
|
||||||
Name: "all",
|
|
||||||
Value: false,
|
|
||||||
Destination: &backupAllServices,
|
|
||||||
Aliases: []string{"a"},
|
|
||||||
Usage: "Backup all services",
|
|
||||||
}
|
|
||||||
|
|
||||||
var appBackupCommand = &cli.Command{
|
|
||||||
Name: "backup",
|
|
||||||
Usage: "Backup an app",
|
|
||||||
Aliases: []string{"b"},
|
|
||||||
Flags: []cli.Flag{backupAllServicesFlag},
|
|
||||||
ArgsUsage: "<service>",
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
app := internal.ValidateApp(c)
|
|
||||||
|
|
||||||
if c.Args().Get(1) != "" && backupAllServices {
|
|
||||||
internal.ShowSubcommandHelpAndError(c, errors.New("cannot use '<service>' and '--all' together"))
|
|
||||||
}
|
|
||||||
|
|
||||||
abraSh := path.Join(config.RECIPES_DIR, app.Type, "abra.sh")
|
|
||||||
if _, err := os.Stat(abraSh); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
logrus.Fatalf("%s does not exist?", abraSh)
|
|
||||||
}
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceCmd := fmt.Sprintf("source %s", abraSh)
|
|
||||||
|
|
||||||
execCmd := "abra_backup"
|
|
||||||
if !backupAllServices {
|
|
||||||
serviceName := c.Args().Get(1)
|
|
||||||
if serviceName == "" {
|
|
||||||
internal.ShowSubcommandHelpAndError(c, errors.New("no service(s) target provided"))
|
|
||||||
}
|
|
||||||
execCmd = fmt.Sprintf("abra_backup_%s", serviceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes, err := ioutil.ReadFile(abraSh)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
if !strings.Contains(string(bytes), execCmd) {
|
|
||||||
logrus.Fatalf("%s doesn't have a %s function", app.Type, execCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceAndExec := fmt.Sprintf("%s; %s", sourceCmd, execCmd)
|
|
||||||
cmd := exec.Command("bash", "-c", sourceAndExec)
|
|
||||||
if err := internal.RunCmd(cmd); err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
|
||||||
}
|
|
@ -9,14 +9,19 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
"coopcloud.tech/abra/pkg/autocomplete"
|
||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appCheckCommand = &cli.Command{
|
var appCheckCommand = cli.Command{
|
||||||
Name: "check",
|
Name: "check",
|
||||||
Usage: "Check if app is configured correctly",
|
|
||||||
Aliases: []string{"c"},
|
Aliases: []string{"c"},
|
||||||
|
Usage: "Check if app is configured correctly",
|
||||||
ArgsUsage: "<service>",
|
ArgsUsage: "<service>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
|
|
||||||
|
@ -10,13 +10,18 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appConfigCommand = &cli.Command{
|
var appConfigCommand = cli.Command{
|
||||||
Name: "config",
|
Name: "config",
|
||||||
Aliases: []string{"c"},
|
Aliases: []string{"c"},
|
||||||
Usage: "Edit app config",
|
Usage: "Edit app config",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
appName := c.Args().First()
|
appName := c.Args().First()
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@ -15,13 +16,18 @@ import (
|
|||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appCpCommand = &cli.Command{
|
var appCpCommand = cli.Command{
|
||||||
Name: "cp",
|
Name: "cp",
|
||||||
Aliases: []string{"c"},
|
Aliases: []string{"c"},
|
||||||
ArgsUsage: "<src> <dst>",
|
ArgsUsage: "<src> <dst>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Usage: "Copy files to/from a running app service",
|
Usage: "Copy files to/from a running app service",
|
||||||
Description: `
|
Description: `
|
||||||
This command supports copying files to and from any app service file system.
|
This command supports copying files to and from any app service file system.
|
||||||
@ -118,7 +124,7 @@ func configureAndCp(
|
|||||||
filters := filters.NewArgs()
|
filters := filters.NewArgs()
|
||||||
filters.Add("name", fmt.Sprintf("%s_%s", appEnv.StackName(), service))
|
filters.Add("name", fmt.Sprintf("%s_%s", appEnv.StackName(), service))
|
||||||
|
|
||||||
container, err := container.GetContainer(c.Context, cl, filters, true)
|
container, err := container.GetContainer(context.Background(), cl, filters, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -137,11 +143,11 @@ func configureAndCp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
copyOpts := types.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false}
|
copyOpts := types.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false}
|
||||||
if err := cl.CopyToContainer(c.Context, container.ID, dstPath, content, copyOpts); err != nil {
|
if err := cl.CopyToContainer(context.Background(), container.ID, dstPath, content, copyOpts); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
content, _, err := cl.CopyFromContainer(c.Context, container.ID, srcPath)
|
content, _, err := cl.CopyFromContainer(context.Background(), container.ID, srcPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,22 @@ package app
|
|||||||
import (
|
import (
|
||||||
"coopcloud.tech/abra/cli/internal"
|
"coopcloud.tech/abra/cli/internal"
|
||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
"coopcloud.tech/abra/pkg/autocomplete"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appDeployCommand = &cli.Command{
|
var appDeployCommand = cli.Command{
|
||||||
Name: "deploy",
|
Name: "deploy",
|
||||||
Aliases: []string{"d"},
|
Aliases: []string{"d"},
|
||||||
Usage: "Deploy an app",
|
Usage: "Deploy an app",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.ForceFlag,
|
internal.ForceFlag,
|
||||||
internal.ChaosFlag,
|
internal.ChaosFlag,
|
||||||
internal.NoDomainChecksFlag,
|
internal.NoDomainChecksFlag,
|
||||||
internal.DontWaitConvergeFlag,
|
internal.DontWaitConvergeFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Description: `
|
Description: `
|
||||||
This command deploys an app. It does not support incrementing the version of a
|
This command deploys an app. It does not support incrementing the version of a
|
||||||
deployed app, for this you need to look at the "abra app upgrade <app>"
|
deployed app, for this you need to look at the "abra app upgrade <app>"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -15,10 +16,10 @@ import (
|
|||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
dockerClient "github.com/docker/docker/client"
|
dockerClient "github.com/docker/docker/client"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appErrorsCommand = &cli.Command{
|
var appErrorsCommand = cli.Command{
|
||||||
Name: "errors",
|
Name: "errors",
|
||||||
Usage: "List errors for a deployed app",
|
Usage: "List errors for a deployed app",
|
||||||
Description: `
|
Description: `
|
||||||
@ -45,7 +46,12 @@ the logs.
|
|||||||
|
|
||||||
`,
|
`,
|
||||||
Aliases: []string{"e"},
|
Aliases: []string{"e"},
|
||||||
Flags: []cli.Flag{internal.WatchFlag},
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
internal.WatchFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
@ -55,7 +61,7 @@ the logs.
|
|||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
isDeployed, _, err := stack.IsDeployed(c.Context, cl, app.StackName())
|
isDeployed, _, err := stack.IsDeployed(context.Background(), cl, app.StackName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -91,7 +97,7 @@ func checkErrors(c *cli.Context, cl *dockerClient.Client, app config.App) error
|
|||||||
for _, service := range recipe.Config.Services {
|
for _, service := range recipe.Config.Services {
|
||||||
filters := filters.NewArgs()
|
filters := filters.NewArgs()
|
||||||
filters.Add("name", service.Name)
|
filters.Add("name", service.Name)
|
||||||
containers, err := cl.ContainerList(c.Context, types.ContainerListOptions{Filters: filters})
|
containers, err := cl.ContainerList(context.Background(), types.ContainerListOptions{Filters: filters})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -102,7 +108,7 @@ func checkErrors(c *cli.Context, cl *dockerClient.Client, app config.App) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
container := containers[0]
|
container := containers[0]
|
||||||
containerState, err := cl.ContainerInspect(c.Context, container.ID)
|
containerState, err := cl.ContainerInspect(context.Background(), container.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -12,22 +12,19 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/ssh"
|
"coopcloud.tech/abra/pkg/ssh"
|
||||||
"coopcloud.tech/tagcmp"
|
"coopcloud.tech/tagcmp"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var status bool
|
var status bool
|
||||||
var statusFlag = &cli.BoolFlag{
|
var statusFlag = &cli.BoolFlag{
|
||||||
Name: "status",
|
Name: "status, S",
|
||||||
Aliases: []string{"S"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Show app deployment status",
|
Usage: "Show app deployment status",
|
||||||
Destination: &status,
|
Destination: &status,
|
||||||
}
|
}
|
||||||
|
|
||||||
var appType string
|
var appType string
|
||||||
var typeFlag = &cli.StringFlag{
|
var typeFlag = &cli.StringFlag{
|
||||||
Name: "type",
|
Name: "type, t",
|
||||||
Aliases: []string{"t"},
|
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Show apps of a specific type",
|
Usage: "Show apps of a specific type",
|
||||||
Destination: &appType,
|
Destination: &appType,
|
||||||
@ -35,8 +32,7 @@ var typeFlag = &cli.StringFlag{
|
|||||||
|
|
||||||
var listAppServer string
|
var listAppServer string
|
||||||
var listAppServerFlag = &cli.StringFlag{
|
var listAppServerFlag = &cli.StringFlag{
|
||||||
Name: "server",
|
Name: "server, s",
|
||||||
Aliases: []string{"s"},
|
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Show apps of a specific server",
|
Usage: "Show apps of a specific server",
|
||||||
Destination: &listAppServer,
|
Destination: &listAppServer,
|
||||||
@ -61,8 +57,9 @@ type serverStatus struct {
|
|||||||
upgradeCount int
|
upgradeCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
var appListCommand = &cli.Command{
|
var appListCommand = cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
|
Aliases: []string{"ls"},
|
||||||
Usage: "List all managed apps",
|
Usage: "List all managed apps",
|
||||||
Description: `
|
Description: `
|
||||||
This command looks at your local file system listing of apps and servers (e.g.
|
This command looks at your local file system listing of apps and servers (e.g.
|
||||||
@ -72,12 +69,14 @@ By passing the "--status/-S" flag, you can query all your servers for the
|
|||||||
actual live deployment status. Depending on how many servers you manage, this
|
actual live deployment status. Depending on how many servers you manage, this
|
||||||
can take some time.
|
can take some time.
|
||||||
`,
|
`,
|
||||||
Aliases: []string{"ls"},
|
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
statusFlag,
|
statusFlag,
|
||||||
listAppServerFlag,
|
listAppServerFlag,
|
||||||
typeFlag,
|
typeFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
appFiles, err := config.LoadAppFiles(listAppServer)
|
appFiles, err := config.LoadAppFiles(listAppServer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -145,8 +144,10 @@ can take some time.
|
|||||||
version := "unknown"
|
version := "unknown"
|
||||||
if statusMeta, ok := statuses[app.StackName()]; ok {
|
if statusMeta, ok := statuses[app.StackName()]; ok {
|
||||||
if currentVersion, exists := statusMeta["version"]; exists {
|
if currentVersion, exists := statusMeta["version"]; exists {
|
||||||
|
if currentVersion != "" {
|
||||||
version = currentVersion
|
version = currentVersion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if statusMeta["status"] != "" {
|
if statusMeta["status"] != "" {
|
||||||
status = statusMeta["status"]
|
status = statusMeta["status"]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@ -15,7 +16,7 @@ import (
|
|||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
dockerClient "github.com/docker/docker/client"
|
dockerClient "github.com/docker/docker/client"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logOpts = types.ContainerLogsOptions{
|
var logOpts = types.ContainerLogsOptions{
|
||||||
@ -32,7 +33,7 @@ func stackLogs(c *cli.Context, stackName string, client *dockerClient.Client) {
|
|||||||
filters := filters.NewArgs()
|
filters := filters.NewArgs()
|
||||||
filters.Add("name", stackName)
|
filters.Add("name", stackName)
|
||||||
serviceOpts := types.ServiceListOptions{Filters: filters}
|
serviceOpts := types.ServiceListOptions{Filters: filters}
|
||||||
services, err := client.ServiceList(c.Context, serviceOpts)
|
services, err := client.ServiceList(context.Background(), serviceOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -45,7 +46,7 @@ func stackLogs(c *cli.Context, stackName string, client *dockerClient.Client) {
|
|||||||
logOpts.ShowStdout = false
|
logOpts.ShowStdout = false
|
||||||
}
|
}
|
||||||
|
|
||||||
logs, err := client.ServiceLogs(c.Context, s, logOpts)
|
logs, err := client.ServiceLogs(context.Background(), s, logOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -63,14 +64,17 @@ func stackLogs(c *cli.Context, stackName string, client *dockerClient.Client) {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var appLogsCommand = &cli.Command{
|
var appLogsCommand = cli.Command{
|
||||||
Name: "logs",
|
Name: "logs",
|
||||||
Aliases: []string{"l"},
|
Aliases: []string{"l"},
|
||||||
ArgsUsage: "[<service>]",
|
ArgsUsage: "[<service>]",
|
||||||
Usage: "Tail app logs",
|
Usage: "Tail app logs",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
internal.StdErrOnlyFlag,
|
internal.StdErrOnlyFlag,
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
@ -98,7 +102,7 @@ var appLogsCommand = &cli.Command{
|
|||||||
func tailServiceLogs(c *cli.Context, cl *dockerClient.Client, app config.App, serviceName string) error {
|
func tailServiceLogs(c *cli.Context, cl *dockerClient.Client, app config.App, serviceName string) error {
|
||||||
filters := filters.NewArgs()
|
filters := filters.NewArgs()
|
||||||
filters.Add("name", fmt.Sprintf("%s_%s", app.StackName(), serviceName))
|
filters.Add("name", fmt.Sprintf("%s_%s", app.StackName(), serviceName))
|
||||||
chosenService, err := service.GetService(c.Context, cl, filters, internal.NoInput)
|
chosenService, err := service.GetService(context.Background(), cl, filters, internal.NoInput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -107,7 +111,7 @@ func tailServiceLogs(c *cli.Context, cl *dockerClient.Client, app config.App, se
|
|||||||
logOpts.ShowStdout = false
|
logOpts.ShowStdout = false
|
||||||
}
|
}
|
||||||
|
|
||||||
logs, err := cl.ServiceLogs(c.Context, chosenService.ID, logOpts)
|
logs, err := cl.ServiceLogs(context.Background(), chosenService.ID, logOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package app
|
|||||||
import (
|
import (
|
||||||
"coopcloud.tech/abra/cli/internal"
|
"coopcloud.tech/abra/cli/internal"
|
||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
"coopcloud.tech/abra/pkg/autocomplete"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appNewDescription = `
|
var appNewDescription = `
|
||||||
@ -26,18 +26,21 @@ pass store (see passwordstore.org for more). The pass command must be available
|
|||||||
on your $PATH.
|
on your $PATH.
|
||||||
`
|
`
|
||||||
|
|
||||||
var appNewCommand = &cli.Command{
|
var appNewCommand = cli.Command{
|
||||||
Name: "new",
|
Name: "new",
|
||||||
Usage: "Create a new app",
|
|
||||||
Aliases: []string{"n"},
|
Aliases: []string{"n"},
|
||||||
|
Usage: "Create a new app",
|
||||||
Description: appNewDescription,
|
Description: appNewDescription,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.NewAppServerFlag,
|
internal.NewAppServerFlag,
|
||||||
internal.DomainFlag,
|
internal.DomainFlag,
|
||||||
internal.NewAppNameFlag,
|
internal.NewAppNameFlag,
|
||||||
internal.PassFlag,
|
internal.PassFlag,
|
||||||
internal.SecretsFlag,
|
internal.SecretsFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
ArgsUsage: "<recipe>",
|
ArgsUsage: "<recipe>",
|
||||||
Action: internal.NewAction,
|
Action: internal.NewAction,
|
||||||
BashComplete: autocomplete.RecipeNameComplete,
|
BashComplete: autocomplete.RecipeNameComplete,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -17,17 +18,20 @@ import (
|
|||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
dockerClient "github.com/docker/docker/client"
|
dockerClient "github.com/docker/docker/client"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appPsCommand = &cli.Command{
|
var appPsCommand = cli.Command{
|
||||||
Name: "ps",
|
Name: "ps",
|
||||||
|
Aliases: []string{"p"},
|
||||||
Usage: "Check app status",
|
Usage: "Check app status",
|
||||||
Description: "This command shows a more detailed status output of a specific deployed app.",
|
Description: "This command shows a more detailed status output of a specific deployed app.",
|
||||||
Aliases: []string{"p"},
|
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
internal.WatchFlag,
|
internal.WatchFlag,
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
@ -37,7 +41,7 @@ var appPsCommand = &cli.Command{
|
|||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
isDeployed, _, err := stack.IsDeployed(c.Context, cl, app.StackName())
|
isDeployed, _, err := stack.IsDeployed(context.Background(), cl, app.StackName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -66,7 +70,7 @@ func showPSOutput(c *cli.Context, app config.App, cl *dockerClient.Client) {
|
|||||||
filters := filters.NewArgs()
|
filters := filters.NewArgs()
|
||||||
filters.Add("name", app.StackName())
|
filters.Add("name", app.StackName())
|
||||||
|
|
||||||
containers, err := cl.ContainerList(c.Context, types.ContainerListOptions{Filters: filters})
|
containers, err := cl.ContainerList(context.Background(), types.ContainerListOptions{Filters: filters})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ import (
|
|||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Volumes stores the variable from VolumesFlag
|
// Volumes stores the variable from VolumesFlag
|
||||||
@ -21,18 +22,20 @@ var Volumes bool
|
|||||||
// VolumesFlag is used to specify if volumes should be deleted when deleting an app
|
// VolumesFlag is used to specify if volumes should be deleted when deleting an app
|
||||||
var VolumesFlag = &cli.BoolFlag{
|
var VolumesFlag = &cli.BoolFlag{
|
||||||
Name: "volumes",
|
Name: "volumes",
|
||||||
Value: false,
|
|
||||||
Destination: &Volumes,
|
Destination: &Volumes,
|
||||||
}
|
}
|
||||||
|
|
||||||
var appRemoveCommand = &cli.Command{
|
var appRemoveCommand = cli.Command{
|
||||||
Name: "remove",
|
Name: "remove",
|
||||||
Usage: "Remove an already undeployed app",
|
|
||||||
Aliases: []string{"rm"},
|
Aliases: []string{"rm"},
|
||||||
|
Usage: "Remove an already undeployed app",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
VolumesFlag,
|
VolumesFlag,
|
||||||
internal.ForceFlag,
|
internal.ForceFlag,
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
|
|
||||||
@ -54,7 +57,7 @@ var appRemoveCommand = &cli.Command{
|
|||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
isDeployed, _, err := stack.IsDeployed(c.Context, cl, app.StackName())
|
isDeployed, _, err := stack.IsDeployed(context.Background(), cl, app.StackName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -64,7 +67,7 @@ var appRemoveCommand = &cli.Command{
|
|||||||
|
|
||||||
fs := filters.NewArgs()
|
fs := filters.NewArgs()
|
||||||
fs.Add("name", app.StackName())
|
fs.Add("name", app.StackName())
|
||||||
secretList, err := cl.SecretList(c.Context, types.SecretListOptions{Filters: fs})
|
secretList, err := cl.SecretList(context.Background(), types.SecretListOptions{Filters: fs})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -94,7 +97,7 @@ var appRemoveCommand = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range secretNamesToRemove {
|
for _, name := range secretNamesToRemove {
|
||||||
err := cl.SecretRemove(c.Context, secrets[name])
|
err := cl.SecretRemove(context.Background(), secrets[name])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -104,7 +107,7 @@ var appRemoveCommand = &cli.Command{
|
|||||||
logrus.Info("no secrets to remove")
|
logrus.Info("no secrets to remove")
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeListOKBody, err := cl.VolumeList(c.Context, fs)
|
volumeListOKBody, err := cl.VolumeList(context.Background(), fs)
|
||||||
volumeList := volumeListOKBody.Volumes
|
volumeList := volumeListOKBody.Volumes
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
@ -131,7 +134,7 @@ var appRemoveCommand = &cli.Command{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, vol := range removeVols {
|
for _, vol := range removeVols {
|
||||||
err := cl.VolumeRemove(c.Context, vol, internal.Force) // last argument is for force removing
|
err := cl.VolumeRemove(context.Background(), vol, internal.Force) // last argument is for force removing
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
@ -10,14 +11,19 @@ import (
|
|||||||
upstream "coopcloud.tech/abra/pkg/upstream/service"
|
upstream "coopcloud.tech/abra/pkg/upstream/service"
|
||||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appRestartCommand = &cli.Command{
|
var appRestartCommand = cli.Command{
|
||||||
Name: "restart",
|
Name: "restart",
|
||||||
Usage: "Restart an app",
|
|
||||||
Aliases: []string{"re"},
|
Aliases: []string{"re"},
|
||||||
|
Usage: "Restart an app",
|
||||||
ArgsUsage: "<service>",
|
ArgsUsage: "<service>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Description: `This command restarts a service within a deployed app.`,
|
Description: `This command restarts a service within a deployed app.`,
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
@ -37,22 +43,22 @@ var appRestartCommand = &cli.Command{
|
|||||||
serviceName := fmt.Sprintf("%s_%s", app.StackName(), serviceNameShort)
|
serviceName := fmt.Sprintf("%s_%s", app.StackName(), serviceNameShort)
|
||||||
|
|
||||||
logrus.Debugf("attempting to scale %s to 0 (restart logic)", serviceName)
|
logrus.Debugf("attempting to scale %s to 0 (restart logic)", serviceName)
|
||||||
if err := upstream.RunServiceScale(c.Context, cl, serviceName, 0); err != nil {
|
if err := upstream.RunServiceScale(context.Background(), cl, serviceName, 0); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stack.WaitOnService(c.Context, cl, serviceName, app.Name); err != nil {
|
if err := stack.WaitOnService(context.Background(), cl, serviceName, app.Name); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("%s has been scaled to 0 (restart logic)", serviceName)
|
logrus.Debugf("%s has been scaled to 0 (restart logic)", serviceName)
|
||||||
|
|
||||||
logrus.Debugf("attempting to scale %s to 1 (restart logic)", serviceName)
|
logrus.Debugf("attempting to scale %s to 1 (restart logic)", serviceName)
|
||||||
if err := upstream.RunServiceScale(c.Context, cl, serviceName, 1); err != nil {
|
if err := upstream.RunServiceScale(context.Background(), cl, serviceName, 1); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stack.WaitOnService(c.Context, cl, serviceName, app.Name); err != nil {
|
if err := stack.WaitOnService(context.Background(), cl, serviceName, app.Name); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"coopcloud.tech/abra/cli/internal"
|
|
||||||
"coopcloud.tech/abra/pkg/config"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var restoreAllServices bool
|
|
||||||
var restoreAllServicesFlag = &cli.BoolFlag{
|
|
||||||
Name: "all",
|
|
||||||
Value: false,
|
|
||||||
Destination: &restoreAllServices,
|
|
||||||
Aliases: []string{"a"},
|
|
||||||
Usage: "Restore all services",
|
|
||||||
}
|
|
||||||
|
|
||||||
var appRestoreCommand = &cli.Command{
|
|
||||||
Name: "restore",
|
|
||||||
Usage: "Restore an app from a backup",
|
|
||||||
Aliases: []string{"rs"},
|
|
||||||
Flags: []cli.Flag{restoreAllServicesFlag},
|
|
||||||
ArgsUsage: "<service> [<backup file>]",
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
app := internal.ValidateApp(c)
|
|
||||||
|
|
||||||
if c.Args().Len() > 1 && restoreAllServices {
|
|
||||||
internal.ShowSubcommandHelpAndError(c, errors.New("cannot use <service>/<backup file> and '--all' together"))
|
|
||||||
}
|
|
||||||
|
|
||||||
abraSh := path.Join(config.RECIPES_DIR, app.Type, "abra.sh")
|
|
||||||
if _, err := os.Stat(abraSh); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
logrus.Fatalf("%s does not exist?", abraSh)
|
|
||||||
}
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceCmd := fmt.Sprintf("source %s", abraSh)
|
|
||||||
execCmd := "abra_restore"
|
|
||||||
if !restoreAllServices {
|
|
||||||
serviceName := c.Args().Get(1)
|
|
||||||
if serviceName == "" {
|
|
||||||
internal.ShowSubcommandHelpAndError(c, errors.New("no service(s) target provided"))
|
|
||||||
}
|
|
||||||
execCmd = fmt.Sprintf("abra_restore_%s", serviceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes, err := ioutil.ReadFile(abraSh)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
if !strings.Contains(string(bytes), execCmd) {
|
|
||||||
logrus.Fatalf("%s doesn't have a %s function", app.Type, execCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
backupFile := c.Args().Get(2)
|
|
||||||
if backupFile != "" {
|
|
||||||
execCmd = fmt.Sprintf("%s %s", execCmd, backupFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceAndExec := fmt.Sprintf("%s; %s", sourceCmd, execCmd)
|
|
||||||
cmd := exec.Command("bash", "-c", sourceAndExec)
|
|
||||||
if err := internal.RunCmd(cmd); err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
"coopcloud.tech/abra/pkg/autocomplete"
|
||||||
@ -14,19 +15,22 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/client"
|
"coopcloud.tech/abra/pkg/client"
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appRollbackCommand = &cli.Command{
|
var appRollbackCommand = cli.Command{
|
||||||
Name: "rollback",
|
Name: "rollback",
|
||||||
Usage: "Roll an app back to a previous version",
|
|
||||||
Aliases: []string{"rl"},
|
Aliases: []string{"rl"},
|
||||||
|
Usage: "Roll an app back to a previous version",
|
||||||
ArgsUsage: "<app>",
|
ArgsUsage: "<app>",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.ForceFlag,
|
internal.ForceFlag,
|
||||||
internal.ChaosFlag,
|
internal.ChaosFlag,
|
||||||
internal.DontWaitConvergeFlag,
|
internal.DontWaitConvergeFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Description: `
|
Description: `
|
||||||
This command rolls an app back to a previous version if one exists.
|
This command rolls an app back to a previous version if one exists.
|
||||||
|
|
||||||
@ -34,7 +38,7 @@ You may pass "--force/-f" to downgrade to the same version again. This can be
|
|||||||
useful if the container runtime has gotten into a weird state.
|
useful if the container runtime has gotten into a weird state.
|
||||||
|
|
||||||
This action could be destructive, please ensure you have a copy of your app
|
This action could be destructive, please ensure you have a copy of your app
|
||||||
data beforehand - see "abra app backup <app>" for more.
|
data beforehand.
|
||||||
|
|
||||||
Chas mode ("--chaos") will deploy your local checkout of a recipe as-is,
|
Chas mode ("--chaos") will deploy your local checkout of a recipe as-is,
|
||||||
including unstaged changes and can be useful for live hacking and testing new
|
including unstaged changes and can be useful for live hacking and testing new
|
||||||
@ -67,7 +71,7 @@ recipes.
|
|||||||
|
|
||||||
logrus.Debugf("checking whether %s is already deployed", stackName)
|
logrus.Debugf("checking whether %s is already deployed", stackName)
|
||||||
|
|
||||||
isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, stackName)
|
isDeployed, deployedVersion, err := stack.IsDeployed(context.Background(), cl, stackName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ import (
|
|||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var user string
|
var user string
|
||||||
@ -26,28 +27,30 @@ var userFlag = &cli.StringFlag{
|
|||||||
var noTTY bool
|
var noTTY bool
|
||||||
var noTTYFlag = &cli.BoolFlag{
|
var noTTYFlag = &cli.BoolFlag{
|
||||||
Name: "no-tty",
|
Name: "no-tty",
|
||||||
Value: false,
|
|
||||||
Destination: &noTTY,
|
Destination: &noTTY,
|
||||||
}
|
}
|
||||||
|
|
||||||
var appRunCommand = &cli.Command{
|
var appRunCommand = cli.Command{
|
||||||
Name: "run",
|
Name: "run",
|
||||||
|
Aliases: []string{"r"},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
noTTYFlag,
|
noTTYFlag,
|
||||||
userFlag,
|
userFlag,
|
||||||
},
|
},
|
||||||
Aliases: []string{"r"},
|
Before: internal.SubCommandBefore,
|
||||||
ArgsUsage: "<service> <args>...",
|
ArgsUsage: "<service> <args>...",
|
||||||
Usage: "Run a command in a service container",
|
Usage: "Run a command in a service container",
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
|
|
||||||
if c.Args().Len() < 2 {
|
if len(c.Args()) < 2 {
|
||||||
internal.ShowSubcommandHelpAndError(c, errors.New("no <service> provided?"))
|
internal.ShowSubcommandHelpAndError(c, errors.New("no <service> provided?"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Args().Len() < 3 {
|
if len(c.Args()) < 3 {
|
||||||
internal.ShowSubcommandHelpAndError(c, errors.New("no <args> provided?"))
|
internal.ShowSubcommandHelpAndError(c, errors.New("no <args> provided?"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,12 +64,12 @@ var appRunCommand = &cli.Command{
|
|||||||
filters := filters.NewArgs()
|
filters := filters.NewArgs()
|
||||||
filters.Add("name", stackAndServiceName)
|
filters.Add("name", stackAndServiceName)
|
||||||
|
|
||||||
targetContainer, err := containerPkg.GetContainer(c.Context, cl, filters, true)
|
targetContainer, err := containerPkg.GetContainer(context.Background(), cl, filters, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := c.Args().Slice()[2:]
|
cmd := c.Args()[2:]
|
||||||
execCreateOpts := types.ExecConfig{
|
execCreateOpts := types.ExecConfig{
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
AttachStdin: true,
|
AttachStdin: true,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -14,29 +15,32 @@ import (
|
|||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var allSecrets bool
|
var allSecrets bool
|
||||||
var allSecretsFlag = &cli.BoolFlag{
|
var allSecretsFlag = &cli.BoolFlag{
|
||||||
Name: "all",
|
Name: "all, a",
|
||||||
Aliases: []string{"a"},
|
|
||||||
Value: false,
|
|
||||||
Destination: &allSecrets,
|
Destination: &allSecrets,
|
||||||
Usage: "Generate all secrets",
|
Usage: "Generate all secrets",
|
||||||
}
|
}
|
||||||
|
|
||||||
var appSecretGenerateCommand = &cli.Command{
|
var appSecretGenerateCommand = cli.Command{
|
||||||
Name: "generate",
|
Name: "generate",
|
||||||
Aliases: []string{"g"},
|
Aliases: []string{"g"},
|
||||||
Usage: "Generate secrets",
|
Usage: "Generate secrets",
|
||||||
ArgsUsage: "<secret> <version>",
|
ArgsUsage: "<secret> <version>",
|
||||||
Flags: []cli.Flag{allSecretsFlag, internal.PassFlag},
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
allSecretsFlag, internal.PassFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
|
|
||||||
if c.Args().Len() == 1 && !allSecrets {
|
if len(c.Args()) == 1 && !allSecrets {
|
||||||
err := errors.New("missing arguments <secret>/<version> or '--all'")
|
err := errors.New("missing arguments <secret>/<version> or '--all'")
|
||||||
internal.ShowSubcommandHelpAndError(c, err)
|
internal.ShowSubcommandHelpAndError(c, err)
|
||||||
}
|
}
|
||||||
@ -95,11 +99,16 @@ var appSecretGenerateCommand = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var appSecretInsertCommand = &cli.Command{
|
var appSecretInsertCommand = cli.Command{
|
||||||
Name: "insert",
|
Name: "insert",
|
||||||
Aliases: []string{"i"},
|
Aliases: []string{"i"},
|
||||||
Usage: "Insert secret",
|
Usage: "Insert secret",
|
||||||
Flags: []cli.Flag{internal.PassFlag},
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
internal.PassFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
ArgsUsage: "<app> <secret-name> <version> <data>",
|
ArgsUsage: "<app> <secret-name> <version> <data>",
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Description: `
|
Description: `
|
||||||
@ -117,7 +126,7 @@ Example:
|
|||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
|
|
||||||
if c.Args().Len() != 4 {
|
if len(c.Args()) != 4 {
|
||||||
internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments?"))
|
internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments?"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,11 +149,16 @@ Example:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var appSecretRmCommand = &cli.Command{
|
var appSecretRmCommand = cli.Command{
|
||||||
Name: "remove",
|
Name: "remove",
|
||||||
Usage: "Remove a secret",
|
|
||||||
Aliases: []string{"rm"},
|
Aliases: []string{"rm"},
|
||||||
Flags: []cli.Flag{allSecretsFlag, internal.PassFlag},
|
Usage: "Remove a secret",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
allSecretsFlag, internal.PassFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
ArgsUsage: "<app> <secret-name>",
|
ArgsUsage: "<app> <secret-name>",
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Description: `
|
Description: `
|
||||||
@ -173,7 +187,7 @@ Example:
|
|||||||
|
|
||||||
filters := filters.NewArgs()
|
filters := filters.NewArgs()
|
||||||
filters.Add("name", app.StackName())
|
filters.Add("name", app.StackName())
|
||||||
secretList, err := cl.SecretList(c.Context, types.SecretListOptions{Filters: filters})
|
secretList, err := cl.SecretList(context.Background(), types.SecretListOptions{Filters: filters})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -183,7 +197,7 @@ Example:
|
|||||||
secretName := cont.Spec.Annotations.Name
|
secretName := cont.Spec.Annotations.Name
|
||||||
parsed := secret.ParseGeneratedSecretName(secretName, app)
|
parsed := secret.ParseGeneratedSecretName(secretName, app)
|
||||||
if allSecrets {
|
if allSecrets {
|
||||||
if err := cl.SecretRemove(c.Context, secretName); err != nil {
|
if err := cl.SecretRemove(context.Background(), secretName); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
logrus.Infof("deleted %s successfully from server", secretName)
|
logrus.Infof("deleted %s successfully from server", secretName)
|
||||||
@ -197,7 +211,7 @@ Example:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if parsed == secretToRm {
|
if parsed == secretToRm {
|
||||||
if err := cl.SecretRemove(c.Context, secretName); err != nil {
|
if err := cl.SecretRemove(context.Background(), secretName); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,10 +232,15 @@ Example:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var appSecretLsCommand = &cli.Command{
|
var appSecretLsCommand = cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List all secrets",
|
|
||||||
Aliases: []string{"ls"},
|
Aliases: []string{"ls"},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
|
Usage: "List all secrets",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
secrets := secret.ReadSecretEnvVars(app.Env)
|
secrets := secret.ReadSecretEnvVars(app.Env)
|
||||||
@ -236,7 +255,7 @@ var appSecretLsCommand = &cli.Command{
|
|||||||
|
|
||||||
filters := filters.NewArgs()
|
filters := filters.NewArgs()
|
||||||
filters.Add("name", app.StackName())
|
filters.Add("name", app.StackName())
|
||||||
secretList, err := cl.SecretList(c.Context, types.SecretListOptions{Filters: filters})
|
secretList, err := cl.SecretList(context.Background(), types.SecretListOptions{Filters: filters})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -272,12 +291,12 @@ var appSecretLsCommand = &cli.Command{
|
|||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
}
|
}
|
||||||
|
|
||||||
var appSecretCommand = &cli.Command{
|
var appSecretCommand = cli.Command{
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
Aliases: []string{"s"},
|
Aliases: []string{"s"},
|
||||||
Usage: "Manage app secrets",
|
Usage: "Manage app secrets",
|
||||||
ArgsUsage: "<command>",
|
ArgsUsage: "<command>",
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []cli.Command{
|
||||||
appSecretGenerateCommand,
|
appSecretGenerateCommand,
|
||||||
appSecretInsertCommand,
|
appSecretInsertCommand,
|
||||||
appSecretRmCommand,
|
appSecretRmCommand,
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"coopcloud.tech/abra/cli/internal"
|
"coopcloud.tech/abra/cli/internal"
|
||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
"coopcloud.tech/abra/pkg/autocomplete"
|
||||||
"coopcloud.tech/abra/pkg/client"
|
"coopcloud.tech/abra/pkg/client"
|
||||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appUndeployCommand = &cli.Command{
|
var appUndeployCommand = cli.Command{
|
||||||
Name: "undeploy",
|
Name: "undeploy",
|
||||||
Aliases: []string{"un"},
|
Aliases: []string{"un"},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Usage: "Undeploy an app",
|
Usage: "Undeploy an app",
|
||||||
Description: `
|
Description: `
|
||||||
This does not destroy any of the application data. However, you should remain
|
This does not destroy any of the application data. However, you should remain
|
||||||
@ -29,7 +36,7 @@ volumes as eligiblef or pruning once undeployed.
|
|||||||
|
|
||||||
logrus.Debugf("checking whether %s is already deployed", stackName)
|
logrus.Debugf("checking whether %s is already deployed", stackName)
|
||||||
|
|
||||||
isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, stackName)
|
isDeployed, deployedVersion, err := stack.IsDeployed(context.Background(), cl, stackName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -43,7 +50,7 @@ volumes as eligiblef or pruning once undeployed.
|
|||||||
}
|
}
|
||||||
|
|
||||||
rmOpts := stack.Remove{Namespaces: []string{app.StackName()}}
|
rmOpts := stack.Remove{Namespaces: []string{app.StackName()}}
|
||||||
if err := stack.RunRemove(c.Context, cl, rmOpts); err != nil {
|
if err := stack.RunRemove(context.Background(), cl, rmOpts); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"coopcloud.tech/abra/cli/internal"
|
"coopcloud.tech/abra/cli/internal"
|
||||||
@ -13,19 +14,22 @@ import (
|
|||||||
"coopcloud.tech/tagcmp"
|
"coopcloud.tech/tagcmp"
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appUpgradeCommand = &cli.Command{
|
var appUpgradeCommand = cli.Command{
|
||||||
Name: "upgrade",
|
Name: "upgrade",
|
||||||
Aliases: []string{"up"},
|
Aliases: []string{"up"},
|
||||||
Usage: "Upgrade an app",
|
Usage: "Upgrade an app",
|
||||||
ArgsUsage: "<app>",
|
ArgsUsage: "<app>",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.ForceFlag,
|
internal.ForceFlag,
|
||||||
internal.ChaosFlag,
|
internal.ChaosFlag,
|
||||||
internal.NoDomainChecksFlag,
|
internal.NoDomainChecksFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Description: `
|
Description: `
|
||||||
This command supports upgrading an app. You can use it to choose and roll out a
|
This command supports upgrading an app. You can use it to choose and roll out a
|
||||||
new upgrade to an existing app.
|
new upgrade to an existing app.
|
||||||
@ -38,7 +42,7 @@ You may pass "--force/-f" to upgrade to the same version again. This can be
|
|||||||
useful if the container runtime has gotten into a weird state.
|
useful if the container runtime has gotten into a weird state.
|
||||||
|
|
||||||
This action could be destructive, please ensure you have a copy of your app
|
This action could be destructive, please ensure you have a copy of your app
|
||||||
data beforehand - see "abra app backup <app>" for more.
|
data beforehand.
|
||||||
|
|
||||||
Chas mode ("--chaos") will deploy your local checkout of a recipe as-is,
|
Chas mode ("--chaos") will deploy your local checkout of a recipe as-is,
|
||||||
including unstaged changes and can be useful for live hacking and testing new
|
including unstaged changes and can be useful for live hacking and testing new
|
||||||
@ -70,7 +74,7 @@ recipes.
|
|||||||
|
|
||||||
logrus.Debugf("checking whether %s is already deployed", stackName)
|
logrus.Debugf("checking whether %s is already deployed", stackName)
|
||||||
|
|
||||||
isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, stackName)
|
isDeployed, deployedVersion, err := stack.IsDeployed(context.Background(), cl, stackName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"coopcloud.tech/abra/cli/internal"
|
"coopcloud.tech/abra/cli/internal"
|
||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
"coopcloud.tech/abra/pkg/autocomplete"
|
||||||
"coopcloud.tech/abra/pkg/client"
|
"coopcloud.tech/abra/pkg/client"
|
||||||
@ -9,7 +11,7 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getImagePath returns the image name
|
// getImagePath returns the image name
|
||||||
@ -21,16 +23,21 @@ func getImagePath(image string) (string, error) {
|
|||||||
|
|
||||||
path := reference.Path(img)
|
path := reference.Path(img)
|
||||||
|
|
||||||
path = recipe.StripTagMeta(path)
|
path = formatter.StripTagMeta(path)
|
||||||
|
|
||||||
logrus.Debugf("parsed %s from %s", path, image)
|
logrus.Debugf("parsed %s from %s", path, image)
|
||||||
|
|
||||||
return path, nil
|
return path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var appVersionCommand = &cli.Command{
|
var appVersionCommand = cli.Command{
|
||||||
Name: "version",
|
Name: "version",
|
||||||
Aliases: []string{"v"},
|
Aliases: []string{"v"},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Usage: "Show app versions",
|
Usage: "Show app versions",
|
||||||
Description: `
|
Description: `
|
||||||
This command shows all information about versioning related to a deployed app.
|
This command shows all information about versioning related to a deployed app.
|
||||||
@ -48,7 +55,7 @@ Cloud recipe version.
|
|||||||
|
|
||||||
logrus.Debugf("checking whether %s is already deployed", stackName)
|
logrus.Debugf("checking whether %s is already deployed", stackName)
|
||||||
|
|
||||||
isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, stackName)
|
isDeployed, deployedVersion, err := stack.IsDeployed(context.Background(), cl, stackName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,31 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"coopcloud.tech/abra/cli/internal"
|
"coopcloud.tech/abra/cli/internal"
|
||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
"coopcloud.tech/abra/pkg/autocomplete"
|
||||||
"coopcloud.tech/abra/pkg/client"
|
"coopcloud.tech/abra/pkg/client"
|
||||||
"coopcloud.tech/abra/pkg/formatter"
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appVolumeListCommand = &cli.Command{
|
var appVolumeListCommand = cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List volumes associated with an app",
|
|
||||||
Aliases: []string{"ls"},
|
Aliases: []string{"ls"},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
|
Usage: "List volumes associated with an app",
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
|
|
||||||
volumeList, err := client.GetVolumes(c.Context, app.Server, app.Name)
|
volumeList, err := client.GetVolumes(context.Background(), app.Server, app.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -45,7 +52,7 @@ var appVolumeListCommand = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var appVolumeRemoveCommand = &cli.Command{
|
var appVolumeRemoveCommand = cli.Command{
|
||||||
Name: "remove",
|
Name: "remove",
|
||||||
Usage: "Remove volume(s) associated with an app",
|
Usage: "Remove volume(s) associated with an app",
|
||||||
Description: `
|
Description: `
|
||||||
@ -62,12 +69,15 @@ Passing "--force" will select all volumes for removal. Be careful.
|
|||||||
ArgsUsage: "<app>",
|
ArgsUsage: "<app>",
|
||||||
Aliases: []string{"rm"},
|
Aliases: []string{"rm"},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.ForceFlag,
|
internal.ForceFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
|
|
||||||
volumeList, err := client.GetVolumes(c.Context, app.Server, app.Name)
|
volumeList, err := client.GetVolumes(context.Background(), app.Server, app.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -89,7 +99,7 @@ Passing "--force" will select all volumes for removal. Be careful.
|
|||||||
volumesToRemove = volumeNames
|
volumesToRemove = volumeNames
|
||||||
}
|
}
|
||||||
|
|
||||||
err = client.RemoveVolumes(c.Context, app.Server, volumesToRemove, internal.Force)
|
err = client.RemoveVolumes(context.Background(), app.Server, volumesToRemove, internal.Force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -101,12 +111,12 @@ Passing "--force" will select all volumes for removal. Be careful.
|
|||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
}
|
}
|
||||||
|
|
||||||
var appVolumeCommand = &cli.Command{
|
var appVolumeCommand = cli.Command{
|
||||||
Name: "volume",
|
Name: "volume",
|
||||||
Aliases: []string{"vl"},
|
Aliases: []string{"vl"},
|
||||||
Usage: "Manage app volumes",
|
Usage: "Manage app volumes",
|
||||||
ArgsUsage: "<command>",
|
ArgsUsage: "<command>",
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []cli.Command{
|
||||||
appVolumeListCommand,
|
appVolumeListCommand,
|
||||||
appVolumeRemoveCommand,
|
appVolumeRemoveCommand,
|
||||||
},
|
},
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/recipe"
|
"coopcloud.tech/abra/pkg/recipe"
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CatalogueSkipList is all the repos that are not recipes.
|
// CatalogueSkipList is all the repos that are not recipes.
|
||||||
@ -56,17 +56,20 @@ var CatalogueSkipList = map[string]bool{
|
|||||||
"tyop": true,
|
"tyop": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
var catalogueGenerateCommand = &cli.Command{
|
var catalogueGenerateCommand = cli.Command{
|
||||||
Name: "generate",
|
Name: "generate",
|
||||||
Aliases: []string{"g"},
|
Aliases: []string{"g"},
|
||||||
Usage: "Generate the recipe catalogue",
|
Usage: "Generate the recipe catalogue",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.PublishFlag,
|
internal.PublishFlag,
|
||||||
internal.DryFlag,
|
internal.DryFlag,
|
||||||
internal.SkipUpdatesFlag,
|
internal.SkipUpdatesFlag,
|
||||||
internal.RegistryUsernameFlag,
|
internal.RegistryUsernameFlag,
|
||||||
internal.RegistryPasswordFlag,
|
internal.RegistryPasswordFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Description: `
|
Description: `
|
||||||
This command generates a new copy of the recipe catalogue which can be found on:
|
This command generates a new copy of the recipe catalogue which can be found on:
|
||||||
|
|
||||||
@ -247,13 +250,13 @@ keys configured on your account.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CatalogueCommand defines the `abra catalogue` command and sub-commands.
|
// CatalogueCommand defines the `abra catalogue` command and sub-commands.
|
||||||
var CatalogueCommand = &cli.Command{
|
var CatalogueCommand = cli.Command{
|
||||||
Name: "catalogue",
|
Name: "catalogue",
|
||||||
Usage: "Manage the recipe catalogue",
|
Usage: "Manage the recipe catalogue",
|
||||||
Aliases: []string{"c"},
|
Aliases: []string{"c"},
|
||||||
ArgsUsage: "<recipe>",
|
ArgsUsage: "<recipe>",
|
||||||
Description: "This command helps recipe packagers interact with the recipe catalogue",
|
Description: "This command helps recipe packagers interact with the recipe catalogue",
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []cli.Command{
|
||||||
catalogueGenerateCommand,
|
catalogueGenerateCommand,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
30
cli/cli.go
30
cli/cli.go
@ -16,16 +16,15 @@ import (
|
|||||||
"coopcloud.tech/abra/cli/server"
|
"coopcloud.tech/abra/cli/server"
|
||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"coopcloud.tech/abra/pkg/web"
|
"coopcloud.tech/abra/pkg/web"
|
||||||
logrusStack "github.com/Gurpartap/logrus-stack"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AutoCompleteCommand helps people set up auto-complete in their shells
|
// AutoCompleteCommand helps people set up auto-complete in their shells
|
||||||
var AutoCompleteCommand = &cli.Command{
|
var AutoCompleteCommand = cli.Command{
|
||||||
Name: "autocomplete",
|
Name: "autocomplete",
|
||||||
Usage: "Configure shell autocompletion (recommended)",
|
|
||||||
Aliases: []string{"ac"},
|
Aliases: []string{"ac"},
|
||||||
|
Usage: "Configure shell autocompletion (recommended)",
|
||||||
Description: `
|
Description: `
|
||||||
This command helps set up autocompletion in your shell by downloading the
|
This command helps set up autocompletion in your shell by downloading the
|
||||||
relevant autocompletion files and laying out what additional information must
|
relevant autocompletion files and laying out what additional information must
|
||||||
@ -43,6 +42,10 @@ Supported shells are as follows:
|
|||||||
|
|
||||||
`,
|
`,
|
||||||
ArgsUsage: "<shell>",
|
ArgsUsage: "<shell>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
shellType := c.Args().First()
|
shellType := c.Args().First()
|
||||||
|
|
||||||
@ -105,10 +108,10 @@ echo "PROG=abra\n_CLI_ZSH_AUTOCOMPLETE_HACK=1\nsource /etc/zsh/completion.d/abra
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpgradeCommand upgrades abra in-place.
|
// UpgradeCommand upgrades abra in-place.
|
||||||
var UpgradeCommand = &cli.Command{
|
var UpgradeCommand = cli.Command{
|
||||||
Name: "upgrade",
|
Name: "upgrade",
|
||||||
Usage: "Upgrade Abra itself",
|
|
||||||
Aliases: []string{"u"},
|
Aliases: []string{"u"},
|
||||||
|
Usage: "Upgrade Abra itself",
|
||||||
Description: `
|
Description: `
|
||||||
This command allows you to upgrade Abra in-place with the latest stable or
|
This command allows you to upgrade Abra in-place with the latest stable or
|
||||||
release candidate.
|
release candidate.
|
||||||
@ -150,7 +153,7 @@ func newAbraApp(version, commit string) *cli.App {
|
|||||||
|_|
|
|_|
|
||||||
`,
|
`,
|
||||||
Version: fmt.Sprintf("%s-%s", version, commit[:7]),
|
Version: fmt.Sprintf("%s-%s", version, commit[:7]),
|
||||||
Commands: []*cli.Command{
|
Commands: []cli.Command{
|
||||||
app.AppCommand,
|
app.AppCommand,
|
||||||
server.ServerCommand,
|
server.ServerCommand,
|
||||||
recipe.RecipeCommand,
|
recipe.RecipeCommand,
|
||||||
@ -159,11 +162,7 @@ func newAbraApp(version, commit string) *cli.App {
|
|||||||
UpgradeCommand,
|
UpgradeCommand,
|
||||||
AutoCompleteCommand,
|
AutoCompleteCommand,
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Authors: []cli.Author{
|
||||||
internal.DebugFlag,
|
|
||||||
internal.NoInputFlag,
|
|
||||||
},
|
|
||||||
Authors: []*cli.Author{
|
|
||||||
// If you're looking at this and you hack on Abra and you're not listed
|
// If you're looking at this and you hack on Abra and you're not listed
|
||||||
// here, please do add yourself! This is a community project, let's show
|
// here, please do add yourself! This is a community project, let's show
|
||||||
// some love
|
// some love
|
||||||
@ -178,13 +177,6 @@ func newAbraApp(version, commit string) *cli.App {
|
|||||||
app.EnableBashCompletion = true
|
app.EnableBashCompletion = true
|
||||||
|
|
||||||
app.Before = func(c *cli.Context) error {
|
app.Before = func(c *cli.Context) error {
|
||||||
if internal.Debug {
|
|
||||||
logrus.SetLevel(logrus.DebugLevel)
|
|
||||||
logrus.SetFormatter(&logrus.TextFormatter{})
|
|
||||||
logrus.SetOutput(os.Stderr)
|
|
||||||
logrus.AddHook(logrusStack.StandardHook())
|
|
||||||
}
|
|
||||||
|
|
||||||
paths := []string{
|
paths := []string{
|
||||||
config.ABRA_DIR,
|
config.ABRA_DIR,
|
||||||
path.Join(config.SERVERS_DIR),
|
path.Join(config.SERVERS_DIR),
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"os"
|
||||||
|
|
||||||
|
logrusStack "github.com/Gurpartap/logrus-stack"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Secrets stores the variable from SecretsFlag
|
// Secrets stores the variable from SecretsFlag
|
||||||
@ -9,9 +13,7 @@ var Secrets bool
|
|||||||
|
|
||||||
// SecretsFlag turns on/off automatically generating secrets
|
// SecretsFlag turns on/off automatically generating secrets
|
||||||
var SecretsFlag = &cli.BoolFlag{
|
var SecretsFlag = &cli.BoolFlag{
|
||||||
Name: "secrets",
|
Name: "secrets, ss",
|
||||||
Aliases: []string{"ss"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Automatically generate secrets",
|
Usage: "Automatically generate secrets",
|
||||||
Destination: &Secrets,
|
Destination: &Secrets,
|
||||||
}
|
}
|
||||||
@ -21,9 +23,7 @@ var Pass bool
|
|||||||
|
|
||||||
// PassFlag turns on/off storing generated secrets in pass
|
// PassFlag turns on/off storing generated secrets in pass
|
||||||
var PassFlag = &cli.BoolFlag{
|
var PassFlag = &cli.BoolFlag{
|
||||||
Name: "pass",
|
Name: "pass, p",
|
||||||
Aliases: []string{"p"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Store the generated secrets in a local pass store",
|
Usage: "Store the generated secrets in a local pass store",
|
||||||
Destination: &Pass,
|
Destination: &Pass,
|
||||||
}
|
}
|
||||||
@ -33,9 +33,8 @@ var Context string
|
|||||||
|
|
||||||
// ContextFlag is temp
|
// ContextFlag is temp
|
||||||
var ContextFlag = &cli.StringFlag{
|
var ContextFlag = &cli.StringFlag{
|
||||||
Name: "context",
|
Name: "context, c",
|
||||||
Value: "",
|
Value: "",
|
||||||
Aliases: []string{"c"},
|
|
||||||
Destination: &Context,
|
Destination: &Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,9 +43,7 @@ var Force bool
|
|||||||
|
|
||||||
// ForceFlag turns on/off force functionality.
|
// ForceFlag turns on/off force functionality.
|
||||||
var ForceFlag = &cli.BoolFlag{
|
var ForceFlag = &cli.BoolFlag{
|
||||||
Name: "force",
|
Name: "force, f",
|
||||||
Value: false,
|
|
||||||
Aliases: []string{"f"},
|
|
||||||
Usage: "Perform action without further prompt. Use with care!",
|
Usage: "Perform action without further prompt. Use with care!",
|
||||||
Destination: &Force,
|
Destination: &Force,
|
||||||
}
|
}
|
||||||
@ -56,9 +53,7 @@ var Chaos bool
|
|||||||
|
|
||||||
// ChaosFlag turns on/off chaos functionality.
|
// ChaosFlag turns on/off chaos functionality.
|
||||||
var ChaosFlag = &cli.BoolFlag{
|
var ChaosFlag = &cli.BoolFlag{
|
||||||
Name: "chaos",
|
Name: "chaos, ch",
|
||||||
Value: false,
|
|
||||||
Aliases: []string{"ch"},
|
|
||||||
Usage: "Deploy uncommitted recipes changes. Use with care!",
|
Usage: "Deploy uncommitted recipes changes. Use with care!",
|
||||||
Destination: &Chaos,
|
Destination: &Chaos,
|
||||||
}
|
}
|
||||||
@ -68,18 +63,15 @@ var DNSProvider string
|
|||||||
|
|
||||||
// DNSProviderFlag selects a DNS provider.
|
// DNSProviderFlag selects a DNS provider.
|
||||||
var DNSProviderFlag = &cli.StringFlag{
|
var DNSProviderFlag = &cli.StringFlag{
|
||||||
Name: "provider",
|
Name: "provider, p",
|
||||||
Value: "",
|
Value: "",
|
||||||
Aliases: []string{"p"},
|
|
||||||
Usage: "DNS provider",
|
Usage: "DNS provider",
|
||||||
Destination: &DNSProvider,
|
Destination: &DNSProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
var NoInput bool
|
var NoInput bool
|
||||||
var NoInputFlag = &cli.BoolFlag{
|
var NoInputFlag = &cli.BoolFlag{
|
||||||
Name: "no-input",
|
Name: "no-input, n",
|
||||||
Value: false,
|
|
||||||
Aliases: []string{"n"},
|
|
||||||
Usage: "Toggle non-interactive mode",
|
Usage: "Toggle non-interactive mode",
|
||||||
Destination: &NoInput,
|
Destination: &NoInput,
|
||||||
}
|
}
|
||||||
@ -87,9 +79,8 @@ var NoInputFlag = &cli.BoolFlag{
|
|||||||
var DNSType string
|
var DNSType string
|
||||||
|
|
||||||
var DNSTypeFlag = &cli.StringFlag{
|
var DNSTypeFlag = &cli.StringFlag{
|
||||||
Name: "type",
|
Name: "type, t",
|
||||||
Value: "",
|
Value: "",
|
||||||
Aliases: []string{"t"},
|
|
||||||
Usage: "Domain name record type (e.g. A)",
|
Usage: "Domain name record type (e.g. A)",
|
||||||
Destination: &DNSType,
|
Destination: &DNSType,
|
||||||
}
|
}
|
||||||
@ -97,9 +88,8 @@ var DNSTypeFlag = &cli.StringFlag{
|
|||||||
var DNSName string
|
var DNSName string
|
||||||
|
|
||||||
var DNSNameFlag = &cli.StringFlag{
|
var DNSNameFlag = &cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name, n",
|
||||||
Value: "",
|
Value: "",
|
||||||
Aliases: []string{"n"},
|
|
||||||
Usage: "Domain name record name (e.g. mysubdomain)",
|
Usage: "Domain name record name (e.g. mysubdomain)",
|
||||||
Destination: &DNSName,
|
Destination: &DNSName,
|
||||||
}
|
}
|
||||||
@ -107,18 +97,16 @@ var DNSNameFlag = &cli.StringFlag{
|
|||||||
var DNSValue string
|
var DNSValue string
|
||||||
|
|
||||||
var DNSValueFlag = &cli.StringFlag{
|
var DNSValueFlag = &cli.StringFlag{
|
||||||
Name: "value",
|
Name: "value, v",
|
||||||
Value: "",
|
Value: "",
|
||||||
Aliases: []string{"v"},
|
|
||||||
Usage: "Domain name record value (e.g. 192.168.1.1)",
|
Usage: "Domain name record value (e.g. 192.168.1.1)",
|
||||||
Destination: &DNSValue,
|
Destination: &DNSValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
var DNSTTL string
|
var DNSTTL string
|
||||||
var DNSTTLFlag = &cli.StringFlag{
|
var DNSTTLFlag = &cli.StringFlag{
|
||||||
Name: "ttl",
|
Name: "ttl, T",
|
||||||
Value: "600s",
|
Value: "600s",
|
||||||
Aliases: []string{"T"},
|
|
||||||
Usage: "Domain name TTL value (seconds)",
|
Usage: "Domain name TTL value (seconds)",
|
||||||
Destination: &DNSTTL,
|
Destination: &DNSTTL,
|
||||||
}
|
}
|
||||||
@ -126,9 +114,8 @@ var DNSTTLFlag = &cli.StringFlag{
|
|||||||
var DNSPriority int
|
var DNSPriority int
|
||||||
|
|
||||||
var DNSPriorityFlag = &cli.IntFlag{
|
var DNSPriorityFlag = &cli.IntFlag{
|
||||||
Name: "priority",
|
Name: "priority, P",
|
||||||
Value: 10,
|
Value: 10,
|
||||||
Aliases: []string{"P"},
|
|
||||||
Usage: "Domain name priority value",
|
Usage: "Domain name priority value",
|
||||||
Destination: &DNSPriority,
|
Destination: &DNSPriority,
|
||||||
}
|
}
|
||||||
@ -136,8 +123,7 @@ var DNSPriorityFlag = &cli.IntFlag{
|
|||||||
var ServerProvider string
|
var ServerProvider string
|
||||||
|
|
||||||
var ServerProviderFlag = &cli.StringFlag{
|
var ServerProviderFlag = &cli.StringFlag{
|
||||||
Name: "provider",
|
Name: "provider, p",
|
||||||
Aliases: []string{"p"},
|
|
||||||
Usage: "3rd party server provider",
|
Usage: "3rd party server provider",
|
||||||
Destination: &ServerProvider,
|
Destination: &ServerProvider,
|
||||||
}
|
}
|
||||||
@ -145,9 +131,8 @@ var ServerProviderFlag = &cli.StringFlag{
|
|||||||
var CapsulInstanceURL string
|
var CapsulInstanceURL string
|
||||||
|
|
||||||
var CapsulInstanceURLFlag = &cli.StringFlag{
|
var CapsulInstanceURLFlag = &cli.StringFlag{
|
||||||
Name: "capsul-url",
|
Name: "capsul-url, cu",
|
||||||
Value: "yolo.servers.coop",
|
Value: "yolo.servers.coop",
|
||||||
Aliases: []string{"cu"},
|
|
||||||
Usage: "capsul instance URL",
|
Usage: "capsul instance URL",
|
||||||
Destination: &CapsulInstanceURL,
|
Destination: &CapsulInstanceURL,
|
||||||
}
|
}
|
||||||
@ -155,9 +140,8 @@ var CapsulInstanceURLFlag = &cli.StringFlag{
|
|||||||
var CapsulName string
|
var CapsulName string
|
||||||
|
|
||||||
var CapsulNameFlag = &cli.StringFlag{
|
var CapsulNameFlag = &cli.StringFlag{
|
||||||
Name: "capsul-name",
|
Name: "capsul-name, cn",
|
||||||
Value: "",
|
Value: "",
|
||||||
Aliases: []string{"cn"},
|
|
||||||
Usage: "capsul name",
|
Usage: "capsul name",
|
||||||
Destination: &CapsulName,
|
Destination: &CapsulName,
|
||||||
}
|
}
|
||||||
@ -165,9 +149,8 @@ var CapsulNameFlag = &cli.StringFlag{
|
|||||||
var CapsulType string
|
var CapsulType string
|
||||||
|
|
||||||
var CapsulTypeFlag = &cli.StringFlag{
|
var CapsulTypeFlag = &cli.StringFlag{
|
||||||
Name: "capsul-type",
|
Name: "capsul-type, ct",
|
||||||
Value: "f1-xs",
|
Value: "f1-xs",
|
||||||
Aliases: []string{"ct"},
|
|
||||||
Usage: "capsul type",
|
Usage: "capsul type",
|
||||||
Destination: &CapsulType,
|
Destination: &CapsulType,
|
||||||
}
|
}
|
||||||
@ -175,38 +158,33 @@ var CapsulTypeFlag = &cli.StringFlag{
|
|||||||
var CapsulImage string
|
var CapsulImage string
|
||||||
|
|
||||||
var CapsulImageFlag = &cli.StringFlag{
|
var CapsulImageFlag = &cli.StringFlag{
|
||||||
Name: "capsul-image",
|
Name: "capsul-image, ci",
|
||||||
Value: "debian10",
|
Value: "debian10",
|
||||||
Aliases: []string{"ci"},
|
|
||||||
Usage: "capsul image",
|
Usage: "capsul image",
|
||||||
Destination: &CapsulImage,
|
Destination: &CapsulImage,
|
||||||
}
|
}
|
||||||
|
|
||||||
var CapsulSSHKeys cli.StringSlice
|
var CapsulSSHKeys cli.StringSlice
|
||||||
|
|
||||||
var CapsulSSHKeysFlag = &cli.StringSliceFlag{
|
var CapsulSSHKeysFlag = &cli.StringSliceFlag{
|
||||||
Name: "capsul-ssh-keys",
|
Name: "capsul-ssh-keys, cs",
|
||||||
Aliases: []string{"cs"},
|
|
||||||
Usage: "capsul SSH key",
|
Usage: "capsul SSH key",
|
||||||
Destination: &CapsulSSHKeys,
|
Value: &CapsulSSHKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
var CapsulAPIToken string
|
var CapsulAPIToken string
|
||||||
|
|
||||||
var CapsulAPITokenFlag = &cli.StringFlag{
|
var CapsulAPITokenFlag = &cli.StringFlag{
|
||||||
Name: "capsul-token",
|
Name: "capsul-token, ca",
|
||||||
Aliases: []string{"ca"},
|
|
||||||
Usage: "capsul API token",
|
Usage: "capsul API token",
|
||||||
EnvVars: []string{"CAPSUL_TOKEN"},
|
EnvVar: "CAPSUL_TOKEN",
|
||||||
Destination: &CapsulAPIToken,
|
Destination: &CapsulAPIToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
var HetznerCloudName string
|
var HetznerCloudName string
|
||||||
|
|
||||||
var HetznerCloudNameFlag = &cli.StringFlag{
|
var HetznerCloudNameFlag = &cli.StringFlag{
|
||||||
Name: "hetzner-name",
|
Name: "hetzner-name, hn",
|
||||||
Value: "",
|
Value: "",
|
||||||
Aliases: []string{"hn"},
|
|
||||||
Usage: "hetzner cloud name",
|
Usage: "hetzner cloud name",
|
||||||
Destination: &HetznerCloudName,
|
Destination: &HetznerCloudName,
|
||||||
}
|
}
|
||||||
@ -214,8 +192,7 @@ var HetznerCloudNameFlag = &cli.StringFlag{
|
|||||||
var HetznerCloudType string
|
var HetznerCloudType string
|
||||||
|
|
||||||
var HetznerCloudTypeFlag = &cli.StringFlag{
|
var HetznerCloudTypeFlag = &cli.StringFlag{
|
||||||
Name: "hetzner-type",
|
Name: "hetzner-type, ht",
|
||||||
Aliases: []string{"ht"},
|
|
||||||
Usage: "hetzner cloud type",
|
Usage: "hetzner cloud type",
|
||||||
Destination: &HetznerCloudType,
|
Destination: &HetznerCloudType,
|
||||||
Value: "cx11",
|
Value: "cx11",
|
||||||
@ -224,8 +201,7 @@ var HetznerCloudTypeFlag = &cli.StringFlag{
|
|||||||
var HetznerCloudImage string
|
var HetznerCloudImage string
|
||||||
|
|
||||||
var HetznerCloudImageFlag = &cli.StringFlag{
|
var HetznerCloudImageFlag = &cli.StringFlag{
|
||||||
Name: "hetzner-image",
|
Name: "hetzner-image, hi",
|
||||||
Aliases: []string{"hi"},
|
|
||||||
Usage: "hetzner cloud image",
|
Usage: "hetzner cloud image",
|
||||||
Value: "debian-10",
|
Value: "debian-10",
|
||||||
Destination: &HetznerCloudImage,
|
Destination: &HetznerCloudImage,
|
||||||
@ -234,17 +210,15 @@ var HetznerCloudImageFlag = &cli.StringFlag{
|
|||||||
var HetznerCloudSSHKeys cli.StringSlice
|
var HetznerCloudSSHKeys cli.StringSlice
|
||||||
|
|
||||||
var HetznerCloudSSHKeysFlag = &cli.StringSliceFlag{
|
var HetznerCloudSSHKeysFlag = &cli.StringSliceFlag{
|
||||||
Name: "hetzner-ssh-keys",
|
Name: "hetzner-ssh-keys, hs",
|
||||||
Aliases: []string{"hs"},
|
|
||||||
Usage: "hetzner cloud SSH keys (e.g. me@foo.com)",
|
Usage: "hetzner cloud SSH keys (e.g. me@foo.com)",
|
||||||
Destination: &HetznerCloudSSHKeys,
|
Value: &HetznerCloudSSHKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
var HetznerCloudLocation string
|
var HetznerCloudLocation string
|
||||||
|
|
||||||
var HetznerCloudLocationFlag = &cli.StringFlag{
|
var HetznerCloudLocationFlag = &cli.StringFlag{
|
||||||
Name: "hetzner-location",
|
Name: "hetzner-location, hl",
|
||||||
Aliases: []string{"hl"},
|
|
||||||
Usage: "hetzner cloud server location",
|
Usage: "hetzner cloud server location",
|
||||||
Value: "hel1",
|
Value: "hel1",
|
||||||
Destination: &HetznerCloudLocation,
|
Destination: &HetznerCloudLocation,
|
||||||
@ -253,10 +227,9 @@ var HetznerCloudLocationFlag = &cli.StringFlag{
|
|||||||
var HetznerCloudAPIToken string
|
var HetznerCloudAPIToken string
|
||||||
|
|
||||||
var HetznerCloudAPITokenFlag = &cli.StringFlag{
|
var HetznerCloudAPITokenFlag = &cli.StringFlag{
|
||||||
Name: "hetzner-token",
|
Name: "hetzner-token, ha",
|
||||||
Aliases: []string{"ha"},
|
|
||||||
Usage: "hetzner cloud API token",
|
Usage: "hetzner cloud API token",
|
||||||
EnvVars: []string{"HCLOUD_TOKEN"},
|
EnvVar: "HCLOUD_TOKEN",
|
||||||
Destination: &HetznerCloudAPIToken,
|
Destination: &HetznerCloudAPIToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,9 +238,7 @@ var Debug bool
|
|||||||
|
|
||||||
// DebugFlag turns on/off verbose logging down to the DEBUG level.
|
// DebugFlag turns on/off verbose logging down to the DEBUG level.
|
||||||
var DebugFlag = &cli.BoolFlag{
|
var DebugFlag = &cli.BoolFlag{
|
||||||
Name: "debug",
|
Name: "debug, d",
|
||||||
Aliases: []string{"d"},
|
|
||||||
Value: false,
|
|
||||||
Destination: &Debug,
|
Destination: &Debug,
|
||||||
Usage: "Show DEBUG messages",
|
Usage: "Show DEBUG messages",
|
||||||
}
|
}
|
||||||
@ -278,60 +249,48 @@ var RC bool
|
|||||||
// RCFlag chooses the latest release candidate for install
|
// RCFlag chooses the latest release candidate for install
|
||||||
var RCFlag = &cli.BoolFlag{
|
var RCFlag = &cli.BoolFlag{
|
||||||
Name: "rc",
|
Name: "rc",
|
||||||
Value: false,
|
|
||||||
Destination: &RC,
|
Destination: &RC,
|
||||||
Usage: "Insatll the latest release candidate",
|
Usage: "Insatll the latest release candidate",
|
||||||
}
|
}
|
||||||
|
|
||||||
var Major bool
|
var Major bool
|
||||||
var MajorFlag = &cli.BoolFlag{
|
var MajorFlag = &cli.BoolFlag{
|
||||||
Name: "major",
|
Name: "major, ma, x",
|
||||||
Usage: "Increase the major part of the version",
|
Usage: "Increase the major part of the version",
|
||||||
Value: false,
|
|
||||||
Aliases: []string{"ma", "x"},
|
|
||||||
Destination: &Major,
|
Destination: &Major,
|
||||||
}
|
}
|
||||||
|
|
||||||
var Minor bool
|
var Minor bool
|
||||||
var MinorFlag = &cli.BoolFlag{
|
var MinorFlag = &cli.BoolFlag{
|
||||||
Name: "minor",
|
Name: "minor, mi, y",
|
||||||
Usage: "Increase the minor part of the version",
|
Usage: "Increase the minor part of the version",
|
||||||
Value: false,
|
|
||||||
Aliases: []string{"mi", "y"},
|
|
||||||
Destination: &Minor,
|
Destination: &Minor,
|
||||||
}
|
}
|
||||||
|
|
||||||
var Patch bool
|
var Patch bool
|
||||||
var PatchFlag = &cli.BoolFlag{
|
var PatchFlag = &cli.BoolFlag{
|
||||||
Name: "patch",
|
Name: "patch, pa, z",
|
||||||
Usage: "Increase the patch part of the version",
|
Usage: "Increase the patch part of the version",
|
||||||
Value: false,
|
|
||||||
Aliases: []string{"pa", "z"},
|
|
||||||
Destination: &Patch,
|
Destination: &Patch,
|
||||||
}
|
}
|
||||||
|
|
||||||
var Dry bool
|
var Dry bool
|
||||||
var DryFlag = &cli.BoolFlag{
|
var DryFlag = &cli.BoolFlag{
|
||||||
Name: "dry-run",
|
Name: "dry-run, dr",
|
||||||
Usage: "Only reports changes that would be made",
|
Usage: "Only reports changes that would be made",
|
||||||
Value: false,
|
|
||||||
Aliases: []string{"d"},
|
|
||||||
Destination: &Dry,
|
Destination: &Dry,
|
||||||
}
|
}
|
||||||
|
|
||||||
var Publish bool
|
var Publish bool
|
||||||
var PublishFlag = &cli.BoolFlag{
|
var PublishFlag = &cli.BoolFlag{
|
||||||
Name: "publish",
|
Name: "publish, p",
|
||||||
Usage: "Publish changes to git.coopcloud.tech",
|
Usage: "Publish changes to git.coopcloud.tech",
|
||||||
Value: false,
|
|
||||||
Aliases: []string{"p"},
|
|
||||||
Destination: &Publish,
|
Destination: &Publish,
|
||||||
}
|
}
|
||||||
|
|
||||||
var Domain string
|
var Domain string
|
||||||
var DomainFlag = &cli.StringFlag{
|
var DomainFlag = &cli.StringFlag{
|
||||||
Name: "domain",
|
Name: "domain, dn",
|
||||||
Aliases: []string{"d"},
|
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Choose a domain name",
|
Usage: "Choose a domain name",
|
||||||
Destination: &Domain,
|
Destination: &Domain,
|
||||||
@ -339,8 +298,7 @@ var DomainFlag = &cli.StringFlag{
|
|||||||
|
|
||||||
var NewAppServer string
|
var NewAppServer string
|
||||||
var NewAppServerFlag = &cli.StringFlag{
|
var NewAppServerFlag = &cli.StringFlag{
|
||||||
Name: "server",
|
Name: "server, s",
|
||||||
Aliases: []string{"s"},
|
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Show apps of a specific server",
|
Usage: "Show apps of a specific server",
|
||||||
Destination: &NewAppServer,
|
Destination: &NewAppServer,
|
||||||
@ -348,8 +306,7 @@ var NewAppServerFlag = &cli.StringFlag{
|
|||||||
|
|
||||||
var NewAppName string
|
var NewAppName string
|
||||||
var NewAppNameFlag = &cli.StringFlag{
|
var NewAppNameFlag = &cli.StringFlag{
|
||||||
Name: "app-name",
|
Name: "app-name, a",
|
||||||
Aliases: []string{"a"},
|
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Choose an app name",
|
Usage: "Choose an app name",
|
||||||
Destination: &NewAppName,
|
Destination: &NewAppName,
|
||||||
@ -357,92 +314,67 @@ var NewAppNameFlag = &cli.StringFlag{
|
|||||||
|
|
||||||
var NoDomainChecks bool
|
var NoDomainChecks bool
|
||||||
var NoDomainChecksFlag = &cli.BoolFlag{
|
var NoDomainChecksFlag = &cli.BoolFlag{
|
||||||
Name: "no-domain-checks",
|
Name: "no-domain-checks, nd",
|
||||||
Aliases: []string{"nd"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Disable app domain sanity checks",
|
Usage: "Disable app domain sanity checks",
|
||||||
Destination: &NoDomainChecks,
|
Destination: &NoDomainChecks,
|
||||||
}
|
}
|
||||||
|
|
||||||
var StdErrOnly bool
|
var StdErrOnly bool
|
||||||
var StdErrOnlyFlag = &cli.BoolFlag{
|
var StdErrOnlyFlag = &cli.BoolFlag{
|
||||||
Name: "stderr",
|
Name: "stderr, s",
|
||||||
Aliases: []string{"s"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Only tail stderr",
|
Usage: "Only tail stderr",
|
||||||
Destination: &StdErrOnly,
|
Destination: &StdErrOnly,
|
||||||
}
|
}
|
||||||
|
|
||||||
var AutoDNSRecord bool
|
|
||||||
var AutoDNSRecordFlag = &cli.BoolFlag{
|
|
||||||
Name: "auto",
|
|
||||||
Aliases: []string{"a"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Automatically configure DNS records",
|
|
||||||
Destination: &AutoDNSRecord,
|
|
||||||
}
|
|
||||||
|
|
||||||
var DontWaitConverge bool
|
var DontWaitConverge bool
|
||||||
var DontWaitConvergeFlag = &cli.BoolFlag{
|
var DontWaitConvergeFlag = &cli.BoolFlag{
|
||||||
Name: "no-converge-checks",
|
Name: "no-converge-checks, nc",
|
||||||
Aliases: []string{"nc"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Don't wait for converge logic checks",
|
Usage: "Don't wait for converge logic checks",
|
||||||
Destination: &DontWaitConverge,
|
Destination: &DontWaitConverge,
|
||||||
}
|
}
|
||||||
|
|
||||||
var Watch bool
|
var Watch bool
|
||||||
var WatchFlag = &cli.BoolFlag{
|
var WatchFlag = &cli.BoolFlag{
|
||||||
Name: "watch",
|
Name: "watch, w",
|
||||||
Aliases: []string{"w"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Watch status by polling repeatedly",
|
Usage: "Watch status by polling repeatedly",
|
||||||
Destination: &Watch,
|
Destination: &Watch,
|
||||||
}
|
}
|
||||||
|
|
||||||
var OnlyErrors bool
|
var OnlyErrors bool
|
||||||
var OnlyErrorFlag = &cli.BoolFlag{
|
var OnlyErrorFlag = &cli.BoolFlag{
|
||||||
Name: "errors",
|
Name: "errors, e",
|
||||||
Aliases: []string{"e"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Only show errors",
|
Usage: "Only show errors",
|
||||||
Destination: &OnlyErrors,
|
Destination: &OnlyErrors,
|
||||||
}
|
}
|
||||||
|
|
||||||
var SkipUpdates bool
|
var SkipUpdates bool
|
||||||
var SkipUpdatesFlag = &cli.BoolFlag{
|
var SkipUpdatesFlag = &cli.BoolFlag{
|
||||||
Name: "skip-updates",
|
Name: "skip-updates, s",
|
||||||
Aliases: []string{"s"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Skip updating recipe repositories",
|
Usage: "Skip updating recipe repositories",
|
||||||
Destination: &SkipUpdates,
|
Destination: &SkipUpdates,
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegistryUsername string
|
var RegistryUsername string
|
||||||
var RegistryUsernameFlag = &cli.StringFlag{
|
var RegistryUsernameFlag = &cli.StringFlag{
|
||||||
Name: "username",
|
Name: "username, user",
|
||||||
Aliases: []string{"user"},
|
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Registry username",
|
Usage: "Registry username",
|
||||||
EnvVars: []string{"REGISTRY_USERNAME"},
|
EnvVar: "REGISTRY_USERNAME",
|
||||||
Destination: &RegistryUsername,
|
Destination: &RegistryUsername,
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegistryPassword string
|
var RegistryPassword string
|
||||||
var RegistryPasswordFlag = &cli.StringFlag{
|
var RegistryPasswordFlag = &cli.StringFlag{
|
||||||
Name: "password",
|
Name: "password, pass",
|
||||||
Aliases: []string{"pass"},
|
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Registry password",
|
Usage: "Registry password",
|
||||||
EnvVars: []string{"REGISTRY_PASSWORD"},
|
EnvVar: "REGISTRY_PASSWORD",
|
||||||
Destination: &RegistryUsername,
|
Destination: &RegistryUsername,
|
||||||
}
|
}
|
||||||
|
|
||||||
var AllTags bool
|
var AllTags bool
|
||||||
var AllTagsFlag = &cli.BoolFlag{
|
var AllTagsFlag = &cli.BoolFlag{
|
||||||
Name: "all-tags",
|
Name: "all-tags, a",
|
||||||
Aliases: []string{"a"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "List all tags, not just upgrades",
|
Usage: "List all tags, not just upgrades",
|
||||||
Destination: &AllTags,
|
Destination: &AllTags,
|
||||||
}
|
}
|
||||||
@ -495,3 +427,15 @@ Host foo.coopcloud.tech
|
|||||||
Good luck!
|
Good luck!
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// SubCommandBefore wires up pre-action machinery (e.g. --debug handling).
|
||||||
|
func SubCommandBefore(c *cli.Context) error {
|
||||||
|
if Debug {
|
||||||
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
logrus.SetFormatter(&logrus.TextFormatter{})
|
||||||
|
logrus.SetOutput(os.Stderr)
|
||||||
|
logrus.AddHook(logrusStack.StandardHook())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -17,7 +18,7 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeployAction is the main command-line action for this package
|
// DeployAction is the main command-line action for this package
|
||||||
@ -46,7 +47,7 @@ func DeployAction(c *cli.Context) error {
|
|||||||
|
|
||||||
logrus.Debugf("checking whether %s is already deployed", app.StackName())
|
logrus.Debugf("checking whether %s is already deployed", app.StackName())
|
||||||
|
|
||||||
isDeployed, deployedVersion, err := stack.IsDeployed(c.Context, cl, app.StackName())
|
isDeployed, deployedVersion, err := stack.IsDeployed(context.Background(), cl, app.StackName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShowSubcommandHelpAndError exits the program on error, logs the error to the
|
// ShowSubcommandHelpAndError exits the program on error, logs the error to the
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/ssh"
|
"coopcloud.tech/abra/pkg/ssh"
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AppSecrets represents all app secrest
|
// AppSecrets represents all app secrest
|
||||||
|
@ -3,8 +3,8 @@ package internal
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
"coopcloud.tech/abra/pkg/recipe"
|
"coopcloud.tech/abra/pkg/recipe"
|
||||||
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -94,7 +94,7 @@ func GetMainAppImage(recipe recipe.Recipe) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
path = reference.Path(img)
|
path = reference.Path(img)
|
||||||
path = recipePkg.StripTagMeta(path)
|
path = formatter.StripTagMeta(path)
|
||||||
|
|
||||||
return path, nil
|
return path, nil
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/ssh"
|
"coopcloud.tech/abra/pkg/ssh"
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AppName is used for configuring app name programmatically
|
// AppName is used for configuring app name programmatically
|
||||||
@ -160,9 +160,9 @@ func ValidateDomain(c *cli.Context) (string, error) {
|
|||||||
|
|
||||||
// ValidateSubCmdFlags ensures flag order conforms to correct order
|
// ValidateSubCmdFlags ensures flag order conforms to correct order
|
||||||
func ValidateSubCmdFlags(c *cli.Context) bool {
|
func ValidateSubCmdFlags(c *cli.Context) bool {
|
||||||
for argIdx, arg := range c.Args().Slice() {
|
for argIdx, arg := range c.Args() {
|
||||||
if !strings.HasPrefix(arg, "--") {
|
if !strings.HasPrefix(arg, "--") {
|
||||||
for _, flag := range c.Args().Slice()[argIdx:] {
|
for _, flag := range c.Args()[argIdx:] {
|
||||||
if strings.HasPrefix(flag, "--") {
|
if strings.HasPrefix(flag, "--") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -369,7 +369,7 @@ func EnsureNewCapsulVPSFlags(c *cli.Context) error {
|
|||||||
if err := survey.AskOne(prompt, &CapsulSSHKeys); err != nil {
|
if err := survey.AskOne(prompt, &CapsulSSHKeys); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
CapsulSSHKeys = *cli.NewStringSlice(strings.Split(sshKeys, ",")...)
|
CapsulSSHKeys = cli.StringSlice(strings.Split(sshKeys, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
if CapsulAPIToken == "" && !NoInput {
|
if CapsulAPIToken == "" && !NoInput {
|
||||||
@ -448,7 +448,7 @@ func EnsureNewHetznerCloudVPSFlags(c *cli.Context) error {
|
|||||||
if err := survey.AskOne(prompt, &sshKeys); err != nil {
|
if err := survey.AskOne(prompt, &sshKeys); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
HetznerCloudSSHKeys = *cli.NewStringSlice(strings.Split(sshKeys, ",")...)
|
HetznerCloudSSHKeys = cli.StringSlice(strings.Split(sshKeys, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !NoInput {
|
if !NoInput {
|
||||||
|
@ -9,15 +9,20 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/lint"
|
"coopcloud.tech/abra/pkg/lint"
|
||||||
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var recipeLintCommand = &cli.Command{
|
var recipeLintCommand = cli.Command{
|
||||||
Name: "lint",
|
Name: "lint",
|
||||||
Usage: "Lint a recipe",
|
Usage: "Lint a recipe",
|
||||||
Aliases: []string{"l"},
|
Aliases: []string{"l"},
|
||||||
ArgsUsage: "<recipe>",
|
ArgsUsage: "<recipe>",
|
||||||
Flags: []cli.Flag{internal.OnlyErrorFlag},
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
internal.OnlyErrorFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
BashComplete: autocomplete.RecipeNameComplete,
|
BashComplete: autocomplete.RecipeNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
recipe := internal.ValidateRecipe(c)
|
recipe := internal.ValidateRecipe(c)
|
||||||
|
@ -6,28 +6,31 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"coopcloud.tech/abra/cli/internal"
|
||||||
"coopcloud.tech/abra/pkg/formatter"
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
"coopcloud.tech/abra/pkg/recipe"
|
"coopcloud.tech/abra/pkg/recipe"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pattern string
|
var pattern string
|
||||||
var patternFlag = &cli.StringFlag{
|
var patternFlag = &cli.StringFlag{
|
||||||
Name: "pattern",
|
Name: "pattern, p",
|
||||||
Value: "",
|
Value: "",
|
||||||
Aliases: []string{"p"},
|
|
||||||
Usage: "Simple string to filter recipes",
|
Usage: "Simple string to filter recipes",
|
||||||
Destination: &pattern,
|
Destination: &pattern,
|
||||||
}
|
}
|
||||||
|
|
||||||
var recipeListCommand = &cli.Command{
|
var recipeListCommand = cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List available recipes",
|
Usage: "List available recipes",
|
||||||
Aliases: []string{"ls"},
|
Aliases: []string{"ls"},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
patternFlag,
|
patternFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
catl, err := recipe.ReadRecipeCatalogue()
|
catl, err := recipe.ReadRecipeCatalogue()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"coopcloud.tech/abra/pkg/git"
|
"coopcloud.tech/abra/pkg/git"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// recipeMetadata is the recipe metadata for the README.md
|
// recipeMetadata is the recipe metadata for the README.md
|
||||||
@ -30,10 +30,15 @@ type recipeMetadata struct {
|
|||||||
SSO string
|
SSO string
|
||||||
}
|
}
|
||||||
|
|
||||||
var recipeNewCommand = &cli.Command{
|
var recipeNewCommand = cli.Command{
|
||||||
Name: "new",
|
Name: "new",
|
||||||
Usage: "Create a new recipe",
|
|
||||||
Aliases: []string{"n"},
|
Aliases: []string{"n"},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
|
Usage: "Create a new recipe",
|
||||||
ArgsUsage: "<recipe>",
|
ArgsUsage: "<recipe>",
|
||||||
Description: `
|
Description: `
|
||||||
This command creates a new recipe.
|
This command creates a new recipe.
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package recipe
|
package recipe
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RecipeCommand defines all recipe related sub-commands.
|
// RecipeCommand defines all recipe related sub-commands.
|
||||||
var RecipeCommand = &cli.Command{
|
var RecipeCommand = cli.Command{
|
||||||
Name: "recipe",
|
Name: "recipe",
|
||||||
|
Aliases: []string{"r"},
|
||||||
Usage: "Manage recipes",
|
Usage: "Manage recipes",
|
||||||
ArgsUsage: "<recipe>",
|
ArgsUsage: "<recipe>",
|
||||||
Aliases: []string{"r"},
|
|
||||||
Description: `
|
Description: `
|
||||||
A recipe is a blueprint for an app. It is a bunch of config files which
|
A recipe is a blueprint for an app. It is a bunch of config files which
|
||||||
describe how to deploy and maintain an app. Recipes are maintained by the Co-op
|
describe how to deploy and maintain an app. Recipes are maintained by the Co-op
|
||||||
@ -20,7 +20,7 @@ sure the recipe is in good working order and the config upgraded in a timely
|
|||||||
manner. Abra supports convenient automation for recipe maintainenace, see the
|
manner. Abra supports convenient automation for recipe maintainenace, see the
|
||||||
"abra recipe upgrade", "abra recipe sync" and "abra recipe release" commands.
|
"abra recipe upgrade", "abra recipe sync" and "abra recipe release" commands.
|
||||||
`,
|
`,
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []cli.Command{
|
||||||
recipeListCommand,
|
recipeListCommand,
|
||||||
recipeVersionCommand,
|
recipeVersionCommand,
|
||||||
recipeReleaseCommand,
|
recipeReleaseCommand,
|
||||||
|
@ -18,13 +18,13 @@ import (
|
|||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var recipeReleaseCommand = &cli.Command{
|
var recipeReleaseCommand = cli.Command{
|
||||||
Name: "release",
|
Name: "release",
|
||||||
Usage: "Release a new recipe version",
|
|
||||||
Aliases: []string{"rl"},
|
Aliases: []string{"rl"},
|
||||||
|
Usage: "Release a new recipe version",
|
||||||
ArgsUsage: "<recipe> [<version>]",
|
ArgsUsage: "<recipe> [<version>]",
|
||||||
Description: `
|
Description: `
|
||||||
This command is used to specify a new version of a recipe. These versions are
|
This command is used to specify a new version of a recipe. These versions are
|
||||||
@ -48,12 +48,15 @@ requires that you have permission to git push to these repositories and have
|
|||||||
your SSH keys configured on your account.
|
your SSH keys configured on your account.
|
||||||
`,
|
`,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.DryFlag,
|
internal.DryFlag,
|
||||||
internal.MajorFlag,
|
internal.MajorFlag,
|
||||||
internal.MinorFlag,
|
internal.MinorFlag,
|
||||||
internal.PatchFlag,
|
internal.PatchFlag,
|
||||||
internal.PublishFlag,
|
internal.PublishFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
BashComplete: autocomplete.RecipeNameComplete,
|
BashComplete: autocomplete.RecipeNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
recipe := internal.ValidateRecipeWithPrompt(c)
|
recipe := internal.ValidateRecipeWithPrompt(c)
|
||||||
@ -140,7 +143,7 @@ func getImageVersions(recipe recipe.Recipe) (map[string]string, error) {
|
|||||||
|
|
||||||
path := reference.Path(img)
|
path := reference.Path(img)
|
||||||
|
|
||||||
path = recipePkg.StripTagMeta(path)
|
path = formatter.StripTagMeta(path)
|
||||||
|
|
||||||
var tag string
|
var tag string
|
||||||
switch img.(type) {
|
switch img.(type) {
|
||||||
|
@ -13,20 +13,23 @@ import (
|
|||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var recipeSyncCommand = &cli.Command{
|
var recipeSyncCommand = cli.Command{
|
||||||
Name: "sync",
|
Name: "sync",
|
||||||
Usage: "Sync recipe version label",
|
|
||||||
Aliases: []string{"s"},
|
Aliases: []string{"s"},
|
||||||
|
Usage: "Sync recipe version label",
|
||||||
ArgsUsage: "<recipe> [<version>]",
|
ArgsUsage: "<recipe> [<version>]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.DryFlag,
|
internal.DryFlag,
|
||||||
internal.MajorFlag,
|
internal.MajorFlag,
|
||||||
internal.MinorFlag,
|
internal.MinorFlag,
|
||||||
internal.PatchFlag,
|
internal.PatchFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Description: `
|
Description: `
|
||||||
This command will generate labels for the main recipe service (i.e. by
|
This command will generate labels for the main recipe service (i.e. by
|
||||||
convention, the service named 'app') which corresponds to the following format:
|
convention, the service named 'app') which corresponds to the following format:
|
||||||
|
@ -12,12 +12,13 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/autocomplete"
|
"coopcloud.tech/abra/pkg/autocomplete"
|
||||||
"coopcloud.tech/abra/pkg/client"
|
"coopcloud.tech/abra/pkg/client"
|
||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
||||||
"coopcloud.tech/tagcmp"
|
"coopcloud.tech/tagcmp"
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
type imgPin struct {
|
type imgPin struct {
|
||||||
@ -25,10 +26,10 @@ type imgPin struct {
|
|||||||
version tagcmp.Tag
|
version tagcmp.Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
var recipeUpgradeCommand = &cli.Command{
|
var recipeUpgradeCommand = cli.Command{
|
||||||
Name: "upgrade",
|
Name: "upgrade",
|
||||||
Usage: "Upgrade recipe image tags",
|
|
||||||
Aliases: []string{"u"},
|
Aliases: []string{"u"},
|
||||||
|
Usage: "Upgrade recipe image tags",
|
||||||
Description: `
|
Description: `
|
||||||
This command reads and attempts to parse all image tags within the given
|
This command reads and attempts to parse all image tags within the given
|
||||||
<recipe> configuration and prompt with more recent tags to upgrade to. It will
|
<recipe> configuration and prompt with more recent tags to upgrade to. It will
|
||||||
@ -50,11 +51,14 @@ You may invoke this command in "wizard" mode and be prompted for input:
|
|||||||
BashComplete: autocomplete.RecipeNameComplete,
|
BashComplete: autocomplete.RecipeNameComplete,
|
||||||
ArgsUsage: "<recipe>",
|
ArgsUsage: "<recipe>",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.PatchFlag,
|
internal.PatchFlag,
|
||||||
internal.MinorFlag,
|
internal.MinorFlag,
|
||||||
internal.MajorFlag,
|
internal.MajorFlag,
|
||||||
internal.AllTagsFlag,
|
internal.AllTagsFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
recipe := internal.ValidateRecipeWithPrompt(c)
|
recipe := internal.ValidateRecipeWithPrompt(c)
|
||||||
|
|
||||||
@ -116,7 +120,7 @@ You may invoke this command in "wizard" mode and be prompted for input:
|
|||||||
}
|
}
|
||||||
logrus.Debugf("retrieved %s from remote registry for %s", regVersions, image)
|
logrus.Debugf("retrieved %s from remote registry for %s", regVersions, image)
|
||||||
|
|
||||||
image = recipePkg.StripTagMeta(image)
|
image = formatter.StripTagMeta(image)
|
||||||
|
|
||||||
switch img.(type) {
|
switch img.(type) {
|
||||||
case reference.NamedTagged:
|
case reference.NamedTagged:
|
||||||
@ -153,7 +157,7 @@ You may invoke this command in "wizard" mode and be prompted for input:
|
|||||||
sort.Sort(tagcmp.ByTagDesc(compatible))
|
sort.Sort(tagcmp.ByTagDesc(compatible))
|
||||||
|
|
||||||
if len(compatible) == 0 && !internal.AllTags {
|
if len(compatible) == 0 && !internal.AllTags {
|
||||||
logrus.Info(fmt.Sprintf("no new versions available for %s, %s is the latest", image, tag))
|
logrus.Info(fmt.Sprintf("no new versions available for %s, assuming %s is the latest (use -a/--all-tags to see all anyway)", image, tag))
|
||||||
continue // skip on to the next tag and don't update any compose files
|
continue // skip on to the next tag and don't update any compose files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,14 +6,19 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/formatter"
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var recipeVersionCommand = &cli.Command{
|
var recipeVersionCommand = cli.Command{
|
||||||
Name: "versions",
|
Name: "versions",
|
||||||
Usage: "List recipe versions",
|
|
||||||
Aliases: []string{"v"},
|
Aliases: []string{"v"},
|
||||||
|
Usage: "List recipe versions",
|
||||||
ArgsUsage: "<recipe>",
|
ArgsUsage: "<recipe>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
BashComplete: autocomplete.RecipeNameComplete,
|
BashComplete: autocomplete.RecipeNameComplete,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
recipe := internal.ValidateRecipe(c)
|
recipe := internal.ValidateRecipe(c)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package record
|
package record
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -9,18 +10,21 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/formatter"
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
"github.com/libdns/gandi"
|
"github.com/libdns/gandi"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RecordListCommand lists domains.
|
// RecordListCommand lists domains.
|
||||||
var RecordListCommand = &cli.Command{
|
var RecordListCommand = cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List domain name records",
|
Usage: "List domain name records",
|
||||||
Aliases: []string{"ls"},
|
Aliases: []string{"ls"},
|
||||||
ArgsUsage: "<zone>",
|
ArgsUsage: "<zone>",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.DNSProviderFlag,
|
internal.DNSProviderFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Description: `
|
Description: `
|
||||||
This command lists all domain name records managed by a 3rd party provider for
|
This command lists all domain name records managed by a 3rd party provider for
|
||||||
a specific zone.
|
a specific zone.
|
||||||
@ -49,7 +53,7 @@ are listed. This zone must already be created on your provider account.
|
|||||||
logrus.Fatalf("%s is not a supported DNS provider", internal.DNSProvider)
|
logrus.Fatalf("%s is not a supported DNS provider", internal.DNSProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.GetRecords(c.Context, zone)
|
records, err := provider.GetRecords(context.Background(), zone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package record
|
package record
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -11,24 +12,26 @@ import (
|
|||||||
"github.com/libdns/gandi"
|
"github.com/libdns/gandi"
|
||||||
"github.com/libdns/libdns"
|
"github.com/libdns/libdns"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RecordNewCommand creates a new domain name record.
|
// RecordNewCommand creates a new domain name record.
|
||||||
var RecordNewCommand = &cli.Command{
|
var RecordNewCommand = cli.Command{
|
||||||
Name: "new",
|
Name: "new",
|
||||||
Usage: "Create a new domain record",
|
Usage: "Create a new domain record",
|
||||||
Aliases: []string{"n"},
|
Aliases: []string{"n"},
|
||||||
ArgsUsage: "<zone>",
|
ArgsUsage: "<zone>",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.DNSProviderFlag,
|
internal.DNSProviderFlag,
|
||||||
internal.DNSTypeFlag,
|
internal.DNSTypeFlag,
|
||||||
internal.DNSNameFlag,
|
internal.DNSNameFlag,
|
||||||
internal.DNSValueFlag,
|
internal.DNSValueFlag,
|
||||||
internal.DNSTTLFlag,
|
internal.DNSTTLFlag,
|
||||||
internal.DNSPriorityFlag,
|
internal.DNSPriorityFlag,
|
||||||
internal.AutoDNSRecordFlag,
|
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Description: `
|
Description: `
|
||||||
This command creates a new domain name record for a specific zone.
|
This command creates a new domain name record for a specific zone.
|
||||||
|
|
||||||
@ -39,13 +42,7 @@ Example:
|
|||||||
|
|
||||||
abra record new foo.com -p gandi -t A -n myapp -v 192.168.178.44
|
abra record new foo.com -p gandi -t A -n myapp -v 192.168.178.44
|
||||||
|
|
||||||
Typically, you need two records, an A record which points at the zone (@.) and
|
You may also invoke this command in "wizard" mode and be prompted for input:
|
||||||
a wildcard record for your apps (*.). Pass "--auto" to have Abra automatically
|
|
||||||
set this up.
|
|
||||||
|
|
||||||
abra record new --auto foo.com -p gandi -v 192.168.178.44
|
|
||||||
|
|
||||||
You may also invoke this command in "wizard" mode and be prompted for input
|
|
||||||
|
|
||||||
abra record new
|
abra record new
|
||||||
|
|
||||||
@ -71,25 +68,6 @@ You may also invoke this command in "wizard" mode and be prompted for input
|
|||||||
logrus.Fatalf("%s is not a supported DNS provider", internal.DNSProvider)
|
logrus.Fatalf("%s is not a supported DNS provider", internal.DNSProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
if internal.AutoDNSRecord {
|
|
||||||
ipv4, err := dns.EnsureIPv4(zone)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Debugf("no ipv4 associated with %s, prompting for input", zone)
|
|
||||||
if err := internal.EnsureDNSValueFlag(c); err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
ipv4 = internal.DNSValue
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Infof("automatically configuring @./*. A records for %s for %s (--auto)", zone, ipv4)
|
|
||||||
|
|
||||||
if err := autoConfigure(c, &provider, zone, ipv4); err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := internal.EnsureDNSTypeFlag(c); err != nil {
|
if err := internal.EnsureDNSTypeFlag(c); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -118,7 +96,7 @@ You may also invoke this command in "wizard" mode and be prompted for input
|
|||||||
record.Priority = internal.DNSPriority
|
record.Priority = internal.DNSPriority
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.GetRecords(c.Context, zone)
|
records, err := provider.GetRecords(context.Background(), zone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -132,7 +110,7 @@ You may also invoke this command in "wizard" mode and be prompted for input
|
|||||||
}
|
}
|
||||||
|
|
||||||
createdRecords, err := provider.SetRecords(
|
createdRecords, err := provider.SetRecords(
|
||||||
c.Context,
|
context.Background(),
|
||||||
zone,
|
zone,
|
||||||
[]libdns.Record{record},
|
[]libdns.Record{record},
|
||||||
)
|
)
|
||||||
@ -169,84 +147,3 @@ You may also invoke this command in "wizard" mode and be prompted for input
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoConfigure(c *cli.Context, provider *gandi.Provider, zone, ipv4 string) error {
|
|
||||||
ttl, err := dns.GetTTL(internal.DNSTTL)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
atRecord := libdns.Record{
|
|
||||||
Type: "A",
|
|
||||||
Name: "@",
|
|
||||||
Value: ipv4,
|
|
||||||
TTL: ttl,
|
|
||||||
}
|
|
||||||
|
|
||||||
wildcardRecord := libdns.Record{
|
|
||||||
Type: "A",
|
|
||||||
Name: "*",
|
|
||||||
Value: ipv4,
|
|
||||||
TTL: ttl,
|
|
||||||
}
|
|
||||||
|
|
||||||
records := []libdns.Record{atRecord, wildcardRecord}
|
|
||||||
|
|
||||||
tableCol := []string{"type", "name", "value", "TTL", "priority"}
|
|
||||||
table := formatter.CreateTable(tableCol)
|
|
||||||
|
|
||||||
for _, record := range records {
|
|
||||||
existingRecords, err := provider.GetRecords(c.Context, zone)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
discovered := false
|
|
||||||
for _, existingRecord := range existingRecords {
|
|
||||||
if existingRecord.Type == record.Type &&
|
|
||||||
existingRecord.Name == record.Name &&
|
|
||||||
existingRecord.Value == record.Value {
|
|
||||||
logrus.Warnf("%s record: %s %s for %s already exists?", record.Type, record.Name, record.Value, zone)
|
|
||||||
discovered = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if discovered {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
createdRecords, err := provider.SetRecords(
|
|
||||||
c.Context,
|
|
||||||
zone,
|
|
||||||
[]libdns.Record{record},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(createdRecords) == 0 {
|
|
||||||
return fmt.Errorf("provider library reports that no record was created?")
|
|
||||||
}
|
|
||||||
|
|
||||||
createdRecord := createdRecords[0]
|
|
||||||
|
|
||||||
value := createdRecord.Value
|
|
||||||
if len(createdRecord.Value) > 30 {
|
|
||||||
value = fmt.Sprintf("%s...", createdRecord.Value[:30])
|
|
||||||
}
|
|
||||||
|
|
||||||
table.Append([]string{
|
|
||||||
createdRecord.Type,
|
|
||||||
createdRecord.Name,
|
|
||||||
value,
|
|
||||||
createdRecord.TTL.String(),
|
|
||||||
strconv.Itoa(createdRecord.Priority),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if table.NumLines() > 0 {
|
|
||||||
table.Render()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package record
|
package record
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RecordCommand supports managing DNS entries.
|
// RecordCommand supports managing DNS entries.
|
||||||
var RecordCommand = &cli.Command{
|
var RecordCommand = cli.Command{
|
||||||
Name: "record",
|
Name: "record",
|
||||||
Usage: "Manage domain name records",
|
Usage: "Manage domain name records",
|
||||||
Aliases: []string{"rc"},
|
Aliases: []string{"rc"},
|
||||||
@ -30,7 +30,7 @@ to implement new provider support easily.
|
|||||||
https://pkg.go.dev/github.com/libdns/libdns
|
https://pkg.go.dev/github.com/libdns/libdns
|
||||||
|
|
||||||
`,
|
`,
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []cli.Command{
|
||||||
RecordListCommand,
|
RecordListCommand,
|
||||||
RecordNewCommand,
|
RecordNewCommand,
|
||||||
RecordRemoveCommand,
|
RecordRemoveCommand,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package record
|
package record
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -11,20 +12,23 @@ import (
|
|||||||
"github.com/libdns/gandi"
|
"github.com/libdns/gandi"
|
||||||
"github.com/libdns/libdns"
|
"github.com/libdns/libdns"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RecordRemoveCommand lists domains.
|
// RecordRemoveCommand lists domains.
|
||||||
var RecordRemoveCommand = &cli.Command{
|
var RecordRemoveCommand = cli.Command{
|
||||||
Name: "remove",
|
Name: "remove",
|
||||||
Usage: "Remove a domain name record",
|
Usage: "Remove a domain name record",
|
||||||
Aliases: []string{"rm"},
|
Aliases: []string{"rm"},
|
||||||
ArgsUsage: "<zone>",
|
ArgsUsage: "<zone>",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
internal.DNSProviderFlag,
|
internal.DNSProviderFlag,
|
||||||
internal.DNSTypeFlag,
|
internal.DNSTypeFlag,
|
||||||
internal.DNSNameFlag,
|
internal.DNSNameFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Description: `
|
Description: `
|
||||||
This command removes a domain name record for a specific zone.
|
This command removes a domain name record for a specific zone.
|
||||||
|
|
||||||
@ -37,7 +41,7 @@ Example:
|
|||||||
|
|
||||||
abra record remove foo.com -p gandi -t A -n myapp
|
abra record remove foo.com -p gandi -t A -n myapp
|
||||||
|
|
||||||
You may also invoke this command in "wizard" mode and be prompted for input
|
You may also invoke this command in "wizard" mode and be prompted for input:
|
||||||
|
|
||||||
abra record rm
|
abra record rm
|
||||||
`,
|
`,
|
||||||
@ -70,7 +74,7 @@ You may also invoke this command in "wizard" mode and be prompted for input
|
|||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := provider.GetRecords(c.Context, zone)
|
records, err := provider.GetRecords(context.Background(), zone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -120,7 +124,7 @@ You may also invoke this command in "wizard" mode and be prompted for input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = provider.DeleteRecords(c.Context, zone, []libdns.Record{toDelete})
|
_, err = provider.DeleteRecords(context.Background(), zone, []libdns.Record{toDelete})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ import (
|
|||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
dockerClient "github.com/docker/docker/client"
|
dockerClient "github.com/docker/docker/client"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -47,26 +47,21 @@ source for this script can be seen here:
|
|||||||
|
|
||||||
var local bool
|
var local bool
|
||||||
var localFlag = &cli.BoolFlag{
|
var localFlag = &cli.BoolFlag{
|
||||||
Name: "local",
|
Name: "local, l",
|
||||||
Aliases: []string{"l"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Use local server",
|
Usage: "Use local server",
|
||||||
Destination: &local,
|
Destination: &local,
|
||||||
}
|
}
|
||||||
|
|
||||||
var provision bool
|
var provision bool
|
||||||
var provisionFlag = &cli.BoolFlag{
|
var provisionFlag = &cli.BoolFlag{
|
||||||
Name: "provision",
|
Name: "provision, p",
|
||||||
Aliases: []string{"p"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Provision server so it can deploy apps",
|
Usage: "Provision server so it can deploy apps",
|
||||||
Destination: &provision,
|
Destination: &provision,
|
||||||
}
|
}
|
||||||
|
|
||||||
var sshAuth string
|
var sshAuth string
|
||||||
var sshAuthFlag = &cli.StringFlag{
|
var sshAuthFlag = &cli.StringFlag{
|
||||||
Name: "ssh-auth",
|
Name: "ssh-auth, sh",
|
||||||
Aliases: []string{"sh"},
|
|
||||||
Value: "identity-file",
|
Value: "identity-file",
|
||||||
Usage: "Select SSH authentication method (identity-file, password)",
|
Usage: "Select SSH authentication method (identity-file, password)",
|
||||||
Destination: &sshAuth,
|
Destination: &sshAuth,
|
||||||
@ -74,22 +69,11 @@ var sshAuthFlag = &cli.StringFlag{
|
|||||||
|
|
||||||
var askSudoPass bool
|
var askSudoPass bool
|
||||||
var askSudoPassFlag = &cli.BoolFlag{
|
var askSudoPassFlag = &cli.BoolFlag{
|
||||||
Name: "ask-sudo-pass",
|
Name: "ask-sudo-pass, as",
|
||||||
Aliases: []string{"as"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Ask for sudo password",
|
Usage: "Ask for sudo password",
|
||||||
Destination: &askSudoPass,
|
Destination: &askSudoPass,
|
||||||
}
|
}
|
||||||
|
|
||||||
var traefik bool
|
|
||||||
var traefikFlag = &cli.BoolFlag{
|
|
||||||
Name: "traefik",
|
|
||||||
Aliases: []string{"t"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Deploy traefik",
|
|
||||||
Destination: &traefik,
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanUp(domainName string) {
|
func cleanUp(domainName string) {
|
||||||
logrus.Warnf("cleaning up context for %s", domainName)
|
logrus.Warnf("cleaning up context for %s", domainName)
|
||||||
if err := client.DeleteContext(domainName); err != nil {
|
if err := client.DeleteContext(domainName); err != nil {
|
||||||
@ -163,12 +147,6 @@ func newLocalServer(c *cli.Context, domainName string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if traefik {
|
|
||||||
if err := deployTraefik(c, cl, domainName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Info("local server has been added")
|
logrus.Info("local server has been added")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -320,7 +298,7 @@ If nothing works, you try running the Docker install script manually on your ser
|
|||||||
|
|
||||||
func initSwarmLocal(c *cli.Context, cl *dockerClient.Client, domainName string) error {
|
func initSwarmLocal(c *cli.Context, cl *dockerClient.Client, domainName string) error {
|
||||||
initReq := swarm.InitRequest{ListenAddr: "0.0.0.0:2377"}
|
initReq := swarm.InitRequest{ListenAddr: "0.0.0.0:2377"}
|
||||||
if _, err := cl.SwarmInit(c.Context, initReq); err != nil {
|
if _, err := cl.SwarmInit(context.Background(), initReq); err != nil {
|
||||||
if strings.Contains(err.Error(), "is already part of a swarm") ||
|
if strings.Contains(err.Error(), "is already part of a swarm") ||
|
||||||
strings.Contains(err.Error(), "must specify a listening address") {
|
strings.Contains(err.Error(), "must specify a listening address") {
|
||||||
logrus.Infof("swarm mode already initialised on %s", domainName)
|
logrus.Infof("swarm mode already initialised on %s", domainName)
|
||||||
@ -332,7 +310,7 @@ func initSwarmLocal(c *cli.Context, cl *dockerClient.Client, domainName string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
netOpts := types.NetworkCreate{Driver: "overlay", Scope: "swarm"}
|
netOpts := types.NetworkCreate{Driver: "overlay", Scope: "swarm"}
|
||||||
if _, err := cl.NetworkCreate(c.Context, "proxy", netOpts); err != nil {
|
if _, err := cl.NetworkCreate(context.Background(), "proxy", netOpts); err != nil {
|
||||||
if !strings.Contains(err.Error(), "proxy already exists") {
|
if !strings.Contains(err.Error(), "proxy already exists") {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -354,7 +332,7 @@ func initSwarm(c *cli.Context, cl *dockerClient.Client, domainName string) error
|
|||||||
ListenAddr: "0.0.0.0:2377",
|
ListenAddr: "0.0.0.0:2377",
|
||||||
AdvertiseAddr: ipv4,
|
AdvertiseAddr: ipv4,
|
||||||
}
|
}
|
||||||
if _, err := cl.SwarmInit(c.Context, initReq); err != nil {
|
if _, err := cl.SwarmInit(context.Background(), initReq); err != nil {
|
||||||
if strings.Contains(err.Error(), "is already part of a swarm") ||
|
if strings.Contains(err.Error(), "is already part of a swarm") ||
|
||||||
strings.Contains(err.Error(), "must specify a listening address") {
|
strings.Contains(err.Error(), "must specify a listening address") {
|
||||||
logrus.Infof("swarm mode already initialised on %s", domainName)
|
logrus.Infof("swarm mode already initialised on %s", domainName)
|
||||||
@ -366,7 +344,7 @@ func initSwarm(c *cli.Context, cl *dockerClient.Client, domainName string) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
netOpts := types.NetworkCreate{Driver: "overlay", Scope: "swarm"}
|
netOpts := types.NetworkCreate{Driver: "overlay", Scope: "swarm"}
|
||||||
if _, err := cl.NetworkCreate(c.Context, "proxy", netOpts); err != nil {
|
if _, err := cl.NetworkCreate(context.Background(), "proxy", netOpts); err != nil {
|
||||||
if !strings.Contains(err.Error(), "proxy already exists") {
|
if !strings.Contains(err.Error(), "proxy already exists") {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -388,34 +366,9 @@ func createServerDir(domainName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deployTraefik(c *cli.Context, cl *dockerClient.Client, domainName string) error {
|
var serverAddCommand = cli.Command{
|
||||||
internal.NoInput = true
|
|
||||||
|
|
||||||
internal.RecipeName = "traefik"
|
|
||||||
internal.NewAppServer = domainName
|
|
||||||
internal.Domain = fmt.Sprintf("%s.%s", "traefik", domainName)
|
|
||||||
internal.NewAppName = fmt.Sprintf("%s_%s", "traefik", config.SanitiseAppName(domainName))
|
|
||||||
|
|
||||||
appEnvPath := path.Join(config.ABRA_DIR, "servers", internal.Domain, fmt.Sprintf("%s.env", internal.NewAppName))
|
|
||||||
if _, err := os.Stat(appEnvPath); os.IsNotExist(err) {
|
|
||||||
logrus.Info(fmt.Sprintf("-t/--traefik specified, automatically deploying traefik to %s", internal.NewAppServer))
|
|
||||||
if err := internal.NewAction(c); err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logrus.Infof("%s already exists, not creating again", appEnvPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal.AppName = internal.NewAppName
|
|
||||||
if err := internal.DeployAction(c); err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var serverAddCommand = &cli.Command{
|
|
||||||
Name: "add",
|
Name: "add",
|
||||||
|
Aliases: []string{"a"},
|
||||||
Usage: "Add a server to your configuration",
|
Usage: "Add a server to your configuration",
|
||||||
Description: `
|
Description: `
|
||||||
This command adds a new server to your configuration so that it can be managed
|
This command adds a new server to your configuration so that it can be managed
|
||||||
@ -451,7 +404,7 @@ system username to make an initial connection. You can use the <user> and
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
abra server add --provision --traefik varia.zone glodemodem 12345
|
abra server add --provision varia.zone glodemodem 12345
|
||||||
|
|
||||||
Abra will construct the following SSH connection and Docker context:
|
Abra will construct the following SSH connection and Docker context:
|
||||||
|
|
||||||
@ -459,25 +412,22 @@ Abra will construct the following SSH connection and Docker context:
|
|||||||
|
|
||||||
All communication between Abra and the server will use this SSH connection.
|
All communication between Abra and the server will use this SSH connection.
|
||||||
|
|
||||||
In this example, Abra will run the following operations:
|
In this example, Abra will install Docker and initialise swarm mode.
|
||||||
|
|
||||||
1. Install Docker
|
|
||||||
2. Initialise Swarm mode
|
|
||||||
3. Deploy Traefik (core web proxy)
|
|
||||||
|
|
||||||
You may omit flags to avoid performing this provisioning logic.
|
You may omit flags to avoid performing this provisioning logic.
|
||||||
`,
|
`,
|
||||||
Aliases: []string{"a"},
|
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
localFlag,
|
localFlag,
|
||||||
provisionFlag,
|
provisionFlag,
|
||||||
sshAuthFlag,
|
sshAuthFlag,
|
||||||
askSudoPassFlag,
|
askSudoPassFlag,
|
||||||
traefikFlag,
|
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
ArgsUsage: "<domain> [<user>] [<port>]",
|
ArgsUsage: "<domain> [<user>] [<port>]",
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
if c.Args().Len() > 0 && local || !internal.ValidateSubCmdFlags(c) {
|
if len(c.Args()) > 0 && local || !internal.ValidateSubCmdFlags(c) {
|
||||||
err := errors.New("cannot use <domain> and --local together")
|
err := errors.New("cannot use <domain> and --local together")
|
||||||
internal.ShowSubcommandHelpAndError(c, err)
|
internal.ShowSubcommandHelpAndError(c, err)
|
||||||
}
|
}
|
||||||
@ -543,17 +493,11 @@ You may omit flags to avoid performing this provisioning logic.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := cl.Info(c.Context); err != nil {
|
if _, err := cl.Info(context.Background()); err != nil {
|
||||||
cleanUp(domainName)
|
cleanUp(domainName)
|
||||||
logrus.Fatalf("couldn't make a remote docker connection to %s? use --provision/-p to attempt to install", domainName)
|
logrus.Fatalf("couldn't make a remote docker connection to %s? use --provision/-p to attempt to install", domainName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if traefik {
|
|
||||||
if err := deployTraefik(c, cl, domainName); err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,24 @@ package server
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"coopcloud.tech/abra/cli/internal"
|
||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"coopcloud.tech/abra/pkg/context"
|
"coopcloud.tech/abra/pkg/context"
|
||||||
"coopcloud.tech/abra/pkg/formatter"
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
"github.com/docker/cli/cli/connhelper/ssh"
|
"github.com/docker/cli/cli/connhelper/ssh"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var serverListCommand = &cli.Command{
|
var serverListCommand = cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Aliases: []string{"ls"},
|
Aliases: []string{"ls"},
|
||||||
Usage: "List managed servers",
|
Usage: "List managed servers",
|
||||||
ArgsUsage: " ",
|
Flags: []cli.Flag{
|
||||||
HideHelp: true,
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
dockerContextStore := context.NewDefaultDockerContextStore()
|
dockerContextStore := context.NewDefaultDockerContextStore()
|
||||||
contexts, err := dockerContextStore.Store.List()
|
contexts, err := dockerContextStore.Store.List()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ import (
|
|||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/hetznercloud/hcloud-go/hcloud"
|
"github.com/hetznercloud/hcloud-go/hcloud"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newHetznerCloudVPS(c *cli.Context) error {
|
func newHetznerCloudVPS(c *cli.Context) error {
|
||||||
@ -27,7 +28,7 @@ func newHetznerCloudVPS(c *cli.Context) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
sshKey, _, err := client.SSHKey.GetByName(c.Context, sshKey)
|
sshKey, _, err := client.SSHKey.GetByName(context.Background(), sshKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -72,7 +73,7 @@ func newHetznerCloudVPS(c *cli.Context) error {
|
|||||||
logrus.Fatal("exiting as requested")
|
logrus.Fatal("exiting as requested")
|
||||||
}
|
}
|
||||||
|
|
||||||
res, _, err := client.Server.Create(c.Context, serverOpts)
|
res, _, err := client.Server.Create(context.Background(), serverOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -110,9 +111,6 @@ bar.example.com).
|
|||||||
@ 1800 IN A %s
|
@ 1800 IN A %s
|
||||||
* 1800 IN A %s
|
* 1800 IN A %s
|
||||||
|
|
||||||
"abra record new --auto" can help you do this quickly if you use a supported
|
|
||||||
DNS provider.
|
|
||||||
|
|
||||||
`,
|
`,
|
||||||
internal.HetznerCloudName, ip, rootPassword,
|
internal.HetznerCloudName, ip, rootPassword,
|
||||||
ip, ip, ip,
|
ip, ip, ip,
|
||||||
@ -200,7 +198,7 @@ bar.example.com).
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var serverNewCommand = &cli.Command{
|
var serverNewCommand = cli.Command{
|
||||||
Name: "new",
|
Name: "new",
|
||||||
Aliases: []string{"n"},
|
Aliases: []string{"n"},
|
||||||
Usage: "Create a new server using a 3rd party provider",
|
Usage: "Create a new server using a 3rd party provider",
|
||||||
@ -223,7 +221,12 @@ API tokens are read from the environment if specified, e.g.
|
|||||||
Where "$provider_TOKEN" is the expected env var format.
|
Where "$provider_TOKEN" is the expected env var format.
|
||||||
`,
|
`,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
|
||||||
internal.ServerProviderFlag,
|
internal.ServerProviderFlag,
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
|
|
||||||
// Capsul
|
// Capsul
|
||||||
internal.CapsulInstanceURLFlag,
|
internal.CapsulInstanceURLFlag,
|
||||||
@ -240,6 +243,7 @@ Where "$provider_TOKEN" is the expected env var format.
|
|||||||
internal.HetznerCloudLocationFlag,
|
internal.HetznerCloudLocationFlag,
|
||||||
internal.HetznerCloudAPITokenFlag,
|
internal.HetznerCloudAPITokenFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
if err := internal.EnsureServerProvider(); err != nil {
|
if err := internal.EnsureServerProvider(); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -12,14 +13,12 @@ import (
|
|||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/hetznercloud/hcloud-go/hcloud"
|
"github.com/hetznercloud/hcloud-go/hcloud"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var rmServer bool
|
var rmServer bool
|
||||||
var rmServerFlag = &cli.BoolFlag{
|
var rmServerFlag = &cli.BoolFlag{
|
||||||
Name: "server",
|
Name: "server, s",
|
||||||
Aliases: []string{"s"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "remove the actual server also",
|
Usage: "remove the actual server also",
|
||||||
Destination: &rmServer,
|
Destination: &rmServer,
|
||||||
}
|
}
|
||||||
@ -50,7 +49,7 @@ func rmHetznerCloudVPS(c *cli.Context) error {
|
|||||||
|
|
||||||
client := hcloud.NewClient(hcloud.WithToken(internal.HetznerCloudAPIToken))
|
client := hcloud.NewClient(hcloud.WithToken(internal.HetznerCloudAPIToken))
|
||||||
|
|
||||||
server, _, err := client.Server.Get(c.Context, internal.HetznerCloudName)
|
server, _, err := client.Server.Get(context.Background(), internal.HetznerCloudName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -89,7 +88,7 @@ destroyed.
|
|||||||
logrus.Fatal("exiting as requested")
|
logrus.Fatal("exiting as requested")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.Server.Delete(c.Context, server)
|
_, err = client.Server.Delete(context.Background(), server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -99,7 +98,7 @@ destroyed.
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var serverRemoveCommand = &cli.Command{
|
var serverRemoveCommand = cli.Command{
|
||||||
Name: "remove",
|
Name: "remove",
|
||||||
Aliases: []string{"rm"},
|
Aliases: []string{"rm"},
|
||||||
ArgsUsage: "[<server>]",
|
ArgsUsage: "[<server>]",
|
||||||
@ -116,6 +115,8 @@ underlying client connection context. This server will then be lost in time,
|
|||||||
like tears in rain.
|
like tears in rain.
|
||||||
`,
|
`,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
internal.DebugFlag,
|
||||||
|
internal.NoInputFlag,
|
||||||
rmServerFlag,
|
rmServerFlag,
|
||||||
internal.ServerProviderFlag,
|
internal.ServerProviderFlag,
|
||||||
|
|
||||||
@ -123,6 +124,7 @@ like tears in rain.
|
|||||||
internal.HetznerCloudNameFlag,
|
internal.HetznerCloudNameFlag,
|
||||||
internal.HetznerCloudAPITokenFlag,
|
internal.HetznerCloudAPITokenFlag,
|
||||||
},
|
},
|
||||||
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
serverName := c.Args().Get(1)
|
serverName := c.Args().Get(1)
|
||||||
if serverName != "" {
|
if serverName != "" {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServerCommand defines the `abra server` command and its subcommands
|
// ServerCommand defines the `abra server` command and its subcommands
|
||||||
var ServerCommand = &cli.Command{
|
var ServerCommand = cli.Command{
|
||||||
Name: "server",
|
Name: "server",
|
||||||
Aliases: []string{"s"},
|
Aliases: []string{"s"},
|
||||||
Usage: "Manage servers",
|
Usage: "Manage servers",
|
||||||
@ -18,7 +18,7 @@ already have a server, you can add it to your configuration using "abra server
|
|||||||
add". Abra can provision servers so that they are ready to deploy Co-op Cloud
|
add". Abra can provision servers so that they are ready to deploy Co-op Cloud
|
||||||
apps, see available flags on "server add" for more.
|
apps, see available flags on "server add" for more.
|
||||||
`,
|
`,
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []cli.Command{
|
||||||
serverNewCommand,
|
serverNewCommand,
|
||||||
serverAddCommand,
|
serverAddCommand,
|
||||||
serverListCommand,
|
serverListCommand,
|
||||||
|
2
go.mod
2
go.mod
@ -20,7 +20,6 @@ require (
|
|||||||
github.com/schollz/progressbar/v3 v3.8.5
|
github.com/schollz/progressbar/v3 v3.8.5
|
||||||
github.com/schultz-is/passgen v1.0.1
|
github.com/schultz-is/passgen v1.0.1
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/urfave/cli/v2 v2.3.0
|
|
||||||
gotest.tools/v3 v3.1.0
|
gotest.tools/v3 v3.1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,6 +42,7 @@ require (
|
|||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/opencontainers/runc v1.0.2 // indirect
|
github.com/opencontainers/runc v1.0.2 // indirect
|
||||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||||
|
github.com/urfave/cli v1.22.5
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
||||||
|
6
go.sum
6
go.sum
@ -769,10 +769,9 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
|
|||||||
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
|
|
||||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
||||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||||
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
||||||
@ -1149,7 +1148,6 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN
|
|||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"coopcloud.tech/abra/pkg/recipe"
|
"coopcloud.tech/abra/pkg/recipe"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AppNameComplete copletes app names
|
// AppNameComplete copletes app names
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
composetypes "github.com/docker/cli/cli/compose/types"
|
||||||
@ -53,11 +54,11 @@ func UpdateTag(pattern, image, tag, recipeName string) (bool, error) {
|
|||||||
case reference.NamedTagged:
|
case reference.NamedTagged:
|
||||||
composeTag = img.(reference.NamedTagged).Tag()
|
composeTag = img.(reference.NamedTagged).Tag()
|
||||||
default:
|
default:
|
||||||
// unable to parse, typically image missing tag
|
logrus.Debugf("unable to parse %s, skipping", img)
|
||||||
return false, nil
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
composeImage := reference.Path(img)
|
composeImage := formatter.StripTagMeta(reference.Path(img))
|
||||||
|
|
||||||
logrus.Debugf("parsed %s from %s", composeTag, service.Image)
|
logrus.Debugf("parsed %s from %s", composeTag, service.Image)
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ func UpdateTag(pattern, image, tag, recipeName string) (bool, error) {
|
|||||||
logrus.Debugf("updating %s to %s in %s", old, new, compose.Filename)
|
logrus.Debugf("updating %s to %s in %s", old, new, compose.Filename)
|
||||||
|
|
||||||
if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0764); err != nil {
|
if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0764); err != nil {
|
||||||
return true, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
"github.com/schollz/progressbar/v3"
|
"github.com/schollz/progressbar/v3"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ShortenID(str string) string {
|
func ShortenID(str string) string {
|
||||||
@ -49,3 +50,22 @@ func CreateProgressbar(length int, title string) *progressbar.ProgressBar {
|
|||||||
progressbar.OptionSetDescription(title),
|
progressbar.OptionSetDescription(title),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StripTagMeta strips front-matter image tag data that we don't need for parsing.
|
||||||
|
func StripTagMeta(image string) string {
|
||||||
|
originalImage := image
|
||||||
|
|
||||||
|
if strings.Contains(image, "docker.io") {
|
||||||
|
image = strings.Split(image, "/")[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(image, "library") {
|
||||||
|
image = strings.Split(image, "/")[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if originalImage != image {
|
||||||
|
logrus.Debugf("stripped %s to %s for parsing", originalImage, image)
|
||||||
|
}
|
||||||
|
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
@ -166,7 +166,7 @@ func (r Recipe) UpdateLabel(pattern, serviceName, label string) error {
|
|||||||
func (r Recipe) UpdateTag(image, tag string) (bool, error) {
|
func (r Recipe) UpdateTag(image, tag string) (bool, error) {
|
||||||
pattern := fmt.Sprintf("%s/%s/compose**yml", config.RECIPES_DIR, r.Name)
|
pattern := fmt.Sprintf("%s/%s/compose**yml", config.RECIPES_DIR, r.Name)
|
||||||
|
|
||||||
image = StripTagMeta(image)
|
image = formatter.StripTagMeta(image)
|
||||||
|
|
||||||
ok, err := compose.UpdateTag(pattern, image, tag, r.Name)
|
ok, err := compose.UpdateTag(pattern, image, tag, r.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -983,7 +983,7 @@ func GetRecipeVersions(recipeName, registryUsername, registryPassword string) (R
|
|||||||
|
|
||||||
path := reference.Path(img)
|
path := reference.Path(img)
|
||||||
|
|
||||||
path = StripTagMeta(path)
|
path = formatter.StripTagMeta(path)
|
||||||
|
|
||||||
var tag string
|
var tag string
|
||||||
switch img.(type) {
|
switch img.(type) {
|
||||||
@ -1050,25 +1050,6 @@ func GetRecipeCatalogueVersions(recipeName string, catl RecipeCatalogue) ([]stri
|
|||||||
return versions, nil
|
return versions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StripTagMeta strips front-matter image tag data that we don't need for parsing.
|
|
||||||
func StripTagMeta(image string) string {
|
|
||||||
originalImage := image
|
|
||||||
|
|
||||||
if strings.Contains(image, "docker.io") {
|
|
||||||
image = strings.Split(image, "/")[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(image, "library") {
|
|
||||||
image = strings.Split(image, "/")[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if originalImage != image {
|
|
||||||
logrus.Debugf("stripped %s to %s for parsing", originalImage, image)
|
|
||||||
}
|
|
||||||
|
|
||||||
return image
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnsureCatalogue ensures that the catalogue is cloned locally & present.
|
// EnsureCatalogue ensures that the catalogue is cloned locally & present.
|
||||||
func EnsureCatalogue() error {
|
func EnsureCatalogue() error {
|
||||||
catalogueDir := path.Join(config.ABRA_DIR, "catalogue")
|
catalogueDir := path.Join(config.ABRA_DIR, "catalogue")
|
||||||
|
@ -325,7 +325,7 @@ func connect(username, host, port string, authMethod ssh.AuthMethod, timeout tim
|
|||||||
conn, err = net.DialTimeout("tcp", hostnameAndPort, timeout)
|
conn, err = net.DialTimeout("tcp", hostnameAndPort, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("tcp dialing %s failed, trying via ~/.ssh/config", hostnameAndPort)
|
logrus.Debugf("tcp dialing %s failed, trying via ~/.ssh/config", hostnameAndPort)
|
||||||
hostConfig, err := GetHostConfig(host, username, port)
|
hostConfig, err := GetHostConfig(host, username, port, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -452,7 +452,7 @@ func GetContextConnDetails(serverName string) (*dockerSSHPkg.Spec, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hostConfig, err := GetHostConfig(serverName, "", "")
|
hostConfig, err := GetHostConfig(serverName, "", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &dockerSSHPkg.Spec{}, err
|
return &dockerSSHPkg.Spec{}, err
|
||||||
}
|
}
|
||||||
@ -472,30 +472,36 @@ func GetContextConnDetails(serverName string) (*dockerSSHPkg.Spec, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetHostConfig retrieves a ~/.ssh/config config for a host.
|
// GetHostConfig retrieves a ~/.ssh/config config for a host.
|
||||||
func GetHostConfig(hostname, username, port string) (HostConfig, error) {
|
func GetHostConfig(hostname, username, port string, override bool) (HostConfig, error) {
|
||||||
var hostConfig HostConfig
|
var hostConfig HostConfig
|
||||||
|
|
||||||
if hostname == "" {
|
if hostname == "" || override {
|
||||||
if hostname = ssh_config.Get(hostname, "Hostname"); hostname == "" {
|
if sshHost := ssh_config.Get(hostname, "Hostname"); sshHost != "" {
|
||||||
logrus.Debugf("no hostname found in SSH config, assuming %s", hostname)
|
hostname = sshHost
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if username == "" {
|
if username == "" || override {
|
||||||
if username = ssh_config.Get(hostname, "User"); username == "" {
|
if sshUser := ssh_config.Get(hostname, "User"); sshUser != "" {
|
||||||
|
username = sshUser
|
||||||
|
} else {
|
||||||
systemUser, err := user.Current()
|
systemUser, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hostConfig, err
|
return hostConfig, err
|
||||||
}
|
}
|
||||||
logrus.Debugf("no username found in SSH config or passed on command-line, assuming %s", username)
|
|
||||||
username = systemUser.Username
|
username = systemUser.Username
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if port == "" {
|
if port == "" || override {
|
||||||
if port = ssh_config.Get(hostname, "Port"); port == "" {
|
if sshPort := ssh_config.Get(hostname, "Port"); sshPort != "" {
|
||||||
logrus.Debugf("no port found in SSH config or passed on command-line, assuming 22")
|
// skip override probably correct port with dummy default value from
|
||||||
port = "22"
|
// ssh_config which is 22. only when the original port number is empty
|
||||||
|
// should we try this default. this might not cover all cases
|
||||||
|
// unfortunately.
|
||||||
|
if port != "" && sshPort != "22" {
|
||||||
|
port = sshPort
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +513,6 @@ func GetHostConfig(hostname, username, port string) (HostConfig, error) {
|
|||||||
}
|
}
|
||||||
hostConfig.IdentityFile = idf
|
hostConfig.IdentityFile = idf
|
||||||
} else {
|
} else {
|
||||||
logrus.Debugf("no identity file found in SSH config for %s", hostname)
|
|
||||||
hostConfig.IdentityFile = ""
|
hostConfig.IdentityFile = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ func getConnectionHelper(daemonURL string, sshFlags []string) (*connhelper.Conne
|
|||||||
ctxConnDetails.Host,
|
ctxConnDetails.Host,
|
||||||
ctxConnDetails.User,
|
ctxConnDetails.User,
|
||||||
ctxConnDetails.Port,
|
ctxConnDetails.Port,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
ABRA_VERSION="0.3.0-alpha"
|
ABRA_VERSION="0.3.0-alpha"
|
||||||
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$ABRA_VERSION"
|
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$ABRA_VERSION"
|
||||||
RC_VERSION="0.4.0-alpha-rc5"
|
RC_VERSION="0.4.0-alpha-rc6"
|
||||||
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$RC_VERSION"
|
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$RC_VERSION"
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
|
1
tests/integration/.abra/servers/server1/gitea1.env
Normal file
1
tests/integration/.abra/servers/server1/gitea1.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
TYPE=gitea
|
1
tests/integration/.abra/servers/server1/wp1.env
Normal file
1
tests/integration/.abra/servers/server1/wp1.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
TYPE=wordpress
|
1
tests/integration/.abra/servers/server2/wp2.env
Normal file
1
tests/integration/.abra/servers/server2/wp2.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
TYPE=wordpress
|
4
tests/integration/.envrc.sample
Normal file
4
tests/integration/.envrc.sample
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
GANDI_TOKEN=...
|
||||||
|
HCLOUD_TOKEN=...
|
||||||
|
REGISTRY_PASSWORD=...
|
||||||
|
REGISTRY_USERNAME=...
|
7
tests/integration/Dockerfile
Normal file
7
tests/integration/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM debian:bullseye-slim
|
||||||
|
|
||||||
|
RUN apt update && apt install -y wget curl git;
|
||||||
|
|
||||||
|
RUN git config --global user.email "integration-tests@coopcloud.tech";
|
||||||
|
|
||||||
|
RUN git config --global user.name "integration-tests";
|
4
tests/integration/README.md
Normal file
4
tests/integration/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# integration tests
|
||||||
|
|
||||||
|
- `cp .envrc.sample .envrc` (fill out values && `direnv allow`)
|
||||||
|
- `TARGET=install.sh make` (ensure `docker context use default`)
|
15
tests/integration/app.sh
Executable file
15
tests/integration/app.sh
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
echo "all apps, all servers"
|
||||||
|
$ABRA app ls
|
||||||
|
printf "\\n\\n\\n"
|
||||||
|
|
||||||
|
echo "all wordpress apps, all servers"
|
||||||
|
$ABRA app ls --type wordpress
|
||||||
|
printf "\\n\\n\\n"
|
||||||
|
|
||||||
|
echo "all wordpress apps, only server2"
|
||||||
|
$ABRA app ls --type wordpress --server server2
|
||||||
|
printf "\\n\\n\\n"
|
9
tests/integration/autocomplete.sh
Executable file
9
tests/integration/autocomplete.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
$ABRA autocomplete bash
|
||||||
|
|
||||||
|
$ABRA autocomplete fizsh
|
||||||
|
|
||||||
|
$ABRA autocomplete zsh
|
7
tests/integration/catalogue.sh
Executable file
7
tests/integration/catalogue.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
$ABRA catalogue generate --debug
|
||||||
|
|
||||||
|
$ABRA catalogue generate gitea --debug
|
22
tests/integration/common.sh
Executable file
22
tests/integration/common.sh
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
ABRA="$HOME/.local/bin/abra"
|
||||||
|
INSTALLER_URL="https://install.abra.coopcloud.tech"
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [ "$arg" == "--dev" ]; then
|
||||||
|
ABRA="/src/abra"
|
||||||
|
INSTALLER_URL="https://git.coopcloud.tech/coop-cloud/abra/raw/branch/main/scripts/installer/installer"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
export PATH=$PATH:$HOME/.local/bin
|
||||||
|
|
||||||
|
echo "choosing $ABRA as abra command"
|
||||||
|
echo "choosing $INSTALLER_URL as abra installer url"
|
||||||
|
}
|
||||||
|
|
||||||
|
init "$@"
|
@ -1,101 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# the goal of this script is to ensure basic core functionality is working
|
|
||||||
# before we make new releases. we try to make a balance between manual testing
|
|
||||||
# and automated testing, i.e. we don't invest too much time in a fragile
|
|
||||||
# automation that costs us more time to maintain and instead just do the test
|
|
||||||
# manually (see `../manual/manual.md` for more). it is a balance which we
|
|
||||||
# figure out together.
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
ABRA="$HOME/.local/bin/abra -d"
|
|
||||||
INSTALLER_URL="https://install.abra.coopcloud.tech"
|
|
||||||
|
|
||||||
for arg in "$@"; do
|
|
||||||
if [ "$arg" == "--dev" ]; then
|
|
||||||
ABRA="/src/abra -d"
|
|
||||||
INSTALLER_URL="https://git.coopcloud.tech/coop-cloud/abra/raw/branch/main/scripts/installer/installer"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
export PATH=$PATH:$HOME/.local/bin
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# choosing abra executable for test run
|
|
||||||
# ========================================================================
|
|
||||||
echo "choosing $ABRA as abra executable"
|
|
||||||
echo "choosing $INSTALLER_URL as abra installer url"
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# latest stable release
|
|
||||||
# ========================================================================
|
|
||||||
wget -O- https://install.abra.autonomic.zone | bash
|
|
||||||
~/.local/bin/abra -v
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# latest rc release
|
|
||||||
# ========================================================================
|
|
||||||
wget -O- https://install.abra.autonomic.zone | bash -s -- --rc
|
|
||||||
~/.local/bin/abra -v
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# upgrade to stable in-place
|
|
||||||
# ========================================================================
|
|
||||||
$ABRA upgrade
|
|
||||||
~/.local/bin/abra -v
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# upgrade to rc in-place
|
|
||||||
# ========================================================================
|
|
||||||
$ABRA upgrade --rc
|
|
||||||
~/.local/bin/abra -v
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# autocomplete
|
|
||||||
# ========================================================================
|
|
||||||
$ABRA autocomplete bash
|
|
||||||
$ABRA autocomplete fizsh
|
|
||||||
$ABRA autocomplete zsh
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# record command
|
|
||||||
# ========================================================================
|
|
||||||
$ABRA record new -p gandi -t A -n int-core -v 192.157.2.21 coopcloud.tech
|
|
||||||
$ABRA record list -p gandi coopcloud.tech | grep -q int-core
|
|
||||||
$ABRA -n record rm -p gandi -t A -n int-core coopcloud.tech
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# catalogue command
|
|
||||||
# ========================================================================
|
|
||||||
$ABRA catalogue generate
|
|
||||||
$ABRA catalogue generate -s gitea
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# recipe command
|
|
||||||
# ========================================================================
|
|
||||||
$ABRA recipe new testrecipe
|
|
||||||
|
|
||||||
$ABRA recipe list
|
|
||||||
$ABRA recipe list -p cloud
|
|
||||||
|
|
||||||
$ABRA recipe versions peertube
|
|
||||||
|
|
||||||
$ABRA recipe lint gitea
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# server command
|
|
||||||
# ========================================================================
|
|
||||||
$ABRA -n server new -p hetzner-cloud --hn int-core
|
|
||||||
|
|
||||||
$ABRA server ls | grep -q int-core
|
|
||||||
|
|
||||||
$ABRA -n server rm -s -p hetzner-cloud --hn int-core
|
|
||||||
|
|
||||||
# ========================================================================
|
|
||||||
# app command
|
|
||||||
# ========================================================================
|
|
||||||
|
|
||||||
$ABRA app ls
|
|
||||||
|
|
||||||
$ABRA app ls -S
|
|
15
tests/integration/install.sh
Executable file
15
tests/integration/install.sh
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
wget -O- https://install.abra.autonomic.zone | bash
|
||||||
|
~/.local/bin/abra -v
|
||||||
|
|
||||||
|
wget -O- https://install.abra.autonomic.zone | bash -s -- --rc
|
||||||
|
~/.local/bin/abra -v
|
||||||
|
|
||||||
|
$ABRA upgrade
|
||||||
|
~/.local/bin/abra -v
|
||||||
|
|
||||||
|
$ABRA upgrade --rc
|
||||||
|
~/.local/bin/abra -v
|
11
tests/integration/makefile
Normal file
11
tests/integration/makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
default:
|
||||||
|
@docker run \
|
||||||
|
-v $$(pwd)/../../:/src \
|
||||||
|
-v $$(pwd)/.abra:/root/.abra \
|
||||||
|
--env-file .envrc \
|
||||||
|
decentral1se/abra-int:latest \
|
||||||
|
sh -c '\
|
||||||
|
echo "Running $(TARGET)..."; \
|
||||||
|
cd /src/tests/integration; \
|
||||||
|
bash "$(TARGET)" -- --dev \
|
||||||
|
'
|
12
tests/integration/recipe.sh
Executable file
12
tests/integration/recipe.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
$ABRA recipe new testrecipe
|
||||||
|
|
||||||
|
$ABRA recipe list
|
||||||
|
$ABRA recipe list -p cloud
|
||||||
|
|
||||||
|
$ABRA recipe versions peertube
|
||||||
|
|
||||||
|
$ABRA recipe lint gitea
|
9
tests/integration/records.sh
Executable file
9
tests/integration/records.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
$ABRA record new -p gandi -t A -n int-core -v 192.157.2.21 coopcloud.tech
|
||||||
|
|
||||||
|
$ABRA record list -p gandi coopcloud.tech | grep -q int-core
|
||||||
|
|
||||||
|
$ABRA -n record rm -p gandi -t A -n int-core coopcloud.tech
|
9
tests/integration/server.sh
Executable file
9
tests/integration/server.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
$ABRA -n server new -p hetzner-cloud --hn int-core
|
||||||
|
|
||||||
|
$ABRA server ls | grep -q int-core
|
||||||
|
|
||||||
|
$ABRA -n server rm -s -p hetzner-cloud --hn int-core
|
@ -1 +0,0 @@
|
|||||||
TYPE=works
|
|
@ -1,84 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
# The goal of this compose file is to have a testing ground for understanding
|
|
||||||
# what cases we need to handle to get stable deployments. For that, we need to
|
|
||||||
# work with healthchecks and deploy configurations quite closely. If you run
|
|
||||||
# the `make symlink` target then this will be loaded into a "fake" app on your
|
|
||||||
# local machine which you can deploy with `abra`.
|
|
||||||
|
|
||||||
version: "3.8"
|
|
||||||
services:
|
|
||||||
r1_should_work:
|
|
||||||
image: redis:alpine
|
|
||||||
deploy:
|
|
||||||
update_config:
|
|
||||||
failure_action: rollback
|
|
||||||
order: start-first
|
|
||||||
rollback_config:
|
|
||||||
order: start-first
|
|
||||||
restart_policy:
|
|
||||||
max_attempts: 1
|
|
||||||
healthcheck:
|
|
||||||
test: redis-cli ping
|
|
||||||
interval: 2s
|
|
||||||
retries: 3
|
|
||||||
start_period: 1s
|
|
||||||
timeout: 3s
|
|
||||||
|
|
||||||
r2_broken_health_check:
|
|
||||||
image: redis:alpine
|
|
||||||
deploy:
|
|
||||||
update_config:
|
|
||||||
failure_action: rollback
|
|
||||||
order: start-first
|
|
||||||
rollback_config:
|
|
||||||
order: start-first
|
|
||||||
restart_policy:
|
|
||||||
max_attempts: 3
|
|
||||||
healthcheck:
|
|
||||||
test: foobar
|
|
||||||
interval: 2s
|
|
||||||
retries: 3
|
|
||||||
start_period: 1s
|
|
||||||
timeout: 3s
|
|
||||||
|
|
||||||
r3_no_health_check:
|
|
||||||
image: redis:alpine
|
|
||||||
deploy:
|
|
||||||
update_config:
|
|
||||||
failure_action: rollback
|
|
||||||
order: start-first
|
|
||||||
rollback_config:
|
|
||||||
order: start-first
|
|
||||||
restart_policy:
|
|
||||||
max_attempts: 3
|
|
||||||
|
|
||||||
r4_disabled_health_check:
|
|
||||||
image: redis:alpine
|
|
||||||
deploy:
|
|
||||||
update_config:
|
|
||||||
failure_action: rollback
|
|
||||||
order: start-first
|
|
||||||
rollback_config:
|
|
||||||
order: start-first
|
|
||||||
restart_policy:
|
|
||||||
max_attempts: 3
|
|
||||||
healthcheck:
|
|
||||||
disable: true
|
|
||||||
|
|
||||||
r5_should_also_work:
|
|
||||||
image: redis:alpine
|
|
||||||
deploy:
|
|
||||||
update_config:
|
|
||||||
failure_action: rollback
|
|
||||||
order: start-first
|
|
||||||
rollback_config:
|
|
||||||
order: start-first
|
|
||||||
restart_policy:
|
|
||||||
max_attempts: 1
|
|
||||||
healthcheck:
|
|
||||||
test: redis-cli ping
|
|
||||||
interval: 2s
|
|
||||||
retries: 3
|
|
||||||
start_period: 1s
|
|
||||||
timeout: 3s
|
|
@ -1 +0,0 @@
|
|||||||
TYPE=works
|
|
@ -1,60 +1,40 @@
|
|||||||
# manual test plan
|
# manual test plan
|
||||||
|
|
||||||
Best served after running `make int-core` which assures most core functionality
|
|
||||||
is still working. These manual tests are for testing things that are hard to
|
|
||||||
wire up for testing in an automated way.
|
|
||||||
|
|
||||||
## recipe publish
|
## recipe publish
|
||||||
|
|
||||||
- `abra recipe upgrade <recipe>`
|
- `abra recipe upgrade <recipe>`
|
||||||
|
- `cd ~/.abra/apps/<recipe>/ && git diff` to ensure changes made
|
||||||
|
|
||||||
- `abra recipe sync <recipe>`
|
- `abra recipe sync <recipe>`
|
||||||
- `abra recipe release --publish <recipe>`
|
- `cd ~/.abra/apps/<recipe>/ && git diff` to ensure changes made
|
||||||
|
|
||||||
## automagic traefik deploy
|
- `abra recipe release <recipe> --dry-run`
|
||||||
|
- prompts should be correct, read what `abra` asks you carefully
|
||||||
- `abra server add -p -t <server>`
|
|
||||||
|
|
||||||
## deploy, upgrade, rollback
|
## deploy, upgrade, rollback
|
||||||
|
|
||||||
- `abra app deploy <app>`
|
|
||||||
- `abra app deploy --force <app>`
|
|
||||||
- `abra app deploy --chaos <app>`
|
- `abra app deploy --chaos <app>`
|
||||||
- `abra app upgrade <app>`
|
- `abra app deploy --force <app>`
|
||||||
|
- `abra app deploy <app>`
|
||||||
- `abra app rollback <app>`
|
- `abra app rollback <app>`
|
||||||
|
- `abra app upgrade <app>`
|
||||||
## backup & restore
|
|
||||||
|
|
||||||
- `abra app deploy <app>`
|
|
||||||
- `abra app backup <app>`
|
|
||||||
- `abra app undeploy <app>`
|
|
||||||
- `abra app volume remove --force <app>`
|
|
||||||
- `abra app deploy <app>`
|
|
||||||
- `abra app restore <app>`
|
|
||||||
|
|
||||||
## app day-to-day ops
|
## app day-to-day ops
|
||||||
|
|
||||||
### easy mode
|
|
||||||
|
|
||||||
- `abra app ls -t <recipe>`
|
|
||||||
- `abra app ls -s <server>`
|
|
||||||
- `abra app ls -s <server> -t <recipe>`
|
|
||||||
- `abra app ls -s <server> -t <recipe> -S`
|
|
||||||
- `abra app config <app>`
|
|
||||||
- `abra app check <app>`
|
- `abra app check <app>`
|
||||||
- `abra app ps <app>`
|
- `abra app config <app>`
|
||||||
- `abra app logs <app>`
|
|
||||||
- `abra app cp <app>`
|
- `abra app cp <app>`
|
||||||
- `abra app run <app>`
|
|
||||||
- `abra app secret ls <app>`
|
|
||||||
- `abra app volume ls <app>`
|
|
||||||
- `abra app new --secrets <recipe>`
|
|
||||||
|
|
||||||
### hard mode
|
|
||||||
|
|
||||||
- `abra app restart <app>`
|
|
||||||
- `abra app remove <app>`
|
|
||||||
- `abra app secret insert <app> foo v1 bar`
|
|
||||||
- `abra app secret remove <app> foo`
|
|
||||||
- `abra app secret generate --all`
|
|
||||||
- `abra app volume remove --force <app>`
|
|
||||||
- `abra app errors -w <app>`
|
- `abra app errors -w <app>`
|
||||||
|
- `abra app logs <app>`
|
||||||
|
- `abra app ls --status <app>`
|
||||||
|
- `abra app new --secrets <recipe>`
|
||||||
|
- `abra app ps <app>`
|
||||||
|
- `abra app remove <app>`
|
||||||
|
- `abra app restart <app>`
|
||||||
|
- `abra app run <app>`
|
||||||
|
- `abra app secret generate --all`
|
||||||
|
- `abra app secret insert <app> foo v1 bar`
|
||||||
|
- `abra app secret ls <app>`
|
||||||
|
- `abra app secret remove <app> foo`
|
||||||
|
- `abra app volume ls <app>`
|
||||||
|
- `abra app volume remove --force <app>`
|
||||||
|
Reference in New Issue
Block a user