-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathinstall.go
More file actions
143 lines (128 loc) · 4.5 KB
/
install.go
File metadata and controls
143 lines (128 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package plugin
import (
"context"
"fmt"
"github.com/distribution/reference"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/trust"
"github.com/docker/cli/internal/jsonstream"
"github.com/docker/cli/internal/prompt"
"github.com/docker/cli/internal/registry"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
type pluginOptions struct {
remote string
localName string
grantPerms bool
disable bool
args []string
skipRemoteCheck bool
untrusted bool
}
func loadPullFlags(opts *pluginOptions, flags *pflag.FlagSet) {
flags.BoolVar(&opts.grantPerms, "grant-all-permissions", false, "Grant all permissions necessary to run the plugin")
flags.BoolVar(&opts.untrusted, "disable-content-trust", !trust.Enabled(), "Skip image verification")
}
func newInstallCommand(dockerCli command.Cli) *cobra.Command {
var options pluginOptions
cmd := &cobra.Command{
Use: "install [OPTIONS] PLUGIN [KEY=VALUE...]",
Short: "Install a plugin",
Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
options.remote = args[0]
if len(args) > 1 {
options.args = args[1:]
}
return runInstall(cmd.Context(), dockerCli, options)
},
}
flags := cmd.Flags()
loadPullFlags(&options, flags)
flags.BoolVar(&options.disable, "disable", false, "Do not enable the plugin on install")
flags.StringVar(&options.localName, "alias", "", "Local name for plugin")
return cmd
}
func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOptions) (types.PluginInstallOptions, error) {
// Names with both tag and digest will be treated by the daemon
// as a pull by digest with a local name for the tag
// (if no local name is provided).
ref, err := reference.ParseNormalizedNamed(opts.remote)
if err != nil {
return types.PluginInstallOptions{}, err
}
indexInfo := registry.NewIndexInfo(ref)
remote := ref.String()
_, isCanonical := ref.(reference.Canonical)
if !opts.untrusted && !isCanonical {
ref = reference.TagNameOnly(ref)
nt, ok := ref.(reference.NamedTagged)
if !ok {
return types.PluginInstallOptions{}, errors.Errorf("invalid name: %s", ref.String())
}
trusted, err := image.TrustedReference(ctx, dockerCli, nt)
if err != nil {
return types.PluginInstallOptions{}, err
}
remote = reference.FamiliarString(trusted)
}
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), indexInfo)
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
if err != nil {
return types.PluginInstallOptions{}, err
}
options := types.PluginInstallOptions{
RegistryAuth: encodedAuth,
RemoteRef: remote,
Disabled: opts.disable,
AcceptAllPermissions: opts.grantPerms,
AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.remote),
PrivilegeFunc: nil,
Args: opts.args,
}
return options, nil
}
func runInstall(ctx context.Context, dockerCLI command.Cli, opts pluginOptions) error {
var localName string
if opts.localName != "" {
aref, err := reference.ParseNormalizedNamed(opts.localName)
if err != nil {
return err
}
if _, ok := aref.(reference.Canonical); ok {
return errors.Errorf("invalid name: %s", opts.localName)
}
localName = reference.FamiliarString(reference.TagNameOnly(aref))
}
options, err := buildPullConfig(ctx, dockerCLI, opts)
if err != nil {
return err
}
responseBody, err := dockerCLI.Client().PluginInstall(ctx, localName, options)
if err != nil {
return err
}
defer func() {
_ = responseBody.Close()
}()
if err := jsonstream.Display(ctx, responseBody, dockerCLI.Out()); err != nil {
return err
}
_, _ = fmt.Fprintln(dockerCLI.Out(), "Installed plugin", opts.remote) // todo: return proper values from the API for this result
return nil
}
func acceptPrivileges(dockerCLI command.Streams, name string) func(ctx context.Context, privileges types.PluginPrivileges) (bool, error) {
return func(ctx context.Context, privileges types.PluginPrivileges) (bool, error) {
_, _ = fmt.Fprintf(dockerCLI.Out(), "Plugin %q is requesting the following privileges:\n", name)
for _, privilege := range privileges {
_, _ = fmt.Fprintf(dockerCLI.Out(), " - %s: %v\n", privilege.Name, privilege.Value)
}
return prompt.Confirm(ctx, dockerCLI.In(), dockerCLI.Out(), "Do you grant the above permissions?")
}
}