2017-01-28 19:54:32 -05:00
|
|
|
package plugin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
2023-08-30 18:36:58 -04:00
|
|
|
"github.com/distribution/reference"
|
2017-04-17 18:07:56 -04:00
|
|
|
"github.com/docker/cli/cli"
|
|
|
|
"github.com/docker/cli/cli/command"
|
2017-01-28 19:54:32 -05:00
|
|
|
"github.com/docker/docker/pkg/jsonmessage"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
2017-10-11 12:18:27 -04:00
|
|
|
func newUpgradeCommand(dockerCli command.Cli) *cobra.Command {
|
2017-01-28 19:54:32 -05:00
|
|
|
var options pluginOptions
|
|
|
|
cmd := &cobra.Command{
|
|
|
|
Use: "upgrade [OPTIONS] PLUGIN [REMOTE]",
|
|
|
|
Short: "Upgrade an existing plugin",
|
|
|
|
Args: cli.RequiresRangeArgs(1, 2),
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
options.localName = args[0]
|
|
|
|
if len(args) == 2 {
|
|
|
|
options.remote = args[1]
|
|
|
|
}
|
2023-09-09 18:27:44 -04:00
|
|
|
return runUpgrade(cmd.Context(), dockerCli, options)
|
2017-01-28 19:54:32 -05:00
|
|
|
},
|
2017-10-25 12:59:32 -04:00
|
|
|
Annotations: map[string]string{"version": "1.26"},
|
2017-01-28 19:54:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
flags := cmd.Flags()
|
2018-03-08 08:35:17 -05:00
|
|
|
loadPullFlags(dockerCli, &options, flags)
|
2017-01-28 19:54:32 -05:00
|
|
|
flags.BoolVar(&options.skipRemoteCheck, "skip-remote-check", false, "Do not check if specified remote plugin matches existing plugin image")
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
2023-09-09 18:27:44 -04:00
|
|
|
func runUpgrade(ctx context.Context, dockerCli command.Cli, opts pluginOptions) error {
|
2017-01-28 19:54:32 -05:00
|
|
|
p, _, err := dockerCli.Client().PluginInspectWithRaw(ctx, opts.localName)
|
|
|
|
if err != nil {
|
2017-03-09 13:23:45 -05:00
|
|
|
return errors.Errorf("error reading plugin data: %v", err)
|
2017-01-28 19:54:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if p.Enabled {
|
2017-03-09 13:23:45 -05:00
|
|
|
return errors.Errorf("the plugin must be disabled before upgrading")
|
2017-01-28 19:54:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
opts.localName = p.Name
|
|
|
|
if opts.remote == "" {
|
|
|
|
opts.remote = p.PluginReference
|
|
|
|
}
|
2017-01-25 19:54:18 -05:00
|
|
|
remote, err := reference.ParseNormalizedNamed(opts.remote)
|
2017-01-28 19:54:32 -05:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "error parsing remote upgrade image reference")
|
|
|
|
}
|
2017-01-25 19:54:18 -05:00
|
|
|
remote = reference.TagNameOnly(remote)
|
2017-01-28 19:54:32 -05:00
|
|
|
|
2017-01-25 19:54:18 -05:00
|
|
|
old, err := reference.ParseNormalizedNamed(p.PluginReference)
|
2017-01-28 19:54:32 -05:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "error parsing current image reference")
|
|
|
|
}
|
2017-01-25 19:54:18 -05:00
|
|
|
old = reference.TagNameOnly(old)
|
2017-01-28 19:54:32 -05:00
|
|
|
|
2017-01-25 19:54:18 -05:00
|
|
|
fmt.Fprintf(dockerCli.Out(), "Upgrading plugin %s from %s to %s\n", p.Name, reference.FamiliarString(old), reference.FamiliarString(remote))
|
2017-01-28 19:54:32 -05:00
|
|
|
if !opts.skipRemoteCheck && remote.String() != old.String() {
|
2017-02-03 19:07:04 -05:00
|
|
|
if !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), "Plugin images do not match, are you sure?") {
|
2017-01-28 19:54:32 -05:00
|
|
|
return errors.New("canceling upgrade request")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
options, err := buildPullConfig(ctx, dockerCli, opts, "plugin upgrade")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
responseBody, err := dockerCli.Client().PluginUpgrade(ctx, opts.localName, options)
|
|
|
|
if err != nil {
|
|
|
|
if strings.Contains(err.Error(), "target is image") {
|
|
|
|
return errors.New(err.Error() + " - Use `docker image pull`")
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer responseBody.Close()
|
|
|
|
if err := jsonmessage.DisplayJSONMessagesToStream(responseBody, dockerCli.Out(), nil); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fmt.Fprintf(dockerCli.Out(), "Upgraded plugin %s to %s\n", opts.localName, opts.remote) // todo: return proper values from the API for this result
|
|
|
|
return nil
|
|
|
|
}
|