upgrade.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package plugin
  2. import (
  3. "bufio"
  4. "context"
  5. "fmt"
  6. "strings"
  7. "github.com/docker/docker/cli"
  8. "github.com/docker/docker/cli/command"
  9. "github.com/docker/docker/pkg/jsonmessage"
  10. "github.com/docker/docker/reference"
  11. "github.com/pkg/errors"
  12. "github.com/spf13/cobra"
  13. )
  14. func newUpgradeCommand(dockerCli *command.DockerCli) *cobra.Command {
  15. var options pluginOptions
  16. cmd := &cobra.Command{
  17. Use: "upgrade [OPTIONS] PLUGIN [REMOTE]",
  18. Short: "Upgrade an existing plugin",
  19. Args: cli.RequiresRangeArgs(1, 2),
  20. RunE: func(cmd *cobra.Command, args []string) error {
  21. options.localName = args[0]
  22. if len(args) == 2 {
  23. options.remote = args[1]
  24. }
  25. return runUpgrade(dockerCli, options)
  26. },
  27. }
  28. flags := cmd.Flags()
  29. loadPullFlags(&options, flags)
  30. flags.BoolVar(&options.skipRemoteCheck, "skip-remote-check", false, "Do not check if specified remote plugin matches existing plugin image")
  31. return cmd
  32. }
  33. func runUpgrade(dockerCli *command.DockerCli, opts pluginOptions) error {
  34. ctx := context.Background()
  35. p, _, err := dockerCli.Client().PluginInspectWithRaw(ctx, opts.localName)
  36. if err != nil {
  37. return fmt.Errorf("error reading plugin data: %v", err)
  38. }
  39. if p.Enabled {
  40. return fmt.Errorf("the plugin must be disabled before upgrading")
  41. }
  42. opts.localName = p.Name
  43. if opts.remote == "" {
  44. opts.remote = p.PluginReference
  45. }
  46. remote, err := reference.ParseNamed(opts.remote)
  47. if err != nil {
  48. return errors.Wrap(err, "error parsing remote upgrade image reference")
  49. }
  50. remote = reference.WithDefaultTag(remote)
  51. old, err := reference.ParseNamed(p.PluginReference)
  52. if err != nil {
  53. return errors.Wrap(err, "error parsing current image reference")
  54. }
  55. old = reference.WithDefaultTag(old)
  56. fmt.Fprintf(dockerCli.Out(), "Upgrading plugin %s from %s to %s\n", p.Name, old, remote)
  57. if !opts.skipRemoteCheck && remote.String() != old.String() {
  58. _, err := fmt.Fprint(dockerCli.Out(), "Plugin images do not match, are you sure? ")
  59. if err != nil {
  60. return errors.Wrap(err, "error writing to stdout")
  61. }
  62. rdr := bufio.NewReader(dockerCli.In())
  63. line, _, err := rdr.ReadLine()
  64. if err != nil {
  65. return errors.Wrap(err, "error reading from stdin")
  66. }
  67. if strings.ToLower(string(line)) != "y" {
  68. return errors.New("canceling upgrade request")
  69. }
  70. }
  71. options, err := buildPullConfig(ctx, dockerCli, opts, "plugin upgrade")
  72. if err != nil {
  73. return err
  74. }
  75. responseBody, err := dockerCli.Client().PluginUpgrade(ctx, opts.localName, options)
  76. if err != nil {
  77. if strings.Contains(err.Error(), "target is image") {
  78. return errors.New(err.Error() + " - Use `docker image pull`")
  79. }
  80. return err
  81. }
  82. defer responseBody.Close()
  83. if err := jsonmessage.DisplayJSONMessagesToStream(responseBody, dockerCli.Out(), nil); err != nil {
  84. return err
  85. }
  86. fmt.Fprintf(dockerCli.Out(), "Upgraded plugin %s to %s\n", opts.localName, opts.remote) // todo: return proper values from the API for this result
  87. return nil
  88. }