mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
3a1279393f
Remove forked reference package. Use normalized named values everywhere and familiar functions to convert back to familiar strings for UX and storage compatibility. Enforce that the source repository in the distribution metadata is always a normalized string, ignore invalid values which are not. Update distribution tests to use normalized values. Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
113 lines
3.3 KiB
Go
113 lines
3.3 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/docker/distribution/reference"
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/pkg/errors"
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
// PluginInstall installs a plugin
|
|
func (cli *Client) PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) (rc io.ReadCloser, err error) {
|
|
query := url.Values{}
|
|
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
|
|
return nil, errors.Wrap(err, "invalid remote reference")
|
|
}
|
|
query.Set("remote", options.RemoteRef)
|
|
|
|
privileges, err := cli.checkPluginPermissions(ctx, query, options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// set name for plugin pull, if empty should default to remote reference
|
|
query.Set("name", name)
|
|
|
|
resp, err := cli.tryPluginPull(ctx, query, privileges, options.RegistryAuth)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
name = resp.header.Get("Docker-Plugin-Name")
|
|
|
|
pr, pw := io.Pipe()
|
|
go func() { // todo: the client should probably be designed more around the actual api
|
|
_, err := io.Copy(pw, resp.body)
|
|
if err != nil {
|
|
pw.CloseWithError(err)
|
|
return
|
|
}
|
|
defer func() {
|
|
if err != nil {
|
|
delResp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil)
|
|
ensureReaderClosed(delResp)
|
|
}
|
|
}()
|
|
if len(options.Args) > 0 {
|
|
if err := cli.PluginSet(ctx, name, options.Args); err != nil {
|
|
pw.CloseWithError(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
if options.Disabled {
|
|
pw.Close()
|
|
return
|
|
}
|
|
|
|
err = cli.PluginEnable(ctx, name, types.PluginEnableOptions{Timeout: 0})
|
|
pw.CloseWithError(err)
|
|
}()
|
|
return pr, nil
|
|
}
|
|
|
|
func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
|
|
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
|
|
return cli.get(ctx, "/plugins/privileges", query, headers)
|
|
}
|
|
|
|
func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (serverResponse, error) {
|
|
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
|
|
return cli.post(ctx, "/plugins/pull", query, privileges, headers)
|
|
}
|
|
|
|
func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options types.PluginInstallOptions) (types.PluginPrivileges, error) {
|
|
resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
|
|
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
|
|
// todo: do inspect before to check existing name before checking privileges
|
|
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
|
if privilegeErr != nil {
|
|
ensureReaderClosed(resp)
|
|
return nil, privilegeErr
|
|
}
|
|
options.RegistryAuth = newAuthHeader
|
|
resp, err = cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
|
|
}
|
|
if err != nil {
|
|
ensureReaderClosed(resp)
|
|
return nil, err
|
|
}
|
|
|
|
var privileges types.PluginPrivileges
|
|
if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil {
|
|
ensureReaderClosed(resp)
|
|
return nil, err
|
|
}
|
|
ensureReaderClosed(resp)
|
|
|
|
if !options.AcceptAllPermissions && options.AcceptPermissionsFunc != nil && len(privileges) > 0 {
|
|
accept, err := options.AcceptPermissionsFunc(privileges)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !accept {
|
|
return nil, pluginPermissionDenied{options.RemoteRef}
|
|
}
|
|
}
|
|
return privileges, nil
|
|
}
|