소스 검색

Merge pull request #28949 from yongtang/28717-docker-plugin-create

Use GetByName to check for collision before create any context in plugin creation
Anusha Ragunathan 8 년 전
부모
커밋
9d884986f5
2개의 변경된 파일23개의 추가작업 그리고 11개의 파일을 삭제
  1. 16 11
      plugin/backend_linux.go
  2. 7 0
      plugin/store/store.go

+ 16 - 11
plugin/backend_linux.go

@@ -311,15 +311,29 @@ func (pm *Manager) Set(name string, args []string) error {
 // CreateFromContext creates a plugin from the given pluginDir which contains
 // CreateFromContext creates a plugin from the given pluginDir which contains
 // both the rootfs and the config.json and a repoName with optional tag.
 // both the rootfs and the config.json and a repoName with optional tag.
 func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.Reader, options *types.PluginCreateOptions) error {
 func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.Reader, options *types.PluginCreateOptions) error {
+	repoName := options.RepoName
+	ref, err := distribution.GetRef(repoName)
+	if err != nil {
+		return err
+	}
+
+	name := ref.Name()
+	tag := distribution.GetTag(ref)
 	pluginID := stringid.GenerateNonCryptoID()
 	pluginID := stringid.GenerateNonCryptoID()
 
 
+	p := v2.NewPlugin(name, pluginID, pm.runRoot, pm.libRoot, tag)
+
+	if v, _ := pm.pluginStore.GetByName(p.Name()); v != nil {
+		return fmt.Errorf("plugin %q already exists", p.Name())
+	}
+
 	pluginDir := filepath.Join(pm.libRoot, pluginID)
 	pluginDir := filepath.Join(pm.libRoot, pluginID)
 	if err := os.MkdirAll(pluginDir, 0755); err != nil {
 	if err := os.MkdirAll(pluginDir, 0755); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	// In case an error happens, remove the created directory.
 	// In case an error happens, remove the created directory.
-	if err := pm.createFromContext(ctx, pluginID, pluginDir, tarCtx, options); err != nil {
+	if err := pm.createFromContext(ctx, tarCtx, pluginDir, repoName, p); err != nil {
 		if err := os.RemoveAll(pluginDir); err != nil {
 		if err := os.RemoveAll(pluginDir); err != nil {
 			logrus.Warnf("unable to remove %q from failed plugin creation: %v", pluginDir, err)
 			logrus.Warnf("unable to remove %q from failed plugin creation: %v", pluginDir, err)
 		}
 		}
@@ -329,20 +343,11 @@ func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.Reader, opti
 	return nil
 	return nil
 }
 }
 
 
-func (pm *Manager) createFromContext(ctx context.Context, pluginID, pluginDir string, tarCtx io.Reader, options *types.PluginCreateOptions) error {
+func (pm *Manager) createFromContext(ctx context.Context, tarCtx io.Reader, pluginDir, repoName string, p *v2.Plugin) error {
 	if err := chrootarchive.Untar(tarCtx, pluginDir, nil); err != nil {
 	if err := chrootarchive.Untar(tarCtx, pluginDir, nil); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	repoName := options.RepoName
-	ref, err := distribution.GetRef(repoName)
-	if err != nil {
-		return err
-	}
-	name := ref.Name()
-	tag := distribution.GetTag(ref)
-
-	p := v2.NewPlugin(name, pluginID, pm.runRoot, pm.libRoot, tag)
 	if err := p.InitPlugin(); err != nil {
 	if err := p.InitPlugin(); err != nil {
 		return err
 		return err
 	}
 	}

+ 7 - 0
plugin/store/store.go

@@ -113,6 +113,13 @@ func (ps *Store) Add(p *v2.Plugin) error {
 	if v, exist := ps.plugins[p.GetID()]; exist {
 	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())
 		return fmt.Errorf("plugin %q has the same ID %s as %q", p.Name(), p.GetID(), v.Name())
 	}
 	}
+	// Since both Pull() and CreateFromContext() calls GetByName() before any plugin
+	// to search for collision (to fail fast), it is unlikely the following check
+	// will return an error.
+	// However, in case two CreateFromContext() are called at the same time,
+	// there is still a remote possibility that a collision might happen.
+	// For that reason we still perform the collision check below as it is protected
+	// by ps.Lock() and ps.Unlock() above.
 	if _, exist := ps.nameToID[p.Name()]; exist {
 	if _, exist := ps.nameToID[p.Name()]; exist {
 		return fmt.Errorf("plugin %q already exists", p.Name())
 		return fmt.Errorf("plugin %q already exists", p.Name())
 	}
 	}