Compare commits

...

11 Commits

Author SHA1 Message Date
fcbf41ee95 chore: use alpha format
Some checks failed
continuous-integration/drone/push Build is failing
2021-11-12 08:25:38 +01:00
5add4ccc1b refactor(installer): remove doubled code for RC
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-11-11 17:40:14 +01:00
9220a8c09b feat(installer): download rc with --rc
All checks were successful
continuous-integration/drone/pr Build is passing
2021-11-11 17:10:48 +01:00
f78a04109c fix: clarify when deploy done [ci skip] 2021-11-10 09:15:52 +01:00
b67ad02f87 feat: rudimentary deploy status checking
All checks were successful
continuous-integration/drone/push Build is passing
See coop-cloud/organising#209.
2021-11-10 09:06:55 +01:00
215431696e feat: implement app restart
All checks were successful
continuous-integration/drone/push Build is passing
Closes coop-cloud/organising#239.
2021-11-10 07:52:45 +01:00
cd361237e7 Revert "Revert "test: remove broken tests for client""
All checks were successful
continuous-integration/drone/push Build is passing
This reverts commit 59031595ea.

Argh, reverted this by accident, heres another one!
2021-11-09 18:25:28 +01:00
db10c7b849 feat: run wizard mode on recipe upgrade [ci skip] 2021-11-09 18:06:06 +01:00
d38f82ebe7 docs: drop recipe [ci skip] 2021-11-09 18:05:53 +01:00
59031595ea Revert "test: remove broken tests for client"
This reverts commit 17a5f1529a.
2021-11-09 17:58:31 +01:00
6f26b51f3e fix: only check host keys on requested hosts
All checks were successful
continuous-integration/drone/push Build is passing
See coop-cloud/organising#242.
2021-11-09 17:44:13 +01:00
11 changed files with 158 additions and 20 deletions

View File

@ -18,6 +18,7 @@ to scaling apps up and spinning them down.
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
appNewCommand, appNewCommand,
appConfigCommand, appConfigCommand,
appRestartCommand,
appDeployCommand, appDeployCommand,
appUpgradeCommand, appUpgradeCommand,
appUndeployCommand, appUndeployCommand,

View File

