2016-05-16 18:50:55 +03:00
|
|
|
// +build experimental
|
|
|
|
|
|
|
|
package plugin
|
|
|
|
|
|
|
|
import (
|
2016-08-11 02:48:17 +03:00
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2016-05-16 18:50:55 +03:00
|
|
|
"fmt"
|
2016-08-11 02:48:17 +03:00
|
|
|
"io/ioutil"
|
2016-05-16 18:50:55 +03:00
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"github.com/Sirupsen/logrus"
|
2016-09-06 21:18:12 +03:00
|
|
|
"github.com/docker/docker/api/types"
|
2016-05-16 18:50:55 +03:00
|
|
|
"github.com/docker/docker/pkg/archive"
|
|
|
|
"github.com/docker/docker/pkg/stringid"
|
|
|
|
"github.com/docker/docker/plugin/distribution"
|
2016-08-26 20:02:38 +03:00
|
|
|
"github.com/docker/docker/plugin/v2"
|
2016-05-16 18:50:55 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// Disable deactivates a plugin, which implies that they cannot be used by containers.
|
|
|
|
func (pm *Manager) Disable(name string) error {
|
2016-08-26 20:02:38 +03:00
|
|
|
p, err := pm.pluginStore.GetByName(name)
|
2016-05-16 18:50:55 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-07-18 18:02:12 +03:00
|
|
|
if err := pm.disable(p); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-08-26 20:02:38 +03:00
|
|
|
pm.pluginEventLogger(p.GetID(), name, "disable")
|
2016-07-18 18:02:12 +03:00
|
|
|
return nil
|
2016-05-16 18:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Enable activates a plugin, which implies that they are ready to be used by containers.
|
|
|
|
func (pm *Manager) Enable(name string) error {
|
2016-08-26 20:02:38 +03:00
|
|
|
p, err := pm.pluginStore.GetByName(name)
|
2016-05-16 18:50:55 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-08-09 21:49:28 +03:00
|
|
|
if err := pm.enable(p, false); err != nil {
|
2016-07-18 18:02:12 +03:00
|
|
|
return err
|
|
|
|
}
|
2016-08-26 20:02:38 +03:00
|
|
|
pm.pluginEventLogger(p.GetID(), name, "enable")
|
2016-07-18 18:02:12 +03:00
|
|
|
return nil
|
2016-05-16 18:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Inspect examines a plugin manifest
|
|
|
|
func (pm *Manager) Inspect(name string) (tp types.Plugin, err error) {
|
2016-08-26 20:02:38 +03:00
|
|
|
p, err := pm.pluginStore.GetByName(name)
|
2016-05-16 18:50:55 +03:00
|
|
|
if err != nil {
|
|
|
|
return tp, err
|
|
|
|
}
|
2016-07-18 18:02:12 +03:00
|
|
|
return p.PluginObj, nil
|
2016-05-16 18:50:55 +03:00
|
|
|
}
|
|
|
|
|
2016-07-18 18:02:12 +03:00
|
|
|
// Pull pulls a plugin and computes the privileges required to install it.
|
2016-05-16 18:50:55 +03:00
|
|
|
func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.AuthConfig) (types.PluginPrivileges, error) {
|
2016-09-08 03:01:10 +03:00
|
|
|
ref, err := distribution.GetRef(name)
|
2016-05-16 18:50:55 +03:00
|
|
|
if err != nil {
|
2016-09-08 03:01:10 +03:00
|
|
|
logrus.Debugf("error in distribution.GetRef: %v", err)
|
2016-05-16 18:50:55 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
name = ref.String()
|
|
|
|
|
2016-08-26 20:02:38 +03:00
|
|
|
if p, _ := pm.pluginStore.GetByName(name); p != nil {
|
2016-05-16 18:50:55 +03:00
|
|
|
logrus.Debugf("plugin already exists")
|
|
|
|
return nil, fmt.Errorf("%s exists", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
pluginID := stringid.GenerateNonCryptoID()
|
|
|
|
|
|
|
|
if err := os.MkdirAll(filepath.Join(pm.libRoot, pluginID), 0755); err != nil {
|
|
|
|
logrus.Debugf("error in MkdirAll: %v", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-09-08 03:01:10 +03:00
|
|
|
pd, err := distribution.Pull(ref, pm.registryService, metaHeader, authConfig)
|
2016-05-16 18:50:55 +03:00
|
|
|
if err != nil {
|
|
|
|
logrus.Debugf("error in distribution.Pull(): %v", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := distribution.WritePullData(pd, filepath.Join(pm.libRoot, pluginID), true); err != nil {
|
|
|
|
logrus.Debugf("error in distribution.WritePullData(): %v", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-09-08 03:01:10 +03:00
|
|
|
tag := distribution.GetTag(ref)
|
2016-08-26 20:02:38 +03:00
|
|
|
p := v2.NewPlugin(ref.Name(), pluginID, pm.runRoot, tag)
|
|
|
|
if err := p.InitPlugin(pm.libRoot); err != nil {
|
2016-05-16 18:50:55 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2016-08-26 20:02:38 +03:00
|
|
|
pm.pluginStore.Add(p)
|
2016-05-16 18:50:55 +03:00
|
|
|
|
2016-07-18 18:02:12 +03:00
|
|
|
pm.pluginEventLogger(pluginID, name, "pull")
|
2016-08-26 20:02:38 +03:00
|
|
|
return p.ComputePrivileges(), nil
|
2016-05-16 18:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// List displays the list of plugins and associated metadata.
|
|
|
|
func (pm *Manager) List() ([]types.Plugin, error) {
|
2016-08-26 20:02:38 +03:00
|
|
|
plugins := pm.pluginStore.GetAll()
|
|
|
|
out := make([]types.Plugin, 0, len(plugins))
|
|
|
|
for _, p := range plugins {
|
2016-07-18 18:02:12 +03:00
|
|
|
out = append(out, p.PluginObj)
|
2016-05-16 18:50:55 +03:00
|
|
|
}
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Push pushes a plugin to the store.
|
|
|
|
func (pm *Manager) Push(name string, metaHeader http.Header, authConfig *types.AuthConfig) error {
|
2016-08-26 20:02:38 +03:00
|
|
|
p, err := pm.pluginStore.GetByName(name)
|
2016-06-27 18:41:53 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-08-26 20:02:38 +03:00
|
|
|
dest := filepath.Join(pm.libRoot, p.GetID())
|
2016-08-11 02:48:17 +03:00
|
|
|
config, err := ioutil.ReadFile(filepath.Join(dest, "manifest.json"))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var dummy types.Plugin
|
|
|
|
err = json.Unmarshal(config, &dummy)
|
2016-05-16 18:50:55 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-06-27 18:41:53 +03:00
|
|
|
|
2016-05-16 18:50:55 +03:00
|
|
|
rootfs, err := archive.Tar(filepath.Join(dest, "rootfs"), archive.Gzip)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-06-25 06:57:21 +03:00
|
|
|
defer rootfs.Close()
|
|
|
|
|
2016-08-11 02:48:17 +03:00
|
|
|
_, err = distribution.Push(name, pm.registryService, metaHeader, authConfig, ioutil.NopCloser(bytes.NewReader(config)), rootfs)
|
2016-05-16 18:50:55 +03:00
|
|
|
// XXX: Ignore returning digest for now.
|
|
|
|
// Since digest needs to be written to the ProgressWriter.
|
2016-06-22 20:40:32 +03:00
|
|
|
return err
|
2016-05-16 18:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove deletes plugin's root directory.
|
2016-07-22 18:24:54 +03:00
|
|
|
func (pm *Manager) Remove(name string, config *types.PluginRmConfig) error {
|
2016-08-26 20:02:38 +03:00
|
|
|
p, err := pm.pluginStore.GetByName(name)
|
2016-05-16 18:50:55 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-09-07 16:59:15 +03:00
|
|
|
|
|
|
|
if !config.ForceRemove {
|
|
|
|
p.RLock()
|
|
|
|
if p.RefCount > 0 {
|
|
|
|
p.RUnlock()
|
|
|
|
return fmt.Errorf("plugin %s is in use", p.Name())
|
|
|
|
}
|
|
|
|
p.RUnlock()
|
|
|
|
|
|
|
|
if p.IsEnabled() {
|
2016-08-26 20:02:38 +03:00
|
|
|
return fmt.Errorf("plugin %s is enabled", p.Name())
|
|
|
|
}
|
2016-09-07 16:59:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if p.IsEnabled() {
|
2016-08-26 20:02:38 +03:00
|
|
|
if err := pm.disable(p); err != nil {
|
|
|
|
logrus.Errorf("failed to disable plugin '%s': %s", p.Name(), err)
|
|
|
|
}
|
2016-07-18 18:02:12 +03:00
|
|
|
}
|
2016-09-07 16:59:15 +03:00
|
|
|
|
2016-08-26 20:02:38 +03:00
|
|
|
pm.pluginStore.Remove(p)
|
|
|
|
pm.pluginEventLogger(p.GetID(), name, "remove")
|
2016-07-18 18:02:12 +03:00
|
|
|
return nil
|
2016-05-16 18:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set sets plugin args
|
|
|
|
func (pm *Manager) Set(name string, args []string) error {
|
2016-08-26 20:02:38 +03:00
|
|
|
p, err := pm.pluginStore.GetByName(name)
|
2016-05-16 18:50:55 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-08-26 20:02:38 +03:00
|
|
|
return p.Set(args)
|
2016-05-16 18:50:55 +03:00
|
|
|
}
|