Some tests had to be skipped as there's some issues to address, and some of the result-types cannot be mocked / stubbed. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
102 lines
3.2 KiB
Go
102 lines
3.2 KiB
Go
package plugin
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/distribution/reference"
|
|
"github.com/docker/cli/cli"
|
|
"github.com/docker/cli/cli/command"
|
|
"github.com/docker/cli/internal/jsonstream"
|
|
"github.com/docker/cli/internal/prompt"
|
|
"github.com/moby/moby/client"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func newUpgradeCommand(dockerCLI command.Cli) *cobra.Command {
|
|
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]
|
|
}
|
|
return runUpgrade(cmd.Context(), dockerCLI, options)
|
|
},
|
|
Annotations: map[string]string{"version": "1.26"},
|
|
ValidArgsFunction: completeNames(dockerCLI, stateAny), // TODO(thaJeztah): should only complete for the first arg
|
|
DisableFlagsInUseLine: true,
|
|
}
|
|
|
|
flags := cmd.Flags()
|
|
flags.BoolVar(&options.grantPerms, "grant-all-permissions", false, "Grant all permissions necessary to run the plugin")
|
|
flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)")
|
|
_ = flags.MarkHidden("disable-content-trust")
|
|
flags.BoolVar(&options.skipRemoteCheck, "skip-remote-check", false, "Do not check if specified remote plugin matches existing plugin image")
|
|
return cmd
|
|
}
|
|
|
|
func runUpgrade(ctx context.Context, dockerCLI command.Cli, opts pluginOptions) error {
|
|
res, err := dockerCLI.Client().PluginInspect(ctx, opts.localName, client.PluginInspectOptions{})
|
|
if err != nil {
|
|
return fmt.Errorf("error reading plugin data: %w", err)
|
|
}
|
|
|
|
if res.Plugin.Enabled {
|
|
return errors.New("the plugin must be disabled before upgrading")
|
|
}
|
|
|
|
opts.localName = res.Plugin.Name
|
|
if opts.remote == "" {
|
|
opts.remote = res.Plugin.PluginReference
|
|
}
|
|
remote, err := reference.ParseNormalizedNamed(opts.remote)
|
|
if err != nil {
|
|
return fmt.Errorf("error parsing remote upgrade image reference: %w", err)
|
|
}
|
|
remote = reference.TagNameOnly(remote)
|
|
|
|
old, err := reference.ParseNormalizedNamed(res.Plugin.PluginReference)
|
|
if err != nil {
|
|
return fmt.Errorf("error parsing current image reference: %w", err)
|
|
}
|
|
old = reference.TagNameOnly(old)
|
|
|
|
_, _ = fmt.Fprintf(dockerCLI.Out(), "Upgrading plugin %s from %s to %s\n", res.Plugin.Name, reference.FamiliarString(old), reference.FamiliarString(remote))
|
|
if !opts.skipRemoteCheck && remote.String() != old.String() {
|
|
r, err := prompt.Confirm(ctx, dockerCLI.In(), dockerCLI.Out(), "Plugin images do not match, are you sure?")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !r {
|
|
return cancelledErr{errors.New("plugin upgrade has been cancelled")}
|
|
}
|
|
}
|
|
|
|
options, err := buildPullConfig(dockerCLI, opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
responseBody, err := dockerCLI.Client().PluginUpgrade(ctx, opts.localName, client.PluginUpgradeOptions(options))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
_ = responseBody.Close()
|
|
}()
|
|
if err := jsonstream.Display(ctx, responseBody, dockerCLI.Out()); 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
|
|
}
|
|
|
|
type cancelledErr struct{ error }
|
|
|
|
func (cancelledErr) Cancelled() {}
|