mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Use GetByName to check for collision before create any context in plugin creation
This fix is a follow up to the comment: https://github.com/docker/docker/pull/28717#discussion_r90040589 Currently, the collision checking is done at the last step `Add()` of plugin creation. However, at this stage the context such as plugin directories have already been creation. In case of name collision, rollback is needed which could be expensive. This fix performs the check at the beginning of CreateFromContext using GetByName. In this way, collision fails fast and no context creation or rollback is needed. Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
parent
f244174664
commit
52405a9b58
2 changed files with 23 additions and 11 deletions
|
@ -200,15 +200,29 @@ func (pm *Manager) Set(name string, args []string) error {
|
|||
// CreateFromContext creates a plugin from the given pluginDir which contains
|
||||
// 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 {
|
||||
repoName := options.RepoName
|
||||
ref, err := distribution.GetRef(repoName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := ref.Name()
|
||||
tag := distribution.GetTag(ref)
|
||||
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)
|
||||
if err := os.MkdirAll(pluginDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
logrus.Warnf("unable to remove %q from failed plugin creation: %v", pluginDir, err)
|
||||
}
|
||||
|
@ -218,20 +232,11 @@ func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.Reader, opti
|
|||
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 {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -106,6 +106,13 @@ func (ps *Store) Add(p *v2.Plugin) error {
|
|||
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())
|
||||
}
|
||||
// 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 {
|
||||
return fmt.Errorf("plugin %q already exists", p.Name())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue