Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugins: experimental support for new plugin management #23446

Merged
merged 3 commits into from
Jun 15, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
plugins: experimental support for new plugin management
This patch introduces a new experimental engine-level plugin management
with a new API and command line. Plugins can be distributed via a Docker
registry, and their lifecycle is managed by the engine.
This makes plugins a first-class construct.

For more background, have a look at issue #20363.

Documentation is in a separate commit. If you want to understand how the
new plugin system works, you can start by reading the documentation.

Note: backwards compatibility with existing plugins is maintained,
albeit they won't benefit from the advantages of the new system.

Signed-off-by: Tibor Vass <tibor@docker.com>
Signed-off-by: Anusha Ragunathan <anusha@docker.com>
  • Loading branch information
Tibor Vass committed Jun 14, 2016
commit f37117045c5398fd3dca8016ea8ca0cb47e7312b
12 changes: 12 additions & 0 deletions api/client/plugin/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// +build !experimental

package plugin

import (
"github.com/docker/docker/api/client"
"github.com/spf13/cobra"
)

// NewPluginCommand returns a cobra command for `plugin` subcommands
func NewPluginCommand(cmd *cobra.Command, dockerCli *client.DockerCli) {
}
36 changes: 36 additions & 0 deletions api/client/plugin/cmd_experimental.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// +build experimental

package plugin

import (
"fmt"

"github.com/docker/docker/api/client"
"github.com/docker/docker/cli"
"github.com/spf13/cobra"
)

// NewPluginCommand returns a cobra command for `plugin` subcommands
func NewPluginCommand(rootCmd *cobra.Command, dockerCli *client.DockerCli) {
cmd := &cobra.Command{
Use: "plugin",
Short: "Manage Docker plugins",
Args: cli.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
},
}

cmd.AddCommand(
newDisableCommand(dockerCli),
newEnableCommand(dockerCli),
newInspectCommand(dockerCli),
newInstallCommand(dockerCli),
newListCommand(dockerCli),
newRemoveCommand(dockerCli),
newSetCommand(dockerCli),
newPushCommand(dockerCli),
)

rootCmd.AddCommand(cmd)
}
23 changes: 23 additions & 0 deletions api/client/plugin/disable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// +build experimental

package plugin

import (
"github.com/docker/docker/api/client"
"github.com/docker/docker/cli"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

func newDisableCommand(dockerCli *client.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "disable",
Short: "Disable a plugin",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return dockerCli.Client().PluginDisable(context.Background(), args[0])
},
}

return cmd
}
23 changes: 23 additions & 0 deletions api/client/plugin/enable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// +build experimental

package plugin

import (
"github.com/docker/docker/api/client"
"github.com/docker/docker/cli"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

func newEnableCommand(dockerCli *client.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "enable",
Short: "Enable a plugin",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return dockerCli.Client().PluginEnable(context.Background(), args[0])
},
}

return cmd
}
39 changes: 39 additions & 0 deletions api/client/plugin/inspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// +build experimental

package plugin

import (
"encoding/json"

"github.com/docker/docker/api/client"
"github.com/docker/docker/cli"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

func newInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "inspect",
Short: "Inspect a plugin",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return runInspect(dockerCli, args[0])
},
}

return cmd
}

func runInspect(dockerCli *client.DockerCli, name string) error {
p, err := dockerCli.Client().PluginInspect(context.Background(), name)
if err != nil {
return err
}

b, err := json.MarshalIndent(p, "", "\t")
if err != nil {
return err
}
_, err = dockerCli.Out().Write(b)
return err
}
51 changes: 51 additions & 0 deletions api/client/plugin/install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// +build experimental

package plugin

import (
"fmt"

"github.com/docker/docker/api/client"
"github.com/docker/docker/cli"
"github.com/docker/docker/reference"
"github.com/docker/docker/registry"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

func newInstallCommand(dockerCli *client.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "install",
Short: "Install a plugin",
Args: cli.RequiresMinArgs(1), // TODO: allow for set args
RunE: func(cmd *cobra.Command, args []string) error {
return runInstall(dockerCli, args[0], args[1:])
},
}

return cmd
}

func runInstall(dockerCli *client.DockerCli, name string, args []string) error {
named, err := reference.ParseNamed(name) // FIXME: validate
if err != nil {
return err
}
named = reference.WithDefaultTag(named)
ref, ok := named.(reference.NamedTagged)
if !ok {
return fmt.Errorf("invalid name: %s", named.String())
}

ctx := context.Background()

repoInfo, err := registry.ParseRepositoryInfo(named)
authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index)

