Skip to content

Commit

Permalink
Merge pull request #28963 from vieux/refactor_plugin_install
Browse files Browse the repository at this point in the history
refactor plugin install
  • Loading branch information
tiborvass authored Dec 5, 2016
2 parents 04cd199 + 30db51c commit 1c96879
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 120 deletions.
3 changes: 2 additions & 1 deletion api/server/router/plugin/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ type Backend interface {
Inspect(name string) (enginetypes.Plugin, error)
Remove(name string, config *enginetypes.PluginRmConfig) error
Set(name string, args []string) error
Pull(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) (enginetypes.PluginPrivileges, error)
Privileges(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) (enginetypes.PluginPrivileges, error)
Pull(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges) error
Push(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) error
CreateFromContext(ctx context.Context, tarCtx io.Reader, options *enginetypes.PluginCreateOptions) error
}
3 changes: 2 additions & 1 deletion api/server/router/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ func (r *pluginRouter) Routes() []router.Route {
func (r *pluginRouter) initRoutes() {
r.routes = []router.Route{
router.NewGetRoute("/plugins", r.listPlugins),
router.NewGetRoute("/plugins/{name:.*}", r.inspectPlugin),
router.NewGetRoute("/plugins/{name:.*}/json", r.inspectPlugin),
router.NewGetRoute("/plugins/privileges", r.getPrivileges),
router.NewDeleteRoute("/plugins/{name:.*}", r.removePlugin),
router.NewPostRoute("/plugins/{name:.*}/enable", r.enablePlugin), // PATCH?
router.NewPostRoute("/plugins/{name:.*}/disable", r.disablePlugin),
Expand Down
57 changes: 35 additions & 22 deletions api/server/router/plugin/plugin_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,17 @@ import (
"golang.org/x/net/context"
)

func (pr *pluginRouter) pullPlugin(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}
func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig) {

metaHeaders := map[string][]string{}
for k, v := range r.Header {
for k, v := range headers {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
}

// Get X-Registry-Auth
authEncoded := r.Header.Get("X-Registry-Auth")
authEncoded := headers.Get("X-Registry-Auth")
authConfig := &types.AuthConfig{}
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
Expand All @@ -34,13 +31,42 @@ func (pr *pluginRouter) pullPlugin(ctx context.Context, w http.ResponseWriter, r
}
}

privileges, err := pr.backend.Pull(r.FormValue("name"), metaHeaders, authConfig)
return metaHeaders, authConfig
}

func (pr *pluginRouter) getPrivileges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}

metaHeaders, authConfig := parseHeaders(r.Header)

privileges, err := pr.backend.Privileges(r.FormValue("name"), metaHeaders, authConfig)
if err != nil {
return err
}
return httputils.WriteJSON(w, http.StatusOK, privileges)
}

func (pr *pluginRouter) pullPlugin(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}

var privileges types.PluginPrivileges
if err := json.NewDecoder(r.Body).Decode(&privileges); err != nil {
return err
}

metaHeaders, authConfig := parseHeaders(r.Header)

if err := pr.backend.Pull(r.FormValue("name"), metaHeaders, authConfig, privileges); err != nil {
return err
}
w.WriteHeader(http.StatusCreated)
return nil
}

func (pr *pluginRouter) createPlugin(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
Expand All @@ -52,6 +78,7 @@ func (pr *pluginRouter) createPlugin(ctx context.Context, w http.ResponseWriter,
if err := pr.backend.CreateFromContext(ctx, r.Body, options); err != nil {
return err
}
//TODO: send progress bar
w.WriteHeader(http.StatusNoContent)
return nil
}
Expand Down Expand Up @@ -92,22 +119,8 @@ func (pr *pluginRouter) pushPlugin(ctx context.Context, w http.ResponseWriter, r
return err
}

metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
}
metaHeaders, authConfig := parseHeaders(r.Header)

// Get X-Registry-Auth
authEncoded := r.Header.Get("X-Registry-Auth")
authConfig := &types.AuthConfig{}
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
authConfig = &types.AuthConfig{}
}
}
return pr.backend.Push(vars["name"], metaHeaders, authConfig)
}

