scale.go 2.3 KB

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