@ -8,6 +8,7 @@ import (
abraFormatter "coopcloud.tech/abra/cli/formatter" abraFormatter "coopcloud.tech/abra/cli/formatter"
"coopcloud.tech/abra/pkg/catalogue" "coopcloud.tech/abra/pkg/catalogue"
"coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/config"
"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/v2"
@ -69,6 +70,12 @@ can take some time.
} }
sort.Sort(config.ByServerAndType(apps)) sort.Sort(config.ByServerAndType(apps))
for _, app := range apps {
if err := ssh.EnsureHostKey(app.Server); err != nil {
logrus.Fatal(err)
}
}
statuses := make(map[string]map[string]string) statuses := make(map[string]map[string]string)
tableCol := []string{"Server", "Type", "Domain"} tableCol := []string{"Server", "Type", "Domain"}
if status { if status {

72
cli/app/restart.go Normal file
View File

@ -0,0 +1,72 @@
package app
import (
"errors"
"fmt"
"time"
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
var appRestartCommand = &cli.Command{
Name: "restart",
Usage: "Restart an app",
Aliases: []string{"R"},
ArgsUsage: "<service>",
Description: `This command restarts a service within a deployed app.`,
Action: func(c *cli.Context) error {
app := internal.ValidateApp(c)
serviceName := c.Args().Get(1)
if serviceName == "" {
err := errors.New("missing service?")
internal.ShowSubcommandHelpAndError(c, err)
}
cl, err := client.New(app.Server)
if err != nil {
logrus.Fatal(err)
}
serviceFilter := fmt.Sprintf("%s_%s", app.StackName(), serviceName)
filters := filters.NewArgs()
filters.Add("name", serviceFilter)
containerOpts := types.ContainerListOptions{Filters: filters}
containers, err := cl.ContainerList(c.Context, containerOpts)
if err != nil {
logrus.Fatal(err)
}
if len(containers) != 1 {
logrus.Fatalf("expected 1 service but got %v", len(containers))
}
logrus.Debugf("attempting to restart %s", serviceFilter)
timeout := 30 * time.Second
if err := cl.ContainerRestart(c.Context, containers[0].ID, &timeout); err != nil {
logrus.Fatal(err)
}
logrus.Infof("%s service restarted", serviceFilter)
return nil
},
BashComplete: func(c *cli.Context) {
appNames, err := config.GetAppNames()
if err != nil {
logrus.Warn(err)
}
if c.NArg() > 0 {
return
}
for _, a := range appNames {
fmt.Println(a)
}
},
}

View File

@ -8,6 +8,7 @@ import (
"coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/secret" "coopcloud.tech/abra/pkg/secret"
"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/v2"
@ -163,6 +164,10 @@ func NewAction(c *cli.Context) error {
} }
if Secrets { if Secrets {
if err := ssh.EnsureHostKey(NewAppServer); err != nil {
logrus.Fatal(err)
}
secrets, err := createSecrets(sanitisedAppName) secrets, err := createSecrets(sanitisedAppName)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)

View File

@ -8,6 +8,7 @@ import (
"coopcloud.tech/abra/pkg/catalogue" "coopcloud.tech/abra/pkg/catalogue"
"coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"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/v2"
@ -98,6 +99,10 @@ func ValidateApp(c *cli.Context) config.App {
logrus.Fatal(err) logrus.Fatal(err)
} }
if err := ssh.EnsureHostKey(app.Server); err != nil {
logrus.Fatal(err)
}
logrus.Debugf("validated '%s' as app argument", appName) logrus.Debugf("validated '%s' as app argument", appName)
return app return app

View File

@ -39,7 +39,7 @@ system.
You may invoke this command in "wizard" mode and be prompted for input: You may invoke this command in "wizard" mode and be prompted for input:
abra recipe sync gitea abra recipe sync
`, `,
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {

View File

@ -36,6 +36,11 @@ update the relevant compose file tags on the local file system.
Some image tags cannot be parsed because they do not follow some sort of Some image tags cannot be parsed because they do not follow some sort of
semver-like convention. In this case, all possible tags will be listed and it semver-like convention. In this case, all possible tags will be listed and it
is up to the end-user to decide. is up to the end-user to decide.
You may invoke this command in "wizard" mode and be prompted for input:
abra recipe upgrade
`, `,
ArgsUsage: "<recipe>", ArgsUsage: "<recipe>",
Flags: []cli.Flag{ Flags: []cli.Flag{
@ -44,7 +49,7 @@ is up to the end-user to decide.
internal.MajorFlag, internal.MajorFlag,
}, },
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipe(c) recipe := internal.ValidateRecipeWithPrompt(c)
bumpType := btoi(internal.Major)*4 + btoi(internal.Minor)*2 + btoi(internal.Patch) bumpType := btoi(internal.Major)*4 + btoi(internal.Minor)*2 + btoi(internal.Patch)
if bumpType != 0 { if bumpType != 0 {

View File

@ -9,7 +9,6 @@ import (
"strings" "strings"
"coopcloud.tech/abra/cli/formatter" "coopcloud.tech/abra/cli/formatter"
"coopcloud.tech/abra/pkg/ssh"
"coopcloud.tech/abra/pkg/upstream/convert" "coopcloud.tech/abra/pkg/upstream/convert"
loader "coopcloud.tech/abra/pkg/upstream/stack" loader "coopcloud.tech/abra/pkg/upstream/stack"
stack "coopcloud.tech/abra/pkg/upstream/stack" stack "coopcloud.tech/abra/pkg/upstream/stack"
@ -146,10 +145,6 @@ func LoadAppFiles(servers ...string) (AppFiles, error) {
logrus.Debugf("collecting metadata from '%v' servers: '%s'", len(servers), strings.Join(servers, ", ")) logrus.Debugf("collecting metadata from '%v' servers: '%s'", len(servers), strings.Join(servers, ", "))
if err := EnsureHostKeysAllServers(servers...); err != nil {
return nil, err
}
for _, server := range servers { for _, server := range servers {
serverDir := path.Join(ABRA_SERVER_FOLDER, server) serverDir := path.Join(ABRA_SERVER_FOLDER, server)
files, err := getAllFilesInDirectory(serverDir) files, err := getAllFilesInDirectory(serverDir)
@ -373,15 +368,3 @@ func GetAppComposeConfig(recipe string, opts stack.Deploy, appEnv AppEnv) (*comp
return compose, nil return compose, nil
} }
// EnsureHostKeysAllServers ensures all configured servers have server SSH host keys validated
func EnsureHostKeysAllServers(servers ...string) error {
for _, serverName := range servers {
logrus.Debugf("ensuring server SSH host key available for %s", serverName)
if err := ssh.EnsureHostKey(serverName); err != nil {
return err
}
}
return nil
}

View File

@ -427,6 +427,11 @@ func connectWithPasswordTimeout(host, username, port, pass string, timeout time.
// EnsureHostKey ensures that a host key trusted and added to the ~/.ssh/known_hosts file // EnsureHostKey ensures that a host key trusted and added to the ~/.ssh/known_hosts file
func EnsureHostKey(hostname string) error { func EnsureHostKey(hostname string) error {
if hostname == "default" || hostname == "local" {
logrus.Debugf("not checking server SSH host key against local/default target")
return nil
}
exists, _, err := GetHostKey(hostname) exists, _, err := GetHostKey(hostname)
if err != nil { if err != nil {
return err return err

View File

@ -3,10 +3,13 @@ package stack // https://github.com/docker/cli/blob/master/cli/command/stack/swa
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"io/ioutil"
"strings" "strings"
abraClient "coopcloud.tech/abra/pkg/client" abraClient "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/upstream/convert" "coopcloud.tech/abra/pkg/upstream/convert"
"github.com/docker/cli/cli/command/service/progress"
composetypes "github.com/docker/cli/cli/compose/types" composetypes "github.com/docker/cli/cli/compose/types"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
@ -346,6 +349,7 @@ func deployServices(
existingServiceMap[service.Spec.Name] = service existingServiceMap[service.Spec.Name] = service
} }
var serviceIDs []string
for internalName, serviceSpec := range services { for internalName, serviceSpec := range services {
var ( var (
name = namespace.Scope(internalName) name = namespace.Scope(internalName)
@ -405,6 +409,8 @@ func deployServices(
return errors.Wrapf(err, "failed to update service %s", name) return errors.Wrapf(err, "failed to update service %s", name)
} }
serviceIDs = append(serviceIDs, service.ID)
for _, warning := range response.Warnings { for _, warning := range response.Warnings {
logrus.Warn(warning) logrus.Warn(warning)
} }
@ -418,11 +424,35 @@ func deployServices(
createOpts.QueryRegistry = true createOpts.QueryRegistry = true
} }
if _, err := cl.ServiceCreate(ctx, serviceSpec, createOpts); err != nil { serviceCreateResponse, err := cl.ServiceCreate(ctx, serviceSpec, createOpts)
if err != nil {
return errors.Wrapf(err, "failed to create service %s", name) return errors.Wrapf(err, "failed to create service %s", name)
} }
serviceIDs = append(serviceIDs, serviceCreateResponse.ID)
} }
} }
logrus.Infof("waiting for services to converge: %s", strings.Join(serviceIDs, ", "))
ch := make(chan error, len(serviceIDs))
for _, serviceID := range serviceIDs {
logrus.Debugf("waiting on %s to converge", serviceID)
go func(s string) {
ch <- waitOnService(ctx, cl, s)
}(serviceID)
}
for _, serviceID := range serviceIDs {
err := <-ch
if err != nil {
return err
}
logrus.Debugf("assuming %s converged successfully", serviceID)
}
logrus.Info("services converged 👌")
return nil return nil
} }
@ -437,3 +467,17 @@ func getStackSecrets(ctx context.Context, dockerclient client.APIClient, namespa
func getStackConfigs(ctx context.Context, dockerclient client.APIClient, namespace string) ([]swarm.Config, error) { func getStackConfigs(ctx context.Context, dockerclient client.APIClient, namespace string) ([]swarm.Config, error) {
return dockerclient.ConfigList(ctx, types.ConfigListOptions{Filters: getStackFilter(namespace)}) return dockerclient.ConfigList(ctx, types.ConfigListOptions{Filters: getStackFilter(namespace)})
} }
// https://github.com/docker/cli/blob/master/cli/command/service/helpers.go
// https://github.com/docker/cli/blob/master/cli/command/service/progress/progress.go
func waitOnService(ctx context.Context, cl *dockerclient.Client, serviceID string) error {
errChan := make(chan error, 1)
pipeReader, pipeWriter := io.Pipe()
go func() {
errChan <- progress.ServiceProgress(ctx, cl, serviceID, pipeWriter)
}()
go io.Copy(ioutil.Discard, pipeReader)
return <-errChan
}

View File

@ -2,6 +2,15 @@
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.3.1-alpha-rc1"
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$RC_VERSION"
for arg in "$@"; do
if [ "$arg" == "--rc" ]; then
ABRA_VERSION="$RC_VERSION"
ABRA_RELEASE_URL="$RC_VERSION_URL"
fi
done
function show_banner { function show_banner {
echo "" echo ""
@ -35,6 +44,7 @@ function install_abra_release {
exit 1 exit 1
fi fi
# FIXME: support different architectures # FIXME: support different architectures
PLATFORM=$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m) PLATFORM=$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m)
FILENAME="abra_"$ABRA_VERSION"_"$PLATFORM"" FILENAME="abra_"$ABRA_VERSION"_"$PLATFORM""
@ -79,6 +89,7 @@ function install_abra_release {
echo "abra installed to $HOME/.local/bin/abra" echo "abra installed to $HOME/.local/bin/abra"
} }
function run_installation { function run_installation {
show_banner show_banner
install_abra_release install_abra_release