Expand Down
67 changes: 58 additions & 9 deletions api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6397,14 +6397,10 @@ paths:
$ref: "#/definitions/ErrorResponse"
tags: ["Plugin"]

/plugins/pull:
post:
summary: "Install a plugin"
operationId: "PluginPull"
description: |
Pulls and installs a plugin. After the plugin is installed, it can be enabled using the [`POST /plugins/{name}/enable` endpoint](#operation/PluginEnable).
produces:
- "application/json"
/plugins/privileges:
get:
summary: "Get plugin privileges"
operationId: "GetPluginPrivileges"
responses:
200:
description: "no error"
Expand Down Expand Up @@ -6439,6 +6435,30 @@ paths:
description: "server error"
schema:
$ref: "#/definitions/ErrorResponse"
parameters:
- name: "name"
in: "query"
description: "The name of the plugin. The `:latest` tag is optional, and is the default if omitted."
required: true
type: "string"
tags:
- "Plugin"

/plugins/pull:
post:
summary: "Install a plugin"
operationId: "PluginPull"
description: |
Pulls and installs a plugin. After the plugin is installed, it can be enabled using the [`POST /plugins/{name}/enable` endpoint](#operation/PostPluginsEnable).
produces:
- "application/json"
responses:
204:
description: "no error"
500:
description: "server error"
schema:
$ref: "#/definitions/ErrorResponse"
parameters:
- name: "name"
in: "query"
Expand All @@ -6452,8 +6472,37 @@ paths:
in: "header"
description: "A base64-encoded auth configuration to use when pulling a plugin from a registry. [See the authentication section for details.](#section/Authentication)"
type: "string"
- name: "body"
in: "body"
schema:
type: "array"
items:
description: "Describes a permission accepted by the user upon installing the plugin."
type: "object"
properties:
Name:
type: "string"
Description:
type: "string"
Value:
type: "array"
items:
type: "string"
example:
- Name: "network"
Description: ""
Value:
- "host"
- Name: "mount"
Description: ""
Value:
- "/data"
- Name: "device"
Description: ""
Value:
- "/dev/cpu_dma_latency"
tags: ["Plugin"]
/plugins/{name}:
/plugins/{name}/json:
get:
summary: "Inspect a plugin"
operationId: "PluginInspect"
Expand Down
2 changes: 1 addition & 1 deletion client/plugin_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// PluginInspectWithRaw inspects an existing plugin
func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) {
resp, err := cli.get(ctx, "/plugins/"+name, nil, nil)
resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil)
if err != nil {
if resp.statusCode == http.StatusNotFound {
return nil, nil, pluginNotFoundError{name}
Expand Down
33 changes: 22 additions & 11 deletions client/plugin_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,21 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
// FIXME(vdemeester) name is a ref, we might want to parse/validate it here.
query := url.Values{}
query.Set("name", name)
resp, err := cli.tryPluginPull(ctx, query, options.RegistryAuth)
resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc()
if privilegeErr != nil {
ensureReaderClosed(resp)
return privilegeErr
}
resp, err = cli.tryPluginPull(ctx, query, newAuthHeader)
options.RegistryAuth = newAuthHeader
resp, err = cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
}
if err != nil {
ensureReaderClosed(resp)
return err
}

defer func() {
if err != nil {
delResp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil)
ensureReaderClosed(delResp)
}
}()

var privileges types.PluginPrivileges
if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil {
ensureReaderClosed(resp)
Expand All @@ -52,6 +46,18 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
}
}

_, err = cli.tryPluginPull(ctx, query, privileges, options.RegistryAuth)
if err != nil {
return err
}

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 {
return err
Expand All @@ -65,7 +71,12 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
return cli.PluginEnable(ctx, name, types.PluginEnableOptions{Timeout: 0})
}

func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
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, nil, headers)
return cli.post(ctx, "/plugins/pull", query, privileges, headers)
}
Loading

0 comments on commit 1c96879

Please sign in to comment.