mirror of
https://github.com/moby/moby.git
synced 2026-01-11 02:31:44 +00:00
client: refactor plugin api client functions to define options/results structs
Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Austin Vazquez <austin.vazquez@docker.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
committed by
Sebastiaan van Stijn
parent
eddf1a1ad6
commit
909e32b27d
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/moby/moby/api/types/container"
|
||||
"github.com/moby/moby/api/types/events"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
"github.com/moby/moby/api/types/plugin"
|
||||
"github.com/moby/moby/api/types/registry"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/api/types/system"
|
||||
@@ -145,16 +144,16 @@ type NodeAPIClient interface {
|
||||
|
||||
// PluginAPIClient defines API client methods for the plugins
|
||||
type PluginAPIClient interface {
|
||||
PluginList(ctx context.Context, opts PluginListOptions) (plugin.ListResponse, error)
|
||||
PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) error
|
||||
PluginEnable(ctx context.Context, name string, options PluginEnableOptions) error
|
||||
PluginDisable(ctx context.Context, name string, options PluginDisableOptions) error
|
||||
PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (io.ReadCloser, error)
|
||||
PluginUpgrade(ctx context.Context, name string, options PluginInstallOptions) (io.ReadCloser, error)
|
||||
PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error)
|
||||
PluginSet(ctx context.Context, name string, args []string) error
|
||||
PluginList(ctx context.Context, options PluginListOptions) (PluginListResult, error)
|
||||
PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) (PluginRemoveResult, error)
|
||||
PluginEnable(ctx context.Context, name string, options PluginEnableOptions) (PluginEnableResult, error)
|
||||
PluginDisable(ctx context.Context, name string, options PluginDisableOptions) (PluginDisableResult, error)
|
||||
PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (PluginInstallResult, error)
|
||||
PluginUpgrade(ctx context.Context, name string, options PluginUpgradeOptions) (PluginUpgradeResult, error)
|
||||
PluginPush(ctx context.Context, name string, options PluginPushOptions) (PluginPushResult, error)
|
||||
PluginSet(ctx context.Context, name string, options PluginSetOptions) (PluginSetResult, error)
|
||||
PluginInspect(ctx context.Context, name string, options PluginInspectOptions) (PluginInspectResult, error)
|
||||
PluginCreate(ctx context.Context, createContext io.Reader, options PluginCreateOptions) error
|
||||
PluginCreate(ctx context.Context, createContext io.Reader, options PluginCreateOptions) (PluginCreateResult, error)
|
||||
}
|
||||
|
||||
// ServiceAPIClient defines API client methods for the services
|
||||
|
||||
@@ -12,8 +12,13 @@ type PluginCreateOptions struct {
|
||||
RepoName string
|
||||
}
|
||||
|
||||
// PluginCreateResult represents the result of a plugin create operation.
|
||||
type PluginCreateResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginCreate creates a plugin
|
||||
func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, createOptions PluginCreateOptions) error {
|
||||
func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, createOptions PluginCreateOptions) (PluginCreateResult, error) {
|
||||
headers := http.Header(make(map[string][]string))
|
||||
headers.Set("Content-Type", "application/x-tar")
|
||||
|
||||
@@ -22,5 +27,5 @@ func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, cr
|
||||
|
||||
resp, err := cli.postRaw(ctx, "/plugins/create", query, createContext, headers)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginCreateResult{}, err
|
||||
}
|
||||
|
||||
@@ -10,11 +10,16 @@ type PluginDisableOptions struct {
|
||||
Force bool
|
||||
}
|
||||
|
||||
// PluginDisableResult represents the result of a plugin disable operation.
|
||||
type PluginDisableResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginDisable disables a plugin
|
||||
func (cli *Client) PluginDisable(ctx context.Context, name string, options PluginDisableOptions) error {
|
||||
func (cli *Client) PluginDisable(ctx context.Context, name string, options PluginDisableOptions) (PluginDisableResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return err
|
||||
return PluginDisableResult{}, err
|
||||
}
|
||||
query := url.Values{}
|
||||
if options.Force {
|
||||
@@ -22,5 +27,5 @@ func (cli *Client) PluginDisable(ctx context.Context, name string, options Plugi
|
||||
}
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/disable", query, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginDisableResult{}, err
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ func TestPluginDisableError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.PluginDisable(context.Background(), "plugin_name", PluginDisableOptions{})
|
||||
_, err = client.PluginDisable(context.Background(), "plugin_name", PluginDisableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
err = client.PluginDisable(context.Background(), "", PluginDisableOptions{})
|
||||
_, err = client.PluginDisable(context.Background(), "", PluginDisableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
err = client.PluginDisable(context.Background(), " ", PluginDisableOptions{})
|
||||
_, err = client.PluginDisable(context.Background(), " ", PluginDisableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -42,6 +42,6 @@ func TestPluginDisable(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.PluginDisable(context.Background(), "plugin_name", PluginDisableOptions{})
|
||||
_, err = client.PluginDisable(context.Background(), "plugin_name", PluginDisableOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -11,16 +11,21 @@ type PluginEnableOptions struct {
|
||||
Timeout int
|
||||
}
|
||||
|
||||
// PluginEnableResult represents the result of a plugin enable operation.
|
||||
type PluginEnableResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginEnable enables a plugin
|
||||
func (cli *Client) PluginEnable(ctx context.Context, name string, options PluginEnableOptions) error {
|
||||
func (cli *Client) PluginEnable(ctx context.Context, name string, options PluginEnableOptions) (PluginEnableResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return err
|
||||
return PluginEnableResult{}, err
|
||||
}
|
||||
query := url.Values{}
|
||||
query.Set("timeout", strconv.Itoa(options.Timeout))
|
||||
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/enable", query, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginEnableResult{}, err
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ func TestPluginEnableError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.PluginEnable(context.Background(), "plugin_name", PluginEnableOptions{})
|
||||
_, err = client.PluginEnable(context.Background(), "plugin_name", PluginEnableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
err = client.PluginEnable(context.Background(), "", PluginEnableOptions{})
|
||||
_, err = client.PluginEnable(context.Background(), "", PluginEnableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
err = client.PluginEnable(context.Background(), " ", PluginEnableOptions{})
|
||||
_, err = client.PluginEnable(context.Background(), " ", PluginEnableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -42,6 +42,6 @@ func TestPluginEnable(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.PluginEnable(context.Background(), "plugin_name", PluginEnableOptions{})
|
||||
_, err = client.PluginEnable(context.Background(), "plugin_name", PluginEnableOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -33,17 +33,23 @@ type PluginInstallOptions struct {
|
||||
Args []string
|
||||
}
|
||||
|
||||
// PluginInstallResult holds the result of a plugin install operation.
|
||||
// It is an io.ReadCloser from which the caller can read installation progress or result.
|
||||
type PluginInstallResult struct {
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
// PluginInstall installs a plugin
|
||||
func (cli *Client) PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (_ io.ReadCloser, retErr error) {
|
||||
func (cli *Client) PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (_ PluginInstallResult, retErr error) {
|
||||
query := url.Values{}
|
||||
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
|
||||
return nil, fmt.Errorf("invalid remote reference: %w", err)
|
||||
return PluginInstallResult{}, fmt.Errorf("invalid remote reference: %w", err)
|
||||
}
|
||||
query.Set("remote", options.RemoteRef)
|
||||
|
||||
privileges, err := cli.checkPluginPermissions(ctx, query, options)
|
||||
privileges, err := cli.checkPluginPermissions(ctx, query, &options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return PluginInstallResult{}, err
|
||||
}
|
||||
|
||||
// set name for plugin pull, if empty should default to remote reference
|
||||
@@ -51,7 +57,7 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options Plugi
|
||||
|
||||
resp, err := cli.tryPluginPull(ctx, query, privileges, options.RegistryAuth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return PluginInstallResult{}, err
|
||||
}
|
||||
|
||||
name = resp.Header.Get("Docker-Plugin-Name")
|
||||
@@ -70,7 +76,7 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options Plugi
|
||||
}
|
||||
}()
|
||||
if len(options.Args) > 0 {
|
||||
if err := cli.PluginSet(ctx, name, options.Args); err != nil {
|
||||
if _, err := cli.PluginSet(ctx, name, PluginSetOptions{Args: options.Args}); err != nil {
|
||||
_ = pw.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
@@ -81,10 +87,10 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options Plugi
|
||||
return
|
||||
}
|
||||
|
||||
enableErr := cli.PluginEnable(ctx, name, PluginEnableOptions{Timeout: 0})
|
||||
_, enableErr := cli.PluginEnable(ctx, name, PluginEnableOptions{Timeout: 0})
|
||||
_ = pw.CloseWithError(enableErr)
|
||||
}()
|
||||
return pr, nil
|
||||
return PluginInstallResult{pr}, nil
|
||||
}
|
||||
|
||||
func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {
|
||||
@@ -99,17 +105,17 @@ func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileg
|
||||
})
|
||||
}
|
||||
|
||||
func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options PluginInstallOptions) (plugin.Privileges, error) {
|
||||
resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
|
||||
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
|
||||
func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options pluginOptions) (plugin.Privileges, error) {
|
||||
resp, err := cli.tryPluginPrivileges(ctx, query, options.getRegistryAuth())
|
||||
if cerrdefs.IsUnauthorized(err) && options.getPrivilegeFunc() != nil {
|
||||
// TODO: do inspect before to check existing name before checking privileges
|
||||
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
|
||||
newAuthHeader, privilegeErr := options.getPrivilegeFunc()(ctx)
|
||||
if privilegeErr != nil {
|
||||
ensureReaderClosed(resp)
|
||||
return nil, privilegeErr
|
||||
}
|
||||
options.RegistryAuth = newAuthHeader
|
||||
resp, err = cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
|
||||
options.setRegistryAuth(newAuthHeader)
|
||||
resp, err = cli.tryPluginPrivileges(ctx, query, options.getRegistryAuth())
|
||||
}
|
||||
if err != nil {
|
||||
ensureReaderClosed(resp)
|
||||
@@ -123,14 +129,47 @@ func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values,
|
||||
}
|
||||
ensureReaderClosed(resp)
|
||||
|
||||
if !options.AcceptAllPermissions && options.AcceptPermissionsFunc != nil && len(privileges) > 0 {
|
||||
accept, err := options.AcceptPermissionsFunc(ctx, privileges)
|
||||
if !options.getAcceptAllPermissions() && options.getAcceptPermissionsFunc() != nil && len(privileges) > 0 {
|
||||
accept, err := options.getAcceptPermissionsFunc()(ctx, privileges)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !accept {
|
||||
return nil, errors.New("permission denied while installing plugin " + options.RemoteRef)
|
||||
return nil, errors.New("permission denied while installing plugin " + options.getRemoteRef())
|
||||
}
|
||||
}
|
||||
return privileges, nil
|
||||
}
|
||||
|
||||
type pluginOptions interface {
|
||||
getRegistryAuth() string
|
||||
setRegistryAuth(string)
|
||||
getPrivilegeFunc() func(context.Context) (string, error)
|
||||
getAcceptAllPermissions() bool
|
||||
getAcceptPermissionsFunc() func(context.Context, plugin.Privileges) (bool, error)
|
||||
getRemoteRef() string
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getRegistryAuth() string {
|
||||
return o.RegistryAuth
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) setRegistryAuth(auth string) {
|
||||
o.RegistryAuth = auth
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getPrivilegeFunc() func(context.Context) (string, error) {
|
||||
return o.PrivilegeFunc
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getAcceptAllPermissions() bool {
|
||||
return o.AcceptAllPermissions
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getAcceptPermissionsFunc() func(context.Context, plugin.Privileges) (bool, error) {
|
||||
return o.AcceptPermissionsFunc
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getRemoteRef() string {
|
||||
return o.RemoteRef
|
||||
}
|
||||
|
||||
@@ -13,18 +13,23 @@ type PluginListOptions struct {
|
||||
Filters Filters
|
||||
}
|
||||
|
||||
// PluginListResult represents the result of a plugin list operation.
|
||||
type PluginListResult struct {
|
||||
Items []*plugin.Plugin
|
||||
}
|
||||
|
||||
// PluginList returns the installed plugins
|
||||
func (cli *Client) PluginList(ctx context.Context, opts PluginListOptions) (plugin.ListResponse, error) {
|
||||
var plugins plugin.ListResponse
|
||||
func (cli *Client) PluginList(ctx context.Context, options PluginListOptions) (PluginListResult, error) {
|
||||
query := url.Values{}
|
||||
|
||||
opts.Filters.updateURLValues(query)
|
||||
options.Filters.updateURLValues(query)
|
||||
resp, err := cli.get(ctx, "/plugins", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return plugins, err
|
||||
return PluginListResult{}, err
|
||||
}
|
||||
|
||||
var plugins plugin.ListResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&plugins)
|
||||
return plugins, err
|
||||
return PluginListResult{Items: plugins}, err
|
||||
}
|
||||
|
||||
@@ -85,10 +85,10 @@ func TestPluginList(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
plugins, err := client.PluginList(context.Background(), PluginListOptions{
|
||||
list, err := client.PluginList(context.Background(), PluginListOptions{
|
||||
Filters: listCase.filters,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(plugins, 2))
|
||||
assert.Check(t, is.Len(list.Items, 2))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,17 +8,27 @@ import (
|
||||
"github.com/moby/moby/api/types/registry"
|
||||
)
|
||||
|
||||
// PluginPushOptions holds parameters to push a plugin.
|
||||
type PluginPushOptions struct {
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
|
||||
}
|
||||
|
||||
// PluginPushResult is the result of a plugin push operation
|
||||
type PluginPushResult struct {
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
// PluginPush pushes a plugin to a registry
|
||||
func (cli *Client) PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error) {
|
||||
func (cli *Client) PluginPush(ctx context.Context, name string, options PluginPushOptions) (PluginPushResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return PluginPushResult{}, err
|
||||
}
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, http.Header{
|
||||
registry.AuthHeader: {registryAuth},
|
||||
registry.AuthHeader: {options.RegistryAuth},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return PluginPushResult{}, err
|
||||
}
|
||||
return resp.Body, nil
|
||||
return PluginPushResult{resp.Body}, nil
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ func TestPluginPushError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginPush(context.Background(), "plugin_name", "")
|
||||
_, err = client.PluginPush(context.Background(), "plugin_name", PluginPushOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.PluginPush(context.Background(), "", "")
|
||||
_, err = client.PluginPush(context.Background(), "", PluginPushOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.PluginPush(context.Background(), " ", "")
|
||||
_, err = client.PluginPush(context.Background(), " ", PluginPushOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -48,6 +48,6 @@ func TestPluginPush(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginPush(context.Background(), "plugin_name", "authtoken")
|
||||
_, err = client.PluginPush(context.Background(), "plugin_name", PluginPushOptions{RegistryAuth: "authtoken"})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -10,11 +10,16 @@ type PluginRemoveOptions struct {
|
||||
Force bool
|
||||
}
|
||||
|
||||
// PluginRemoveResult represents the result of a plugin removal.
|
||||
type PluginRemoveResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginRemove removes a plugin
|
||||
func (cli *Client) PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) error {
|
||||
func (cli *Client) PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) (PluginRemoveResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return err
|
||||
return PluginRemoveResult{}, err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
@@ -24,5 +29,5 @@ func (cli *Client) PluginRemove(ctx context.Context, name string, options Plugin
|
||||
|
||||
resp, err := cli.delete(ctx, "/plugins/"+name, query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginRemoveResult{}, err
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ func TestPluginRemoveError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.PluginRemove(context.Background(), "plugin_name", PluginRemoveOptions{})
|
||||
_, err = client.PluginRemove(context.Background(), "plugin_name", PluginRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
err = client.PluginRemove(context.Background(), "", PluginRemoveOptions{})
|
||||
_, err = client.PluginRemove(context.Background(), "", PluginRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
err = client.PluginRemove(context.Background(), " ", PluginRemoveOptions{})
|
||||
_, err = client.PluginRemove(context.Background(), " ", PluginRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -42,6 +42,6 @@ func TestPluginRemove(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.PluginRemove(context.Background(), "plugin_name", PluginRemoveOptions{})
|
||||
_, err = client.PluginRemove(context.Background(), "plugin_name", PluginRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -4,14 +4,24 @@ import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// PluginSetOptions defines options for modifying a plugin's settings.
|
||||
type PluginSetOptions struct {
|
||||
Args []string
|
||||
}
|
||||
|
||||
// PluginSetResult represents the result of a plugin set operation.
|
||||
type PluginSetResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginSet modifies settings for an existing plugin
|
||||
func (cli *Client) PluginSet(ctx context.Context, name string, args []string) error {
|
||||
func (cli *Client) PluginSet(ctx context.Context, name string, options PluginSetOptions) (PluginSetResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return err
|
||||
return PluginSetResult{}, err
|
||||
}
|
||||
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/set", nil, args, nil)
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/set", nil, options.Args, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginSetResult{}, err
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ func TestPluginSetError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.PluginSet(context.Background(), "plugin_name", []string{})
|
||||
_, err = client.PluginSet(context.Background(), "plugin_name", PluginSetOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
err = client.PluginSet(context.Background(), "", []string{})
|
||||
_, err = client.PluginSet(context.Background(), "", PluginSetOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
err = client.PluginSet(context.Background(), " ", []string{})
|
||||
_, err = client.PluginSet(context.Background(), " ", PluginSetOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -42,6 +42,6 @@ func TestPluginSet(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.PluginSet(context.Background(), "plugin_name", []string{"arg1"})
|
||||
_, err = client.PluginSet(context.Background(), "plugin_name", PluginSetOptions{Args: []string{"arg1"}})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,29 @@ import (
|
||||
"github.com/moby/moby/api/types/registry"
|
||||
)
|
||||
|
||||
// PluginUpgradeOptions holds parameters to upgrade a plugin.
|
||||
type PluginUpgradeOptions struct {
|
||||
Disabled bool
|
||||
AcceptAllPermissions bool
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
|
||||
RemoteRef string // RemoteRef is the plugin name on the registry
|
||||
|
||||
// PrivilegeFunc is a function that clients can supply to retry operations
|
||||
// after getting an authorization error. This function returns the registry
|
||||
// authentication header value in base64 encoded format, or an error if the
|
||||
// privilege request fails.
|
||||
//
|
||||
// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
|
||||
PrivilegeFunc func(context.Context) (string, error)
|
||||
AcceptPermissionsFunc func(context.Context, plugin.Privileges) (bool, error)
|
||||
Args []string
|
||||
}
|
||||
|
||||
// PluginUpgradeResult holds the result of a plugin upgrade operation.
|
||||
type PluginUpgradeResult io.ReadCloser
|
||||
|
||||
// PluginUpgrade upgrades a plugin
|
||||
func (cli *Client) PluginUpgrade(ctx context.Context, name string, options PluginInstallOptions) (io.ReadCloser, error) {
|
||||
func (cli *Client) PluginUpgrade(ctx context.Context, name string, options PluginUpgradeOptions) (PluginUpgradeResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -25,7 +46,7 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options Plugi
|
||||
}
|
||||
query.Set("remote", options.RemoteRef)
|
||||
|
||||
privileges, err := cli.checkPluginPermissions(ctx, query, options)
|
||||
privileges, err := cli.checkPluginPermissions(ctx, query, &options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -42,3 +63,27 @@ func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privi
|
||||
registry.AuthHeader: {registryAuth},
|
||||
})
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getRegistryAuth() string {
|
||||
return o.RegistryAuth
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) setRegistryAuth(auth string) {
|
||||
o.RegistryAuth = auth
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getPrivilegeFunc() func(context.Context) (string, error) {
|
||||
return o.PrivilegeFunc
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getAcceptAllPermissions() bool {
|
||||
return o.AcceptAllPermissions
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getAcceptPermissionsFunc() func(context.Context, plugin.Privileges) (bool, error) {
|
||||
return o.AcceptPermissionsFunc
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getRemoteRef() string {
|
||||
return o.RemoteRef
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func TestAuthZPluginV2Disable(t *testing.T) {
|
||||
assert.ErrorContains(t, err, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
|
||||
|
||||
// disable the plugin
|
||||
err = c.PluginDisable(ctx, authzPluginNameWithTag, client.PluginDisableOptions{})
|
||||
_, err = c.PluginDisable(ctx, authzPluginNameWithTag, client.PluginDisableOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// now test to see if the docker api works.
|
||||
|
||||
@@ -135,14 +135,14 @@ func TestPluginInstall(t *testing.T) {
|
||||
err := plugin.Create(ctx, apiclient, repo)
|
||||
assert.NilError(t, err)
|
||||
|
||||
rdr, err := apiclient.PluginPush(ctx, repo, "")
|
||||
pushResult, err := apiclient.PluginPush(ctx, repo, client.PluginPushOptions{})
|
||||
assert.NilError(t, err)
|
||||
defer rdr.Close()
|
||||
defer pushResult.Close()
|
||||
|
||||
buf := &strings.Builder{}
|
||||
assert.NilError(t, err)
|
||||
var digest string
|
||||
assert.NilError(t, jsonmessage.DisplayJSONMessagesStream(rdr, buf, 0, false, func(j jsonmessage.JSONMessage) {
|
||||
assert.NilError(t, jsonmessage.DisplayJSONMessagesStream(pushResult, buf, 0, false, func(j jsonmessage.JSONMessage) {
|
||||
if j.Aux != nil {
|
||||
var r types.PushResult
|
||||
assert.NilError(t, json.Unmarshal(*j.Aux, &r))
|
||||
@@ -150,17 +150,17 @@ func TestPluginInstall(t *testing.T) {
|
||||
}
|
||||
}), buf)
|
||||
|
||||
err = apiclient.PluginRemove(ctx, repo, client.PluginRemoveOptions{Force: true})
|
||||
_, err = apiclient.PluginRemove(ctx, repo, client.PluginRemoveOptions{Force: true})
|
||||
assert.NilError(t, err)
|
||||
|
||||
rdr, err = apiclient.PluginInstall(ctx, repo, client.PluginInstallOptions{
|
||||
installResult, err := apiclient.PluginInstall(ctx, repo, client.PluginInstallOptions{
|
||||
Disabled: true,
|
||||
RemoteRef: repo + "@" + digest,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
defer rdr.Close()
|
||||
defer installResult.Close()
|
||||
|
||||
_, err = io.Copy(io.Discard, rdr)
|
||||
_, err = io.Copy(io.Discard, installResult)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = apiclient.PluginInspect(ctx, repo, client.PluginInspectOptions{})
|
||||
@@ -268,9 +268,12 @@ func TestPluginsWithRuntimes(t *testing.T) {
|
||||
apiclient := d.NewClientT(t)
|
||||
|
||||
assert.NilError(t, plugin.Create(ctx, apiclient, "test:latest"))
|
||||
defer apiclient.PluginRemove(ctx, "test:latest", client.PluginRemoveOptions{Force: true})
|
||||
defer func() {
|
||||
_, _ = apiclient.PluginRemove(ctx, "test:latest", client.PluginRemoveOptions{Force: true})
|
||||
}()
|
||||
|
||||
assert.NilError(t, apiclient.PluginEnable(ctx, "test:latest", client.PluginEnableOptions{Timeout: 30}))
|
||||
_, err = apiclient.PluginEnable(ctx, "test:latest", client.PluginEnableOptions{Timeout: 30})
|
||||
assert.NilError(t, err)
|
||||
|
||||
p := filepath.Join(dir, "myrt")
|
||||
script := fmt.Sprintf(`#!/bin/sh
|
||||
@@ -331,12 +334,12 @@ func TestPluginBackCompatMediaTypes(t *testing.T) {
|
||||
|
||||
assert.NilError(t, plugin.Create(ctx, apiclient, repo))
|
||||
|
||||
rdr, err := apiclient.PluginPush(ctx, repo, "")
|
||||
res, err := apiclient.PluginPush(ctx, repo, client.PluginPushOptions{})
|
||||
assert.NilError(t, err)
|
||||
defer rdr.Close()
|
||||
defer res.Close()
|
||||
|
||||
buf := &strings.Builder{}
|
||||
assert.NilError(t, jsonmessage.DisplayJSONMessagesStream(rdr, buf, 0, false, nil), buf)
|
||||
assert.NilError(t, jsonmessage.DisplayJSONMessagesStream(res, buf, 0, false, nil), buf)
|
||||
|
||||
// Use custom header here because older versions of the registry do not
|
||||
// parse the accept header correctly and does not like the accept header
|
||||
@@ -356,7 +359,7 @@ func TestPluginBackCompatMediaTypes(t *testing.T) {
|
||||
fetcher, err := resolver.Fetcher(ctx, n)
|
||||
assert.NilError(t, err)
|
||||
|
||||
rdr, err = fetcher.Fetch(ctx, desc)
|
||||
rdr, err := fetcher.Fetch(ctx, desc)
|
||||
assert.NilError(t, err)
|
||||
defer rdr.Close()
|
||||
|
||||
|
||||
@@ -31,9 +31,12 @@ func TestContinueAfterPluginCrash(t *testing.T) {
|
||||
|
||||
ctxT, cancel := context.WithTimeout(ctx, 60*time.Second)
|
||||
defer cancel()
|
||||
assert.Assert(t, apiclient.PluginEnable(ctxT, "test", client.PluginEnableOptions{Timeout: 30}))
|
||||
_, err := apiclient.PluginEnable(ctxT, "test", client.PluginEnableOptions{Timeout: 30})
|
||||
assert.NilError(t, err)
|
||||
cancel()
|
||||
defer apiclient.PluginRemove(ctx, "test", client.PluginRemoveOptions{Force: true})
|
||||
defer func() {
|
||||
_, _ = apiclient.PluginRemove(ctx, "test", client.PluginRemoveOptions{Force: true})
|
||||
}()
|
||||
|
||||
ctxT, cancel = context.WithTimeout(ctx, 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestReadPluginNoRead(t *testing.T) {
|
||||
assert.Assert(t, err)
|
||||
createPlugin(ctx, t, apiclient, "test", "discard", asLogDriver)
|
||||
|
||||
err = apiclient.PluginEnable(ctx, "test", client.PluginEnableOptions{Timeout: 30})
|
||||
_, err = apiclient.PluginEnable(ctx, "test", client.PluginEnableOptions{Timeout: 30})
|
||||
assert.Check(t, err)
|
||||
d.Stop(t)
|
||||
|
||||
|
||||
@@ -29,9 +29,11 @@ func TestDaemonStartWithLogOpt(t *testing.T) {
|
||||
c := d.NewClientT(t)
|
||||
|
||||
createPlugin(ctx, t, c, "test", "dummy", asLogDriver)
|
||||
err := c.PluginEnable(ctx, "test", client.PluginEnableOptions{Timeout: 30})
|
||||
_, err := c.PluginEnable(ctx, "test", client.PluginEnableOptions{Timeout: 30})
|
||||
assert.Check(t, err)
|
||||
defer c.PluginRemove(ctx, "test", client.PluginRemoveOptions{Force: true})
|
||||
defer func() {
|
||||
_, _ = c.PluginRemove(ctx, "test", client.PluginRemoveOptions{Force: true})
|
||||
}()
|
||||
|
||||
d.Stop(t)
|
||||
d.Start(t, "--iptables=false", "--ip6tables=false", "--log-driver=test", "--log-opt=foo=bar")
|
||||
|
||||
@@ -47,10 +47,10 @@ func TestPluginWithDevMounts(t *testing.T) {
|
||||
c.IpcHost = true
|
||||
})
|
||||
|
||||
err = c.PluginEnable(ctx, "test", client.PluginEnableOptions{Timeout: 30})
|
||||
_, err = c.PluginEnable(ctx, "test", client.PluginEnableOptions{Timeout: 30})
|
||||
assert.NilError(t, err)
|
||||
defer func() {
|
||||
err := c.PluginRemove(ctx, "test", client.PluginRemoveOptions{Force: true})
|
||||
_, err := c.PluginRemove(ctx, "test", client.PluginRemoveOptions{Force: true})
|
||||
assert.Check(t, err)
|
||||
}()
|
||||
|
||||
|
||||
@@ -35,19 +35,19 @@ func TestServicePlugin(t *testing.T) {
|
||||
apiclient := d.NewClientT(t)
|
||||
err := plugin.Create(ctx, apiclient, repo)
|
||||
assert.NilError(t, err)
|
||||
r, err := apiclient.PluginPush(ctx, repo, "")
|
||||
r, err := apiclient.PluginPush(ctx, repo, client.PluginPushOptions{})
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(io.Discard, r)
|
||||
assert.NilError(t, err)
|
||||
err = apiclient.PluginRemove(ctx, repo, client.PluginRemoveOptions{})
|
||||
_, err = apiclient.PluginRemove(ctx, repo, client.PluginRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
err = plugin.Create(ctx, apiclient, repo2)
|
||||
assert.NilError(t, err)
|
||||
r, err = apiclient.PluginPush(ctx, repo2, "")
|
||||
r, err = apiclient.PluginPush(ctx, repo2, client.PluginPushOptions{})
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(io.Discard, r)
|
||||
assert.NilError(t, err)
|
||||
err = apiclient.PluginRemove(ctx, repo2, client.PluginRemoveOptions{})
|
||||
_, err = apiclient.PluginRemove(ctx, repo2, client.PluginRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
d.Stop(t)
|
||||
|
||||
|
||||
@@ -164,18 +164,18 @@ func deleteAllNetworks(ctx context.Context, t testing.TB, c client.NetworkAPICli
|
||||
|
||||
func deleteAllPlugins(ctx context.Context, t testing.TB, c client.PluginAPIClient, protectedPlugins map[string]struct{}) {
|
||||
t.Helper()
|
||||
plugins, err := c.PluginList(ctx, client.PluginListOptions{})
|
||||
res, err := c.PluginList(ctx, client.PluginListOptions{})
|
||||
// Docker EE does not allow cluster-wide plugin management.
|
||||
if cerrdefs.IsNotImplemented(err) {
|
||||
return
|
||||
}
|
||||
assert.Check(t, err, "failed to list plugins")
|
||||
|
||||
for _, p := range plugins {
|
||||
for _, p := range res.Items {
|
||||
if _, ok := protectedPlugins[p.Name]; ok {
|
||||
continue
|
||||
}
|
||||
err := c.PluginRemove(ctx, p.Name, client.PluginRemoveOptions{Force: true})
|
||||
_, err := c.PluginRemove(ctx, p.Name, client.PluginRemoveOptions{Force: true})
|
||||
assert.Check(t, err, "failed to remove plugin %s", p.ID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ func ProtectPlugins(ctx context.Context, t testing.TB, testEnv *Execution) {
|
||||
func getExistingPlugins(ctx context.Context, t testing.TB, testEnv *Execution) []string {
|
||||
t.Helper()
|
||||
apiClient := testEnv.APIClient()
|
||||
pluginList, err := apiClient.PluginList(ctx, client.PluginListOptions{})
|
||||
res, err := apiClient.PluginList(ctx, client.PluginListOptions{})
|
||||
// Docker EE does not allow cluster-wide plugin management.
|
||||
if cerrdefs.IsNotImplemented(err) {
|
||||
return []string{}
|
||||
@@ -202,7 +202,7 @@ func getExistingPlugins(ctx context.Context, t testing.TB, testEnv *Execution) [
|
||||
assert.NilError(t, err, "failed to list plugins")
|
||||
|
||||
var plugins []string
|
||||
for _, plugin := range pluginList {
|
||||
for _, plugin := range res.Items {
|
||||
plugins = append(plugins, plugin.Name)
|
||||
}
|
||||
return plugins
|
||||
|
||||
@@ -51,7 +51,7 @@ func WithBinary(bin string) CreateOpt {
|
||||
// CreateClient is the interface used for `BuildPlugin` to interact with the
|
||||
// daemon.
|
||||
type CreateClient interface {
|
||||
PluginCreate(context.Context, io.Reader, client.PluginCreateOptions) error
|
||||
PluginCreate(context.Context, io.Reader, client.PluginCreateOptions) (client.PluginCreateResult, error)
|
||||
}
|
||||
|
||||
// Create creates a new plugin with the specified name
|
||||
@@ -71,7 +71,8 @@ func Create(ctx context.Context, c CreateClient, name string, opts ...CreateOpt)
|
||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
return c.PluginCreate(ctx, tar, client.PluginCreateOptions{RepoName: name})
|
||||
_, err = c.PluginCreate(ctx, tar, client.PluginCreateOptions{RepoName: name})
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateInRegistry makes a plugin (locally) and pushes it to a registry.
|
||||
|
||||
19
vendor/github.com/moby/moby/client/client_interfaces.go
generated
vendored
19
vendor/github.com/moby/moby/client/client_interfaces.go
generated
vendored
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/moby/moby/api/types/container"
|
||||
"github.com/moby/moby/api/types/events"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
"github.com/moby/moby/api/types/plugin"
|
||||
"github.com/moby/moby/api/types/registry"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/api/types/system"
|
||||
@@ -145,16 +144,16 @@ type NodeAPIClient interface {
|
||||
|
||||
// PluginAPIClient defines API client methods for the plugins
|
||||
type PluginAPIClient interface {
|
||||
PluginList(ctx context.Context, opts PluginListOptions) (plugin.ListResponse, error)
|
||||
PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) error
|
||||
PluginEnable(ctx context.Context, name string, options PluginEnableOptions) error
|
||||
PluginDisable(ctx context.Context, name string, options PluginDisableOptions) error
|
||||
PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (io.ReadCloser, error)
|
||||
PluginUpgrade(ctx context.Context, name string, options PluginInstallOptions) (io.ReadCloser, error)
|
||||
PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error)
|
||||
PluginSet(ctx context.Context, name string, args []string) error
|
||||
PluginList(ctx context.Context, options PluginListOptions) (PluginListResult, error)
|
||||
PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) (PluginRemoveResult, error)
|
||||
PluginEnable(ctx context.Context, name string, options PluginEnableOptions) (PluginEnableResult, error)
|
||||
PluginDisable(ctx context.Context, name string, options PluginDisableOptions) (PluginDisableResult, error)
|
||||
PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (PluginInstallResult, error)
|
||||
PluginUpgrade(ctx context.Context, name string, options PluginUpgradeOptions) (PluginUpgradeResult, error)
|
||||
PluginPush(ctx context.Context, name string, options PluginPushOptions) (PluginPushResult, error)
|
||||
PluginSet(ctx context.Context, name string, options PluginSetOptions) (PluginSetResult, error)
|
||||
PluginInspect(ctx context.Context, name string, options PluginInspectOptions) (PluginInspectResult, error)
|
||||
PluginCreate(ctx context.Context, createContext io.Reader, options PluginCreateOptions) error
|
||||
PluginCreate(ctx context.Context, createContext io.Reader, options PluginCreateOptions) (PluginCreateResult, error)
|
||||
}
|
||||
|
||||
// ServiceAPIClient defines API client methods for the services
|
||||
|
||||
9
vendor/github.com/moby/moby/client/plugin_create.go
generated
vendored
9
vendor/github.com/moby/moby/client/plugin_create.go
generated
vendored
@@ -12,8 +12,13 @@ type PluginCreateOptions struct {
|
||||
RepoName string
|
||||
}
|
||||
|
||||
// PluginCreateResult represents the result of a plugin create operation.
|
||||
type PluginCreateResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginCreate creates a plugin
|
||||
func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, createOptions PluginCreateOptions) error {
|
||||
func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, createOptions PluginCreateOptions) (PluginCreateResult, error) {
|
||||
headers := http.Header(make(map[string][]string))
|
||||
headers.Set("Content-Type", "application/x-tar")
|
||||
|
||||
@@ -22,5 +27,5 @@ func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, cr
|
||||
|
||||
resp, err := cli.postRaw(ctx, "/plugins/create", query, createContext, headers)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginCreateResult{}, err
|
||||
}
|
||||
|
||||
11
vendor/github.com/moby/moby/client/plugin_disable.go
generated
vendored
11
vendor/github.com/moby/moby/client/plugin_disable.go
generated
vendored
@@ -10,11 +10,16 @@ type PluginDisableOptions struct {
|
||||
Force bool
|
||||
}
|
||||
|
||||
// PluginDisableResult represents the result of a plugin disable operation.
|
||||
type PluginDisableResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginDisable disables a plugin
|
||||
func (cli *Client) PluginDisable(ctx context.Context, name string, options PluginDisableOptions) error {
|
||||
func (cli *Client) PluginDisable(ctx context.Context, name string, options PluginDisableOptions) (PluginDisableResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return err
|
||||
return PluginDisableResult{}, err
|
||||
}
|
||||
query := url.Values{}
|
||||
if options.Force {
|
||||
@@ -22,5 +27,5 @@ func (cli *Client) PluginDisable(ctx context.Context, name string, options Plugi
|
||||
}
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/disable", query, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginDisableResult{}, err
|
||||
}
|
||||
|
||||
11
vendor/github.com/moby/moby/client/plugin_enable.go
generated
vendored
11
vendor/github.com/moby/moby/client/plugin_enable.go
generated
vendored
@@ -11,16 +11,21 @@ type PluginEnableOptions struct {
|
||||
Timeout int
|
||||
}
|
||||
|
||||
// PluginEnableResult represents the result of a plugin enable operation.
|
||||
type PluginEnableResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginEnable enables a plugin
|
||||
func (cli *Client) PluginEnable(ctx context.Context, name string, options PluginEnableOptions) error {
|
||||
func (cli *Client) PluginEnable(ctx context.Context, name string, options PluginEnableOptions) (PluginEnableResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return err
|
||||
return PluginEnableResult{}, err
|
||||
}
|
||||
query := url.Values{}
|
||||
query.Set("timeout", strconv.Itoa(options.Timeout))
|
||||
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/enable", query, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginEnableResult{}, err
|
||||
}
|
||||
|
||||
73
vendor/github.com/moby/moby/client/plugin_install.go
generated
vendored
73
vendor/github.com/moby/moby/client/plugin_install.go
generated
vendored
@@ -33,17 +33,23 @@ type PluginInstallOptions struct {
|
||||
Args []string
|
||||
}
|
||||
|
||||
// PluginInstallResult holds the result of a plugin install operation.
|
||||
// It is an io.ReadCloser from which the caller can read installation progress or result.
|
||||
type PluginInstallResult struct {
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
// PluginInstall installs a plugin
|
||||
func (cli *Client) PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (_ io.ReadCloser, retErr error) {
|
||||
func (cli *Client) PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (_ PluginInstallResult, retErr error) {
|
||||
query := url.Values{}
|
||||
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
|
||||
return nil, fmt.Errorf("invalid remote reference: %w", err)
|
||||
return PluginInstallResult{}, fmt.Errorf("invalid remote reference: %w", err)
|
||||
}
|
||||
query.Set("remote", options.RemoteRef)
|
||||
|
||||
privileges, err := cli.checkPluginPermissions(ctx, query, options)
|
||||
privileges, err := cli.checkPluginPermissions(ctx, query, &options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return PluginInstallResult{}, err
|
||||
}
|
||||
|
||||
// set name for plugin pull, if empty should default to remote reference
|
||||
@@ -51,7 +57,7 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options Plugi
|
||||
|
||||
resp, err := cli.tryPluginPull(ctx, query, privileges, options.RegistryAuth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return PluginInstallResult{}, err
|
||||
}
|
||||
|
||||
name = resp.Header.Get("Docker-Plugin-Name")
|
||||
@@ -70,7 +76,7 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options Plugi
|
||||
}
|
||||
}()
|
||||
if len(options.Args) > 0 {
|
||||
if err := cli.PluginSet(ctx, name, options.Args); err != nil {
|
||||
if _, err := cli.PluginSet(ctx, name, PluginSetOptions{Args: options.Args}); err != nil {
|
||||
_ = pw.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
@@ -81,10 +87,10 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options Plugi
|
||||
return
|
||||
}
|
||||
|
||||
enableErr := cli.PluginEnable(ctx, name, PluginEnableOptions{Timeout: 0})
|
||||
_, enableErr := cli.PluginEnable(ctx, name, PluginEnableOptions{Timeout: 0})
|
||||
_ = pw.CloseWithError(enableErr)
|
||||
}()
|
||||
return pr, nil
|
||||
return PluginInstallResult{pr}, nil
|
||||
}
|
||||
|
||||
func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {
|
||||
@@ -99,17 +105,17 @@ func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileg
|
||||
})
|
||||
}
|
||||
|
||||
func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options PluginInstallOptions) (plugin.Privileges, error) {
|
||||
resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
|
||||
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
|
||||
func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options pluginOptions) (plugin.Privileges, error) {
|
||||
resp, err := cli.tryPluginPrivileges(ctx, query, options.getRegistryAuth())
|
||||
if cerrdefs.IsUnauthorized(err) && options.getPrivilegeFunc() != nil {
|
||||
// TODO: do inspect before to check existing name before checking privileges
|
||||
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
|
||||
newAuthHeader, privilegeErr := options.getPrivilegeFunc()(ctx)
|
||||
if privilegeErr != nil {
|
||||
ensureReaderClosed(resp)
|
||||
return nil, privilegeErr
|
||||
}
|
||||
options.RegistryAuth = newAuthHeader
|
||||
resp, err = cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
|
||||
options.setRegistryAuth(newAuthHeader)
|
||||
resp, err = cli.tryPluginPrivileges(ctx, query, options.getRegistryAuth())
|
||||
}
|
||||
if err != nil {
|
||||
ensureReaderClosed(resp)
|
||||
@@ -123,14 +129,47 @@ func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values,
|
||||
}
|
||||
ensureReaderClosed(resp)
|
||||
|
||||
if !options.AcceptAllPermissions && options.AcceptPermissionsFunc != nil && len(privileges) > 0 {
|
||||
accept, err := options.AcceptPermissionsFunc(ctx, privileges)
|
||||
if !options.getAcceptAllPermissions() && options.getAcceptPermissionsFunc() != nil && len(privileges) > 0 {
|
||||
accept, err := options.getAcceptPermissionsFunc()(ctx, privileges)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !accept {
|
||||
return nil, errors.New("permission denied while installing plugin " + options.RemoteRef)
|
||||
return nil, errors.New("permission denied while installing plugin " + options.getRemoteRef())
|
||||
}
|
||||
}
|
||||
return privileges, nil
|
||||
}
|
||||
|
||||
type pluginOptions interface {
|
||||
getRegistryAuth() string
|
||||
setRegistryAuth(string)
|
||||
getPrivilegeFunc() func(context.Context) (string, error)
|
||||
getAcceptAllPermissions() bool
|
||||
getAcceptPermissionsFunc() func(context.Context, plugin.Privileges) (bool, error)
|
||||
getRemoteRef() string
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getRegistryAuth() string {
|
||||
return o.RegistryAuth
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) setRegistryAuth(auth string) {
|
||||
o.RegistryAuth = auth
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getPrivilegeFunc() func(context.Context) (string, error) {
|
||||
return o.PrivilegeFunc
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getAcceptAllPermissions() bool {
|
||||
return o.AcceptAllPermissions
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getAcceptPermissionsFunc() func(context.Context, plugin.Privileges) (bool, error) {
|
||||
return o.AcceptPermissionsFunc
|
||||
}
|
||||
|
||||
func (o *PluginInstallOptions) getRemoteRef() string {
|
||||
return o.RemoteRef
|
||||
}
|
||||
|
||||
15
vendor/github.com/moby/moby/client/plugin_list.go
generated
vendored
15
vendor/github.com/moby/moby/client/plugin_list.go
generated
vendored
@@ -13,18 +13,23 @@ type PluginListOptions struct {
|
||||
Filters Filters
|
||||
}
|
||||
|
||||
// PluginListResult represents the result of a plugin list operation.
|
||||
type PluginListResult struct {
|
||||
Items []*plugin.Plugin
|
||||
}
|
||||
|
||||
// PluginList returns the installed plugins
|
||||
func (cli *Client) PluginList(ctx context.Context, opts PluginListOptions) (plugin.ListResponse, error) {
|
||||
var plugins plugin.ListResponse
|
||||
func (cli *Client) PluginList(ctx context.Context, options PluginListOptions) (PluginListResult, error) {
|
||||
query := url.Values{}
|
||||
|
||||
opts.Filters.updateURLValues(query)
|
||||
options.Filters.updateURLValues(query)
|
||||
resp, err := cli.get(ctx, "/plugins", query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return plugins, err
|
||||
return PluginListResult{}, err
|
||||
}
|
||||
|
||||
var plugins plugin.ListResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&plugins)
|
||||
return plugins, err
|
||||
return PluginListResult{Items: plugins}, err
|
||||
}
|
||||
|
||||
20
vendor/github.com/moby/moby/client/plugin_push.go
generated
vendored
20
vendor/github.com/moby/moby/client/plugin_push.go
generated
vendored
@@ -8,17 +8,27 @@ import (
|
||||
"github.com/moby/moby/api/types/registry"
|
||||
)
|
||||
|
||||
// PluginPushOptions holds parameters to push a plugin.
|
||||
type PluginPushOptions struct {
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
|
||||
}
|
||||
|
||||
// PluginPushResult is the result of a plugin push operation
|
||||
type PluginPushResult struct {
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
// PluginPush pushes a plugin to a registry
|
||||
func (cli *Client) PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error) {
|
||||
func (cli *Client) PluginPush(ctx context.Context, name string, options PluginPushOptions) (PluginPushResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return PluginPushResult{}, err
|
||||
}
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, http.Header{
|
||||
registry.AuthHeader: {registryAuth},
|
||||
registry.AuthHeader: {options.RegistryAuth},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return PluginPushResult{}, err
|
||||
}
|
||||
return resp.Body, nil
|
||||
return PluginPushResult{resp.Body}, nil
|
||||
}
|
||||
|
||||
11
vendor/github.com/moby/moby/client/plugin_remove.go
generated
vendored
11
vendor/github.com/moby/moby/client/plugin_remove.go
generated
vendored
@@ -10,11 +10,16 @@ type PluginRemoveOptions struct {
|
||||
Force bool
|
||||
}
|
||||
|
||||
// PluginRemoveResult represents the result of a plugin removal.
|
||||
type PluginRemoveResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginRemove removes a plugin
|
||||
func (cli *Client) PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) error {
|
||||
func (cli *Client) PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) (PluginRemoveResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return err
|
||||
return PluginRemoveResult{}, err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
@@ -24,5 +29,5 @@ func (cli *Client) PluginRemove(ctx context.Context, name string, options Plugin
|
||||
|
||||
resp, err := cli.delete(ctx, "/plugins/"+name, query, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginRemoveResult{}, err
|
||||
}
|
||||
|
||||
18
vendor/github.com/moby/moby/client/plugin_set.go
generated
vendored
18
vendor/github.com/moby/moby/client/plugin_set.go
generated
vendored
@@ -4,14 +4,24 @@ import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// PluginSetOptions defines options for modifying a plugin's settings.
|
||||
type PluginSetOptions struct {
|
||||
Args []string
|
||||
}
|
||||
|
||||
// PluginSetResult represents the result of a plugin set operation.
|
||||
type PluginSetResult struct {
|
||||
// Currently empty; can be extended in the future if needed.
|
||||
}
|
||||
|
||||
// PluginSet modifies settings for an existing plugin
|
||||
func (cli *Client) PluginSet(ctx context.Context, name string, args []string) error {
|
||||
func (cli *Client) PluginSet(ctx context.Context, name string, options PluginSetOptions) (PluginSetResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return err
|
||||
return PluginSetResult{}, err
|
||||
}
|
||||
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/set", nil, args, nil)
|
||||
resp, err := cli.post(ctx, "/plugins/"+name+"/set", nil, options.Args, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
return PluginSetResult{}, err
|
||||
}
|
||||
|
||||
49
vendor/github.com/moby/moby/client/plugin_upgrade.go
generated
vendored
49
vendor/github.com/moby/moby/client/plugin_upgrade.go
generated
vendored
@@ -12,8 +12,29 @@ import (
|
||||
"github.com/moby/moby/api/types/registry"
|
||||
)
|
||||
|
||||
// PluginUpgradeOptions holds parameters to upgrade a plugin.
|
||||
type PluginUpgradeOptions struct {
|
||||
Disabled bool
|
||||
AcceptAllPermissions bool
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
|
||||
RemoteRef string // RemoteRef is the plugin name on the registry
|
||||
|
||||
// PrivilegeFunc is a function that clients can supply to retry operations
|
||||
// after getting an authorization error. This function returns the registry
|
||||
// authentication header value in base64 encoded format, or an error if the
|
||||
// privilege request fails.
|
||||
//
|
||||
// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
|
||||
PrivilegeFunc func(context.Context) (string, error)
|
||||
AcceptPermissionsFunc func(context.Context, plugin.Privileges) (bool, error)
|
||||
Args []string
|
||||
}
|
||||
|
||||
// PluginUpgradeResult holds the result of a plugin upgrade operation.
|
||||
type PluginUpgradeResult io.ReadCloser
|
||||
|
||||
// PluginUpgrade upgrades a plugin
|
||||
func (cli *Client) PluginUpgrade(ctx context.Context, name string, options PluginInstallOptions) (io.ReadCloser, error) {
|
||||
func (cli *Client) PluginUpgrade(ctx context.Context, name string, options PluginUpgradeOptions) (PluginUpgradeResult, error) {
|
||||
name, err := trimID("plugin", name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -25,7 +46,7 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options Plugi
|
||||
}
|
||||
query.Set("remote", options.RemoteRef)
|
||||
|
||||
privileges, err := cli.checkPluginPermissions(ctx, query, options)
|
||||
privileges, err := cli.checkPluginPermissions(ctx, query, &options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -42,3 +63,27 @@ func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privi
|
||||
registry.AuthHeader: {registryAuth},
|
||||
})
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getRegistryAuth() string {
|
||||
return o.RegistryAuth
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) setRegistryAuth(auth string) {
|
||||
o.RegistryAuth = auth
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getPrivilegeFunc() func(context.Context) (string, error) {
|
||||
return o.PrivilegeFunc
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getAcceptAllPermissions() bool {
|
||||
return o.AcceptAllPermissions
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getAcceptPermissionsFunc() func(context.Context, plugin.Privileges) (bool, error) {
|
||||
return o.AcceptPermissionsFunc
|
||||
}
|
||||
|
||||
func (o *PluginUpgradeOptions) getRemoteRef() string {
|
||||
return o.RemoteRef
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user