Skip to content

Commit

Permalink
Merge pull request moby#28717 from yongtang/28684-duplicate-docker-pl…
Browse files Browse the repository at this point in the history
…ugin-create

Fix issue caused by duplicate `docker plugin create` with same names
  • Loading branch information
anusha-ragunathan authored Nov 29, 2016
2 parents 492bc8e + 662d456 commit 82b35dd
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 4 deletions.
32 changes: 32 additions & 0 deletions integration-cli/docker_cli_plugins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"

"io/ioutil"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -169,3 +170,34 @@ func (s *DockerSuite) TestPluginEnableDisableNegative(c *check.C) {
_, _, err = dockerCmdWithError("plugin", "remove", pName)
c.Assert(err, checker.IsNil)
}

func (s *DockerSuite) TestPluginCreate(c *check.C) {
testRequires(c, DaemonIsLinux, Network)

name := "foo/bar-driver"
temp, err := ioutil.TempDir("", "foo")
c.Assert(err, checker.IsNil)
defer os.RemoveAll(temp)

data := `{"description": "foo plugin"}`
err = ioutil.WriteFile(filepath.Join(temp, "config.json"), []byte(data), 0644)
c.Assert(err, checker.IsNil)

out, _, err := dockerCmdWithError("plugin", "create", name, temp)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, name)

out, _, err = dockerCmdWithError("plugin", "ls")
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, name)

out, _, err = dockerCmdWithError("plugin", "create", name, temp)
c.Assert(err, checker.NotNil)
c.Assert(out, checker.Contains, "already exist")

out, _, err = dockerCmdWithError("plugin", "ls")
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, name)
// The output will consists of one HEADER line and one line of foo/bar-driver
c.Assert(len(strings.Split(strings.TrimSpace(out), "\n")), checker.Equals, 2)
}
16 changes: 15 additions & 1 deletion plugin/backend_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,18 @@ func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.Reader, opti
return err
}

// In case an error happens, remove the created directory.
if err := pm.createFromContext(ctx, pluginID, pluginDir, tarCtx, options); err != nil {
if err := os.RemoveAll(pluginDir); err != nil {
logrus.Warnf("unable to remove %q from failed plugin creation: %v", pluginDir, err)
}
return err
}

return nil
}

func (pm *Manager) createFromContext(ctx context.Context, pluginID, pluginDir string, tarCtx io.Reader, options *types.PluginCreateOptions) error {
if err := chrootarchive.Untar(tarCtx, pluginDir, nil); err != nil {
return err
}
Expand All @@ -224,7 +236,9 @@ func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.Reader, opti
return err
}

pm.pluginStore.Add(p)
if err := pm.pluginStore.Add(p); err != nil {
return err
}

pm.pluginEventLogger(p.GetID(), repoName, "create")

Expand Down
2 changes: 1 addition & 1 deletion plugin/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (pm *Manager) init() error {
return
}

pm.pluginStore.Add(p)
pm.pluginStore.Update(p)
requiresManualRestore := !pm.liveRestore && p.IsEnabled()

if requiresManualRestore {
Expand Down
23 changes: 21 additions & 2 deletions plugin/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,31 @@ func (ps *Store) SetState(p *v2.Plugin, state bool) {
}

// Add adds a plugin to memory and plugindb.
func (ps *Store) Add(p *v2.Plugin) {
// An error will be returned if there is a collision.
func (ps *Store) Add(p *v2.Plugin) error {
ps.Lock()
defer ps.Unlock()

if v, exist := ps.plugins[p.GetID()]; exist {
return fmt.Errorf("plugin %q has the same ID %s as %q", p.Name(), p.GetID(), v.Name())
}
if _, exist := ps.nameToID[p.Name()]; exist {
return fmt.Errorf("plugin %q already exists", p.Name())
}
ps.plugins[p.GetID()] = p
ps.nameToID[p.Name()] = p.GetID()
ps.updatePluginDB()
return nil
}

// Update updates a plugin to memory and plugindb.
func (ps *Store) Update(p *v2.Plugin) {
ps.Lock()
defer ps.Unlock()

ps.plugins[p.GetID()] = p
ps.nameToID[p.Name()] = p.GetID()
ps.updatePluginDB()
ps.Unlock()
}

// Remove removes a plugin from memory and plugindb.
Expand Down

0 comments on commit 82b35dd

Please sign in to comment.