encodedAuth, err := client.EncodeAuthToBase64(authConfig)
if err != nil {
return err
}
// TODO: pass acceptAllPermissions and noEnable flag
return dockerCli.Client().PluginInstall(ctx, ref.String(), encodedAuth, false, false, dockerCli.In(), dockerCli.Out())
}
44 changes: 44 additions & 0 deletions api/client/plugin/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// +build experimental

package plugin

import (
"fmt"
"text/tabwriter"

"github.com/docker/docker/api/client"
"github.com/docker/docker/cli"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

func newListCommand(dockerCli *client.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "ls",
Short: "List plugins",
Aliases: []string{"list"},
Args: cli.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli)
},
}

return cmd
}

func runList(dockerCli *client.DockerCli) error {
plugins, err := dockerCli.Client().PluginList(context.Background())
if err != nil {
return err
}

w := tabwriter.NewWriter(dockerCli.Out(), 20, 1, 3, ' ', 0)
fmt.Fprintf(w, "NAME \tTAG \tACTIVE")
fmt.Fprintf(w, "\n")

for _, p := range plugins {
fmt.Fprintf(w, "%s\t%s\t%v\n", p.Name, p.Tag, p.Active)
}
w.Flush()
return nil
}
50 changes: 50 additions & 0 deletions api/client/plugin/push.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// +build experimental

package plugin

import (
"fmt"

"golang.org/x/net/context"

"github.com/docker/docker/api/client"
"github.com/docker/docker/cli"
"github.com/docker/docker/reference"
"github.com/docker/docker/registry"
"github.com/spf13/cobra"
)

func newPushCommand(dockerCli *client.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "push",
Short: "Push a plugin",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return runPush(dockerCli, args[0])
},
}
return cmd
}

func runPush(dockerCli *client.DockerCli, name string) error {
named, err := reference.ParseNamed(name) // FIXME: validate
if err != nil {
return err
}
named = reference.WithDefaultTag(named)
ref, ok := named.(reference.NamedTagged)
if !ok {
return fmt.Errorf("invalid name: %s", named.String())
}

ctx := context.Background()

repoInfo, err := registry.ParseRepositoryInfo(named)
authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index)

encodedAuth, err := client.EncodeAuthToBase64(authConfig)
if err != nil {
return err
}
return dockerCli.Client().PluginPush(ctx, ref.String(), encodedAuth)
}
43 changes: 43 additions & 0 deletions api/client/plugin/remove.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// +build experimental

package plugin

import (
"fmt"

"github.com/docker/docker/api/client"
"github.com/docker/docker/cli"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

func newRemoveCommand(dockerCli *client.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "rm",
Short: "Remove a plugin",
Aliases: []string{"remove"},
Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return runRemove(dockerCli, args)
},
}

return cmd
}

func runRemove(dockerCli *client.DockerCli, names []string) error {
var errs cli.Errors
for _, name := range names {
// TODO: pass names to api instead of making multiple api calls
if err := dockerCli.Client().PluginRemove(context.Background(), name); err != nil {
errs = append(errs, err)
continue
}
fmt.Fprintln(dockerCli.Out(), name)
}
// Do not simplify to `return errs` because even if errs == nil, it is not a nil-error interface value.
if errs != nil {
return errs
}
return nil
}
28 changes: 28 additions & 0 deletions api/client/plugin/set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// +build experimental

package plugin

import (
"golang.org/x/net/context"

"github.com/docker/docker/api/client"
"github.com/docker/docker/cli"
"github.com/spf13/cobra"
)

func newSetCommand(dockerCli *client.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "set",
Short: "Change settings for a plugin",
Args: cli.RequiresMinArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
return runSet(dockerCli, args[0], args[1:])
},
}

return cmd
}

func runSet(dockerCli *client.DockerCli, name string, args []string) error {
return dockerCli.Client().PluginSet(context.Background(), name, args)
}
21 changes: 21 additions & 0 deletions api/server/router/plugin/backend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// +build experimental

package plugin

import (
"net/http"

enginetypes "github.com/docker/engine-api/types"
)

// Backend for Plugin
type Backend interface {
Disable(name string) error
Enable(name string) error
List() ([]enginetypes.Plugin, error)
Inspect(name string) (enginetypes.Plugin, error)
Remove(name string) error
Set(name string, args []string) error
Pull(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) (enginetypes.PluginPrivileges, error)
Push(name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) error
}
Loading