Browse Source

Merge pull request #1287 from docker/scale

Nicolas De loof 4 years ago
parent
commit
4d05e0234a
2 changed files with 94 additions and 0 deletions
  1. 52 0
      cli/cmd/compose/up.go
  2. 42 0
      cli/cmd/compose/up_test.go

+ 52 - 0
cli/cmd/compose/up.go

@@ -22,6 +22,8 @@ import (
 	"os"
 	"os/signal"
 	"path/filepath"
+	"strconv"
+	"strings"
 	"syscall"
 
 	"github.com/docker/compose-cli/api/client"
@@ -54,6 +56,7 @@ type upOptions struct {
 	noStart       bool
 	cascadeStop   bool
 	exitCodeFrom  string
+	scale         []string
 }
 
 func (o upOptions) recreateStrategy() string {
@@ -98,6 +101,7 @@ func upCommand(p *projectOptions, contextType string) *cobra.Command {
 	flags.BoolVarP(&opts.Detach, "detach", "d", false, "Detached mode: Run containers in the background")
 	flags.BoolVar(&opts.Build, "build", false, "Build images before starting containers.")
 	flags.BoolVar(&opts.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file.")
+	flags.StringArrayVar(&opts.scale, "scale", []string{}, "Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present.")
 
 	switch contextType {
 	case store.AciContextType:
@@ -119,6 +123,11 @@ func runUp(ctx context.Context, opts upOptions, services []string) error {
 		return err
 	}
 
+	err = applyScaleOpt(opts.scale, project)
+	if err != nil {
+		return err
+	}
+
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
 		return "", c.ComposeService().Up(ctx, project, compose.UpOptions{
 			Detach: opts.Detach,
@@ -133,6 +142,11 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 		return err
 	}
 
+	err = applyScaleOpt(opts.scale, project)
+	if err != nil {
+		return err
+	}
+
 	if opts.exitCodeFrom != "" {
 		_, err := project.GetService(opts.exitCodeFrom)
 		if err != nil {
@@ -201,6 +215,44 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 	return err
 }
 
+func applyScaleOpt(opts []string, project *types.Project) error {
+	for _, scale := range opts {
+		split := strings.Split(scale, "=")
+		if len(split) != 2 {
+			return fmt.Errorf("invalid --scale option %q. Should be SERVICE=NUM", scale)
+		}
+		name := split[0]
+		replicas, err := strconv.Atoi(split[1])
+		if err != nil {
+			return err
+		}
+		err = setServiceScale(project, name, replicas)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func setServiceScale(project *types.Project, name string, replicas int) error {
+	for i, s := range project.Services {
+		if s.Name == name {
+			service, err := project.GetService(name)
+			if err != nil {
+				return err
+			}
+			if service.Deploy == nil {
+				service.Deploy = &types.DeployConfig{}
+			}
+			count := uint64(replicas)
+			service.Deploy.Replicas = &count
+			project.Services[i] = service
+			return nil
+		}
+	}
+	return fmt.Errorf("unknown service %q", name)
+}
+
 func setup(ctx context.Context, opts composeOptions, services []string) (*client.Client, *types.Project, error) {
 	c, err := client.NewWithDefaultLocalBackend(ctx)
 	if err != nil {

+ 42 - 0
cli/cmd/compose/up_test.go

@@ -0,0 +1,42 @@
+/*
+   Copyright 2020 Docker Compose CLI authors
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package compose
+
+import (
+	"testing"
+
+	"github.com/compose-spec/compose-go/types"
+	"gotest.tools/v3/assert"
+)
+
+func TestApplyScaleOpt(t *testing.T) {
+	p := types.Project{
+		Services: []types.ServiceConfig{
+			{
+				Name: "foo",
+			},
+			{
+				Name: "bar",
+			},
+		},
+	}
+	err := applyScaleOpt([]string{"foo=2"}, &p)
+	assert.NilError(t, err)
+	foo, err := p.GetService("foo")
+	assert.NilError(t, err)
+	assert.Check(t, *foo.Deploy.Replicas == 2)
+}