scale.go 2.3 KB

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