github.com/olljanat/moby@v1.13.1/cli/command/service/scale.go (about)

     1  package service
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"golang.org/x/net/context"
     9  
    10  	"github.com/docker/docker/api/types"
    11  	"github.com/docker/docker/cli"
    12  	"github.com/docker/docker/cli/command"
    13  	"github.com/spf13/cobra"
    14  )
    15  
    16  func newScaleCommand(dockerCli *command.DockerCli) *cobra.Command {
    17  	return &cobra.Command{
    18  		Use:   "scale SERVICE=REPLICAS [SERVICE=REPLICAS...]",
    19  		Short: "Scale one or multiple replicated services",
    20  		Args:  scaleArgs,
    21  		RunE: func(cmd *cobra.Command, args []string) error {
    22  			return runScale(dockerCli, args)
    23  		},
    24  	}
    25  }
    26  
    27  func scaleArgs(cmd *cobra.Command, args []string) error {
    28  	if err := cli.RequiresMinArgs(1)(cmd, args); err != nil {
    29  		return err
    30  	}
    31  	for _, arg := range args {
    32  		if parts := strings.SplitN(arg, "=", 2); len(parts) != 2 {
    33  			return fmt.Errorf(
    34  				"Invalid scale specifier '%s'.\nSee '%s --help'.\n\nUsage:  %s\n\n%s",
    35  				arg,
    36  				cmd.CommandPath(),
    37  				cmd.UseLine(),
    38  				cmd.Short,
    39  			)
    40  		}
    41  	}
    42  	return nil
    43  }
    44  
    45  func runScale(dockerCli *command.DockerCli, args []string) error {
    46  	var errors []string
    47  	for _, arg := range args {
    48  		parts := strings.SplitN(arg, "=", 2)
    49  		serviceID, scaleStr := parts[0], parts[1]
    50  
    51  		// validate input arg scale number
    52  		scale, err := strconv.ParseUint(scaleStr, 10, 64)
    53  		if err != nil {
    54  			errors = append(errors, fmt.Sprintf("%s: invalid replicas value %s: %v", serviceID, scaleStr, err))
    55  			continue
    56  		}
    57  
    58  		if err := runServiceScale(dockerCli, serviceID, scale); err != nil {
    59  			errors = append(errors, fmt.Sprintf("%s: %v", serviceID, err))
    60  		}
    61  	}
    62  
    63  	if len(errors) == 0 {
    64  		return nil
    65  	}
    66  	return fmt.Errorf(strings.Join(errors, "\n"))
    67  }
    68  
    69  func runServiceScale(dockerCli *command.DockerCli, serviceID string, scale uint64) error {
    70  	client := dockerCli.Client()
    71  	ctx := context.Background()
    72  
    73  	service, _, err := client.ServiceInspectWithRaw(ctx, serviceID)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	serviceMode := &service.Spec.Mode
    79  	if serviceMode.Replicated == nil {
    80  		return fmt.Errorf("scale can only be used with replicated mode")
    81  	}
    82  
    83  	serviceMode.Replicated.Replicas = &scale
    84  
    85  	response, err := client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	for _, warning := range response.Warnings {
    91  		fmt.Fprintln(dockerCli.Err(), warning)
    92  	}
    93  
    94  	fmt.Fprintf(dockerCli.Out(), "%s scaled to %d\n", serviceID, scale)
    95  	return nil
    96  }