From abd094387fde660cfddcd86f26a58a0716878ac0 Mon Sep 17 00:00:00 2001 From: cellarspoon Date: Sat, 1 Jan 2022 17:22:35 +0100 Subject: [PATCH] fix: use scale for restarting The other approach wasn't working. Duplicating containers on restart. You'd end up with 2 containers per restart... --- cli/app/restart.go | 49 ++++++++++++++++++++--------------- pkg/upstream/service/scale.go | 44 +++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 21 deletions(-) create mode 100644 pkg/upstream/service/scale.go diff --git a/cli/app/restart.go b/cli/app/restart.go index 0b7ddf69..47714bf4 100644 --- a/cli/app/restart.go +++ b/cli/app/restart.go @@ -3,28 +3,28 @@ package app import ( "errors" "fmt" - "time" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/client" - containerPkg "coopcloud.tech/abra/pkg/container" - "github.com/docker/docker/api/types/filters" + upstream "coopcloud.tech/abra/pkg/upstream/service" + stack "coopcloud.tech/abra/pkg/upstream/stack" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) var appRestartCommand = &cli.Command{ - Name: "restart", - Usage: "Restart an app", - Aliases: []string{"re"}, - ArgsUsage: "", - Description: `This command restarts a service within a deployed app.`, + Name: "restart", + Usage: "Restart an app", + Aliases: []string{"re"}, + ArgsUsage: "", + Description: `This command restarts a service within a deployed app.`, + BashComplete: autocomplete.AppNameComplete, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - serviceName := c.Args().Get(1) - if serviceName == "" { + serviceNameShort := c.Args().Get(1) + if serviceNameShort == "" { err := errors.New("missing service?") internal.ShowSubcommandHelpAndError(c, err) } @@ -34,25 +34,32 @@ var appRestartCommand = &cli.Command{ logrus.Fatal(err) } - serviceFilter := fmt.Sprintf("%s_%s", app.StackName(), serviceName) - filters := filters.NewArgs() - filters.Add("name", serviceFilter) + serviceName := fmt.Sprintf("%s_%s", app.StackName(), serviceNameShort) - targetContainer, err := containerPkg.GetContainer(c.Context, cl, filters, true) - if err != nil { + logrus.Debugf("attempting to scale %s to 0 (restart logic)", serviceName) + if err := upstream.RunServiceScale(c.Context, cl, serviceName, 0); err != nil { logrus.Fatal(err) } - logrus.Debugf("attempting to restart %s", serviceFilter) - - timeout := 30 * time.Second - if err := cl.ContainerRestart(c.Context, targetContainer.ID, &timeout); err != nil { + if err := stack.WaitOnService(c.Context, cl, serviceName, app.Name); err != nil { logrus.Fatal(err) } - logrus.Infof("%s service restarted", serviceFilter) + logrus.Debugf("%s has been scaled to 0 (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 { + logrus.Fatal(err) + } + + if err := stack.WaitOnService(c.Context, cl, serviceName, app.Name); err != nil { + logrus.Fatal(err) + } + + logrus.Debugf("%s has been scaled to 1 (restart logic)", serviceName) + + logrus.Infof("%s service successfully restarted", serviceNameShort) return nil }, - BashComplete: autocomplete.AppNameComplete, } diff --git a/pkg/upstream/service/scale.go b/pkg/upstream/service/scale.go new file mode 100644 index 00000000..e8296379 --- /dev/null +++ b/pkg/upstream/service/scale.go @@ -0,0 +1,44 @@ +package upstream + +import ( + "context" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" + "github.com/sirupsen/logrus" +) + +// RunServiceScale scales a service (useful for restart action) +func RunServiceScale(ctx context.Context, cl *client.Client, serviceID string, scale uint64) error { + service, _, err := cl.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{}) + if err != nil { + return err + } + + serviceMode := &service.Spec.Mode + if serviceMode.Replicated != nil { + serviceMode.Replicated.Replicas = &scale + } else if serviceMode.ReplicatedJob != nil { + serviceMode.ReplicatedJob.TotalCompletions = &scale + } else { + return fmt.Errorf("scale can only be used with replicated or replicated-job mode") + } + + response, err := cl.ServiceUpdate( + ctx, + service.ID, + service.Version, + service.Spec, + types.ServiceUpdateOptions{}, + ) + if err != nil { + return err + } + + for _, warning := range response.Warnings { + logrus.Warn(warning) + } + + return nil +}