|
@@ -5,12 +5,14 @@ package plugin
|
|
|
import (
|
|
|
"bytes"
|
|
|
"encoding/json"
|
|
|
+ "errors"
|
|
|
"fmt"
|
|
|
"io"
|
|
|
"io/ioutil"
|
|
|
"net/http"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
|
+ "reflect"
|
|
|
"regexp"
|
|
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
@@ -87,59 +89,139 @@ func (pm *Manager) Inspect(refOrID string) (tp types.Plugin, err error) {
|
|
|
return tp, fmt.Errorf("no plugin name or ID associated with %q", refOrID)
|
|
|
}
|
|
|
|
|
|
-func (pm *Manager) pull(ref reference.Named, metaHeader http.Header, authConfig *types.AuthConfig, pluginID string) (types.PluginPrivileges, error) {
|
|
|
+func (pm *Manager) pull(name string, metaHeader http.Header, authConfig *types.AuthConfig) (reference.Named, distribution.PullData, error) {
|
|
|
+ ref, err := distribution.GetRef(name)
|
|
|
+ if err != nil {
|
|
|
+ logrus.Debugf("error in distribution.GetRef: %v", err)
|
|
|
+ return nil, nil, err
|
|
|
+ }
|
|
|
+ name = ref.String()
|
|
|
+
|
|
|
+ if p, _ := pm.pluginStore.GetByName(name); p != nil {
|
|
|
+ logrus.Debug("plugin already exists")
|
|
|
+ return nil, nil, fmt.Errorf("%s exists", name)
|
|
|
+ }
|
|
|
+
|
|
|
pd, err := distribution.Pull(ref, pm.registryService, metaHeader, authConfig)
|
|
|
if err != nil {
|
|
|
logrus.Debugf("error in distribution.Pull(): %v", err)
|
|
|
- return nil, err
|
|
|
+ return nil, nil, err
|
|
|
}
|
|
|
+ return ref, pd, nil
|
|
|
+}
|
|
|
|
|
|
- if err := distribution.WritePullData(pd, filepath.Join(pm.libRoot, pluginID), true); err != nil {
|
|
|
- logrus.Debugf("error in distribution.WritePullData(): %v", err)
|
|
|
+func computePrivileges(pd distribution.PullData) (types.PluginPrivileges, error) {
|
|
|
+ config, err := pd.Config()
|
|
|
+ if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- tag := distribution.GetTag(ref)
|
|
|
- p := v2.NewPlugin(ref.Name(), pluginID, pm.runRoot, pm.libRoot, tag)
|
|
|
- if err := p.InitPlugin(); err != nil {
|
|
|
+ var c types.PluginConfig
|
|
|
+ if err := json.Unmarshal(config, &c); err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- pm.pluginStore.Add(p)
|
|
|
|
|
|
- pm.pluginEventLogger(pluginID, ref.String(), "pull")
|
|
|
- return p.ComputePrivileges(), nil
|
|
|
+ var privileges types.PluginPrivileges
|
|
|
+ if c.Network.Type != "null" && c.Network.Type != "bridge" {
|
|
|
+ privileges = append(privileges, types.PluginPrivilege{
|
|
|
+ Name: "network",
|
|
|
+ Description: "permissions to access a network",
|
|
|
+ Value: []string{c.Network.Type},
|
|
|
+ })
|
|
|
+ }
|
|
|
+ for _, mount := range c.Mounts {
|
|
|
+ if mount.Source != nil {
|
|
|
+ privileges = append(privileges, types.PluginPrivilege{
|
|
|
+ Name: "mount",
|
|
|
+ Description: "host path to mount",
|
|
|
+ Value: []string{*mount.Source},
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, device := range c.Linux.Devices {
|
|
|
+ if device.Path != nil {
|
|
|
+ privileges = append(privileges, types.PluginPrivilege{
|
|
|
+ Name: "device",
|
|
|
+ Description: "host device to access",
|
|
|
+ Value: []string{*device.Path},
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if c.Linux.DeviceCreation {
|
|
|
+ privileges = append(privileges, types.PluginPrivilege{
|
|
|
+ Name: "device-creation",
|
|
|
+ Description: "allow creating devices inside plugin",
|
|
|
+ Value: []string{"true"},
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if len(c.Linux.Capabilities) > 0 {
|
|
|
+ privileges = append(privileges, types.PluginPrivilege{
|
|
|
+ Name: "capabilities",
|
|
|
+ Description: "list of additional capabilities required",
|
|
|
+ Value: c.Linux.Capabilities,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return privileges, nil
|
|
|
}
|
|
|
|
|
|
-// Pull pulls a plugin and computes the privileges required to install it.
|
|
|
-func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.AuthConfig) (types.PluginPrivileges, error) {
|
|
|
- ref, err := distribution.GetRef(name)
|
|
|
+// Privileges pulls a plugin config and computes the privileges required to install it.
|
|
|
+func (pm *Manager) Privileges(name string, metaHeader http.Header, authConfig *types.AuthConfig) (types.PluginPrivileges, error) {
|
|
|
+ _, pd, err := pm.pull(name, metaHeader, authConfig)
|
|
|
if err != nil {
|
|
|
- logrus.Debugf("error in distribution.GetRef: %v", err)
|
|
|
return nil, err
|
|
|
}
|
|
|
- name = ref.String()
|
|
|
+ return computePrivileges(pd)
|
|
|
+}
|
|
|
|
|
|
- if p, _ := pm.pluginStore.GetByName(name); p != nil {
|
|
|
- logrus.Debug("plugin already exists")
|
|
|
- return nil, fmt.Errorf("%s exists", name)
|
|
|
+// Pull pulls a plugin, check if the correct privileges are provided and install the plugin.
|
|
|
+func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.AuthConfig, privileges types.PluginPrivileges) (err error) {
|
|
|
+ ref, pd, err := pm.pull(name, metaHeader, authConfig)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ requiredPrivileges, err := computePrivileges(pd)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if !reflect.DeepEqual(privileges, requiredPrivileges) {
|
|
|
+ return errors.New("incorrect privileges")
|
|
|
}
|
|
|
|
|
|
pluginID := stringid.GenerateNonCryptoID()
|
|
|
pluginDir := filepath.Join(pm.libRoot, pluginID)
|
|
|
if err := os.MkdirAll(pluginDir, 0755); err != nil {
|
|
|
logrus.Debugf("error in MkdirAll: %v", err)
|
|
|
- return nil, err
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
- priv, err := pm.pull(ref, metaHeader, authConfig, pluginID)
|
|
|
- if err != nil {
|
|
|
- if err := os.RemoveAll(pluginDir); err != nil {
|
|
|
- logrus.Warnf("unable to remove %q from failed plugin pull: %v", pluginDir, err)
|
|
|
+ defer func() {
|
|
|
+ if err != nil {
|
|
|
+ if delErr := os.RemoveAll(pluginDir); delErr != nil {
|
|
|
+ logrus.Warnf("unable to remove %q from failed plugin pull: %v", pluginDir, delErr)
|
|
|
+ }
|
|
|
}
|
|
|
- return nil, err
|
|
|
+ }()
|
|
|
+
|
|
|
+ err = distribution.WritePullData(pd, filepath.Join(pm.libRoot, pluginID), true)
|
|
|
+ if err != nil {
|
|
|
+ logrus.Debugf("error in distribution.WritePullData(): %v", err)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ tag := distribution.GetTag(ref)
|
|
|
+ p := v2.NewPlugin(ref.Name(), pluginID, pm.runRoot, pm.libRoot, tag)
|
|
|
+ err = p.InitPlugin()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
}
|
|
|
+ pm.pluginStore.Add(p)
|
|
|
|
|
|
- return priv, nil
|
|
|
+ pm.pluginEventLogger(pluginID, ref.String(), "pull")
|
|
|
+
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
// List displays the list of plugins and associated metadata.
|