mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #28601 from tiborvass/plugin-misc-fixes
Plugin miscellaneous fixes
This commit is contained in:
commit
23ea9e45fd
18 changed files with 348 additions and 203 deletions
|
@ -1329,9 +1329,8 @@ definitions:
|
||||||
- Entrypoint
|
- Entrypoint
|
||||||
- Workdir
|
- Workdir
|
||||||
- Network
|
- Network
|
||||||
- Capabilities
|
- Linux
|
||||||
- Mounts
|
- Mounts
|
||||||
- Devices
|
|
||||||
- Env
|
- Env
|
||||||
- Args
|
- Args
|
||||||
properties:
|
properties:
|
||||||
|
@ -1379,18 +1378,26 @@ definitions:
|
||||||
Type:
|
Type:
|
||||||
x-nullable: false
|
x-nullable: false
|
||||||
type: "string"
|
type: "string"
|
||||||
Capabilities:
|
Linux:
|
||||||
type: "array"
|
type: "object"
|
||||||
items:
|
x-nullable: false
|
||||||
type: "string"
|
required: [Capabilities, DeviceCreation, Devices]
|
||||||
|
properties:
|
||||||
|
Capabilities:
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
DeviceCreation:
|
||||||
|
type: "boolean"
|
||||||
|
x-nullable: false
|
||||||
|
Devices:
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/PluginDevice"
|
||||||
Mounts:
|
Mounts:
|
||||||
type: "array"
|
type: "array"
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/PluginMount"
|
$ref: "#/definitions/PluginMount"
|
||||||
Devices:
|
|
||||||
type: "array"
|
|
||||||
items:
|
|
||||||
$ref: "#/definitions/PluginDevice"
|
|
||||||
Env:
|
Env:
|
||||||
type: "array"
|
type: "array"
|
||||||
items:
|
items:
|
||||||
|
|
|
@ -39,18 +39,10 @@ type PluginConfig struct {
|
||||||
// Required: true
|
// Required: true
|
||||||
Args PluginConfigArgs `json:"Args"`
|
Args PluginConfigArgs `json:"Args"`
|
||||||
|
|
||||||
// capabilities
|
|
||||||
// Required: true
|
|
||||||
Capabilities []string `json:"Capabilities"`
|
|
||||||
|
|
||||||
// description
|
// description
|
||||||
// Required: true
|
// Required: true
|
||||||
Description string `json:"Description"`
|
Description string `json:"Description"`
|
||||||
|
|
||||||
// devices
|
|
||||||
// Required: true
|
|
||||||
Devices []PluginDevice `json:"Devices"`
|
|
||||||
|
|
||||||
// documentation
|
// documentation
|
||||||
// Required: true
|
// Required: true
|
||||||
Documentation string `json:"Documentation"`
|
Documentation string `json:"Documentation"`
|
||||||
|
@ -67,6 +59,10 @@ type PluginConfig struct {
|
||||||
// Required: true
|
// Required: true
|
||||||
Interface PluginConfigInterface `json:"Interface"`
|
Interface PluginConfigInterface `json:"Interface"`
|
||||||
|
|
||||||
|
// linux
|
||||||
|
// Required: true
|
||||||
|
Linux PluginConfigLinux `json:"Linux"`
|
||||||
|
|
||||||
// mounts
|
// mounts
|
||||||
// Required: true
|
// Required: true
|
||||||
Mounts []PluginMount `json:"Mounts"`
|
Mounts []PluginMount `json:"Mounts"`
|
||||||
|
@ -117,6 +113,23 @@ type PluginConfigInterface struct {
|
||||||
Types []PluginInterfaceType `json:"Types"`
|
Types []PluginInterfaceType `json:"Types"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PluginConfigLinux plugin config linux
|
||||||
|
// swagger:model PluginConfigLinux
|
||||||
|
type PluginConfigLinux struct {
|
||||||
|
|
||||||
|
// capabilities
|
||||||
|
// Required: true
|
||||||
|
Capabilities []string `json:"Capabilities"`
|
||||||
|
|
||||||
|
// device creation
|
||||||
|
// Required: true
|
||||||
|
DeviceCreation bool `json:"DeviceCreation"`
|
||||||
|
|
||||||
|
// devices
|
||||||
|
// Required: true
|
||||||
|
Devices []PluginDevice `json:"Devices"`
|
||||||
|
}
|
||||||
|
|
||||||
// PluginConfigNetwork plugin config network
|
// PluginConfigNetwork plugin config network
|
||||||
// swagger:model PluginConfigNetwork
|
// swagger:model PluginConfigNetwork
|
||||||
type PluginConfigNetwork struct {
|
type PluginConfigNetwork struct {
|
||||||
|
|
|
@ -8,13 +8,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/cloudflare/cfssl/log"
|
"github.com/cloudflare/cfssl/log"
|
||||||
containertypes "github.com/docker/docker/api/types/container"
|
|
||||||
"github.com/docker/docker/container"
|
"github.com/docker/docker/container"
|
||||||
"github.com/docker/docker/daemon/links"
|
"github.com/docker/docker/daemon/links"
|
||||||
"github.com/docker/docker/pkg/idtools"
|
"github.com/docker/docker/pkg/idtools"
|
||||||
|
@ -22,16 +20,10 @@ import (
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/libnetwork"
|
"github.com/docker/libnetwork"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/devices"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/label"
|
"github.com/opencontainers/runc/libcontainer/label"
|
||||||
"github.com/opencontainers/runtime-spec/specs-go"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func u32Ptr(i int64) *uint32 { u := uint32(i); return &u }
|
|
||||||
func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm }
|
|
||||||
|
|
||||||
func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
|
func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
|
||||||
var env []string
|
var env []string
|
||||||
children := daemon.children(container)
|
children := daemon.children(container)
|
||||||
|
@ -247,78 +239,6 @@ func killProcessDirectly(container *container.Container) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func specDevice(d *configs.Device) specs.Device {
|
|
||||||
return specs.Device{
|
|
||||||
Type: string(d.Type),
|
|
||||||
Path: d.Path,
|
|
||||||
Major: d.Major,
|
|
||||||
Minor: d.Minor,
|
|
||||||
FileMode: fmPtr(int64(d.FileMode)),
|
|
||||||
UID: u32Ptr(int64(d.Uid)),
|
|
||||||
GID: u32Ptr(int64(d.Gid)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func specDeviceCgroup(d *configs.Device) specs.DeviceCgroup {
|
|
||||||
t := string(d.Type)
|
|
||||||
return specs.DeviceCgroup{
|
|
||||||
Allow: true,
|
|
||||||
Type: &t,
|
|
||||||
Major: &d.Major,
|
|
||||||
Minor: &d.Minor,
|
|
||||||
Access: &d.Permissions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []specs.Device, devPermissions []specs.DeviceCgroup, err error) {
|
|
||||||
resolvedPathOnHost := deviceMapping.PathOnHost
|
|
||||||
|
|
||||||
// check if it is a symbolic link
|
|
||||||
if src, e := os.Lstat(deviceMapping.PathOnHost); e == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink {
|
|
||||||
if linkedPathOnHost, e := filepath.EvalSymlinks(deviceMapping.PathOnHost); e == nil {
|
|
||||||
resolvedPathOnHost = linkedPathOnHost
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
device, err := devices.DeviceFromPath(resolvedPathOnHost, deviceMapping.CgroupPermissions)
|
|
||||||
// if there was no error, return the device
|
|
||||||
if err == nil {
|
|
||||||
device.Path = deviceMapping.PathInContainer
|
|
||||||
return append(devs, specDevice(device)), append(devPermissions, specDeviceCgroup(device)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the device is not a device node
|
|
||||||
// try to see if it's a directory holding many devices
|
|
||||||
if err == devices.ErrNotADevice {
|
|
||||||
|
|
||||||
// check if it is a directory
|
|
||||||
if src, e := os.Stat(resolvedPathOnHost); e == nil && src.IsDir() {
|
|
||||||
|
|
||||||
// mount the internal devices recursively
|
|
||||||
filepath.Walk(resolvedPathOnHost, func(dpath string, f os.FileInfo, e error) error {
|
|
||||||
childDevice, e := devices.DeviceFromPath(dpath, deviceMapping.CgroupPermissions)
|
|
||||||
if e != nil {
|
|
||||||
// ignore the device
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the device to userSpecified devices
|
|
||||||
childDevice.Path = strings.Replace(dpath, resolvedPathOnHost, deviceMapping.PathInContainer, 1)
|
|
||||||
devs = append(devs, specDevice(childDevice))
|
|
||||||
devPermissions = append(devPermissions, specDeviceCgroup(childDevice))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(devs) > 0 {
|
|
||||||
return devs, devPermissions, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return devs, devPermissions, fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func detachMounted(path string) error {
|
func detachMounted(path string) error {
|
||||||
return syscall.Unmount(path, syscall.MNT_DETACH)
|
return syscall.Unmount(path, syscall.MNT_DETACH)
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ func setDevices(s *specs.Spec, c *container.Container) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, d := range hostDevices {
|
for _, d := range hostDevices {
|
||||||
devs = append(devs, specDevice(d))
|
devs = append(devs, oci.Device(d))
|
||||||
}
|
}
|
||||||
rwm := "rwm"
|
rwm := "rwm"
|
||||||
devPermissions = []specs.DeviceCgroup{
|
devPermissions = []specs.DeviceCgroup{
|
||||||
|
@ -99,7 +99,7 @@ func setDevices(s *specs.Spec, c *container.Container) error {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, deviceMapping := range c.HostConfig.Devices {
|
for _, deviceMapping := range c.HostConfig.Devices {
|
||||||
d, dPermissions, err := getDevicesFromPath(deviceMapping)
|
d, dPermissions, err := oci.DevicesFromPath(deviceMapping.PathOnHost, deviceMapping.PathInContainer, deviceMapping.CgroupPermissions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -221,18 +221,6 @@ func setCapabilities(s *specs.Spec, c *container.Container) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func delNamespace(s *specs.Spec, nsType specs.NamespaceType) {
|
|
||||||
idx := -1
|
|
||||||
for i, n := range s.Linux.Namespaces {
|
|
||||||
if n.Type == nsType {
|
|
||||||
idx = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if idx >= 0 {
|
|
||||||
s.Linux.Namespaces = append(s.Linux.Namespaces[:idx], s.Linux.Namespaces[idx+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error {
|
func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error {
|
||||||
userNS := false
|
userNS := false
|
||||||
// user
|
// user
|
||||||
|
@ -283,7 +271,7 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
|
||||||
setNamespace(s, nsUser)
|
setNamespace(s, nsUser)
|
||||||
}
|
}
|
||||||
} else if c.HostConfig.IpcMode.IsHost() {
|
} else if c.HostConfig.IpcMode.IsHost() {
|
||||||
delNamespace(s, specs.NamespaceType("ipc"))
|
oci.RemoveNamespace(s, specs.NamespaceType("ipc"))
|
||||||
} else {
|
} else {
|
||||||
ns := specs.Namespace{Type: "ipc"}
|
ns := specs.Namespace{Type: "ipc"}
|
||||||
setNamespace(s, ns)
|
setNamespace(s, ns)
|
||||||
|
@ -304,14 +292,14 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
|
||||||
setNamespace(s, nsUser)
|
setNamespace(s, nsUser)
|
||||||
}
|
}
|
||||||
} else if c.HostConfig.PidMode.IsHost() {
|
} else if c.HostConfig.PidMode.IsHost() {
|
||||||
delNamespace(s, specs.NamespaceType("pid"))
|
oci.RemoveNamespace(s, specs.NamespaceType("pid"))
|
||||||
} else {
|
} else {
|
||||||
ns := specs.Namespace{Type: "pid"}
|
ns := specs.Namespace{Type: "pid"}
|
||||||
setNamespace(s, ns)
|
setNamespace(s, ns)
|
||||||
}
|
}
|
||||||
// uts
|
// uts
|
||||||
if c.HostConfig.UTSMode.IsHost() {
|
if c.HostConfig.UTSMode.IsHost() {
|
||||||
delNamespace(s, specs.NamespaceType("uts"))
|
oci.RemoveNamespace(s, specs.NamespaceType("uts"))
|
||||||
s.Hostname = ""
|
s.Hostname = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ keywords: "API, Usage, plugins, documentation, developer"
|
||||||
will be rejected.
|
will be rejected.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
# Plugin Config Version 0 of Plugin V2
|
# Plugin Config Version 0 of Plugin V2
|
||||||
|
|
||||||
This document outlines the format of the V0 plugin configuration. The plugin
|
This document outlines the format of the V0 plugin configuration. The plugin
|
||||||
|
@ -85,10 +86,6 @@ Config provides the base accessible fields for working with V0 plugin format
|
||||||
- **host**
|
- **host**
|
||||||
- **none**
|
- **none**
|
||||||
|
|
||||||
- **`capabilities`** *array*
|
|
||||||
|
|
||||||
capabilities of the plugin (*Linux only*), see list [`here`](https://github.com/opencontainers/runc/blob/master/libcontainer/SPEC.md#security)
|
|
||||||
|
|
||||||
- **`mounts`** *PluginMount array*
|
- **`mounts`** *PluginMount array*
|
||||||
|
|
||||||
mount of the plugin, struct consisting of the following fields, see [`MOUNTS`](https://github.com/opencontainers/runtime-spec/blob/master/config.md#mounts)
|
mount of the plugin, struct consisting of the following fields, see [`MOUNTS`](https://github.com/opencontainers/runtime-spec/blob/master/config.md#mounts)
|
||||||
|
@ -117,22 +114,6 @@ Config provides the base accessible fields for working with V0 plugin format
|
||||||
|
|
||||||
options of the mount.
|
options of the mount.
|
||||||
|
|
||||||
- **`devices`** *PluginDevice array*
|
|
||||||
|
|
||||||
device of the plugin, (*Linux only*), struct consisting of the following fields, see [`DEVICES`](https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#devices)
|
|
||||||
|
|
||||||
- **`name`** *string*
|
|
||||||
|
|
||||||
name of the device.
|
|
||||||
|
|
||||||
- **`description`** *string*
|
|
||||||
|
|
||||||
description of the device.
|
|
||||||
|
|
||||||
- **`path`** *string*
|
|
||||||
|
|
||||||
path of the device.
|
|
||||||
|
|
||||||
- **`env`** *PluginEnv array*
|
- **`env`** *PluginEnv array*
|
||||||
|
|
||||||
env of the plugin, struct consisting of the following fields
|
env of the plugin, struct consisting of the following fields
|
||||||
|
@ -165,6 +146,27 @@ Config provides the base accessible fields for working with V0 plugin format
|
||||||
|
|
||||||
values of the args.
|
values of the args.
|
||||||
|
|
||||||
|
- **`linux`** *PluginLinux*
|
||||||
|
|
||||||
|
- **`capabilities`** *string array*
|
||||||
|
|
||||||
|
capabilities of the plugin (*Linux only*), see list [`here`](https://github.com/opencontainers/runc/blob/master/libcontainer/SPEC.md#security)
|
||||||
|
|
||||||
|
- **`devices`** *PluginDevice array*
|
||||||
|
|
||||||
|
device of the plugin, (*Linux only*), struct consisting of the following fields, see [`DEVICES`](https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#devices)
|
||||||
|
|
||||||
|
- **`name`** *string*
|
||||||
|
|
||||||
|
name of the device.
|
||||||
|
|
||||||
|
- **`description`** *string*
|
||||||
|
|
||||||
|
description of the device.
|
||||||
|
|
||||||
|
- **`path`** *string*
|
||||||
|
|
||||||
|
path of the device.
|
||||||
|
|
||||||
## Example Config
|
## Example Config
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,6 @@ import (
|
||||||
"github.com/go-check/check"
|
"github.com/go-check/check"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pluginName = "tiborvass/no-remove"
|
|
||||||
|
|
||||||
// TestDaemonRestartWithPluginEnabled tests state restore for an enabled plugin
|
// TestDaemonRestartWithPluginEnabled tests state restore for an enabled plugin
|
||||||
func (s *DockerDaemonSuite) TestDaemonRestartWithPluginEnabled(c *check.C) {
|
func (s *DockerDaemonSuite) TestDaemonRestartWithPluginEnabled(c *check.C) {
|
||||||
testRequires(c, Network)
|
testRequires(c, Network)
|
||||||
|
@ -23,15 +21,15 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithPluginEnabled(c *check.C) {
|
||||||
c.Fatalf("Could not start daemon: %v", err)
|
c.Fatalf("Could not start daemon: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
|
||||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -44,7 +42,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithPluginEnabled(c *check.C) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Fatalf("Could not list plugins: %v %s", err, out)
|
c.Fatalf("Could not list plugins: %v %s", err, out)
|
||||||
}
|
}
|
||||||
c.Assert(out, checker.Contains, pluginName)
|
c.Assert(out, checker.Contains, pName)
|
||||||
c.Assert(out, checker.Contains, "true")
|
c.Assert(out, checker.Contains, "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,12 +54,12 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithPluginDisabled(c *check.C) {
|
||||||
c.Fatalf("Could not start daemon: %v", err)
|
c.Fatalf("Could not start daemon: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName, "--disable"); err != nil {
|
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName, "--disable"); err != nil {
|
||||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -74,7 +72,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithPluginDisabled(c *check.C) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Fatalf("Could not list plugins: %v %s", err, out)
|
c.Fatalf("Could not list plugins: %v %s", err, out)
|
||||||
}
|
}
|
||||||
c.Assert(out, checker.Contains, pluginName)
|
c.Assert(out, checker.Contains, pName)
|
||||||
c.Assert(out, checker.Contains, "false")
|
c.Assert(out, checker.Contains, "false")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,17 +84,17 @@ func (s *DockerDaemonSuite) TestDaemonKillLiveRestoreWithPlugins(c *check.C) {
|
||||||
if err := s.d.Start("--live-restore"); err != nil {
|
if err := s.d.Start("--live-restore"); err != nil {
|
||||||
c.Fatalf("Could not start daemon: %v", err)
|
c.Fatalf("Could not start daemon: %v", err)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
|
||||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := s.d.Restart("--live-restore"); err != nil {
|
if err := s.d.Restart("--live-restore"); err != nil {
|
||||||
c.Fatalf("Could not restart daemon: %v", err)
|
c.Fatalf("Could not restart daemon: %v", err)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -105,7 +103,7 @@ func (s *DockerDaemonSuite) TestDaemonKillLiveRestoreWithPlugins(c *check.C) {
|
||||||
c.Fatalf("Could not kill daemon: %v", err)
|
c.Fatalf("Could not kill daemon: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
|
cmd := exec.Command("pgrep", "-f", pluginProcessName)
|
||||||
if out, ec, err := runCommandWithOutput(cmd); ec != 0 {
|
if out, ec, err := runCommandWithOutput(cmd); ec != 0 {
|
||||||
c.Fatalf("Expected exit code '0', got %d err: %v output: %s ", ec, err, out)
|
c.Fatalf("Expected exit code '0', got %d err: %v output: %s ", ec, err, out)
|
||||||
}
|
}
|
||||||
|
@ -119,17 +117,17 @@ func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C)
|
||||||
if err := s.d.Start("--live-restore"); err != nil {
|
if err := s.d.Start("--live-restore"); err != nil {
|
||||||
c.Fatalf("Could not start daemon: %v", err)
|
c.Fatalf("Could not start daemon: %v", err)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
|
||||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := s.d.Restart("--live-restore"); err != nil {
|
if err := s.d.Restart("--live-restore"); err != nil {
|
||||||
c.Fatalf("Could not restart daemon: %v", err)
|
c.Fatalf("Could not restart daemon: %v", err)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -138,7 +136,7 @@ func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C)
|
||||||
c.Fatalf("Could not kill daemon: %v", err)
|
c.Fatalf("Could not kill daemon: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
|
cmd := exec.Command("pgrep", "-f", pluginProcessName)
|
||||||
if out, ec, err := runCommandWithOutput(cmd); ec != 0 {
|
if out, ec, err := runCommandWithOutput(cmd); ec != 0 {
|
||||||
c.Fatalf("Expected exit code '0', got %d err: %v output: %s ", ec, err, out)
|
c.Fatalf("Expected exit code '0', got %d err: %v output: %s ", ec, err, out)
|
||||||
}
|
}
|
||||||
|
@ -151,7 +149,7 @@ func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
|
||||||
if err := s.d.Start(); err != nil {
|
if err := s.d.Start(); err != nil {
|
||||||
c.Fatalf("Could not start daemon: %v", err)
|
c.Fatalf("Could not start daemon: %v", err)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
|
||||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,10 +157,10 @@ func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
|
||||||
if err := s.d.Restart(); err != nil {
|
if err := s.d.Restart(); err != nil {
|
||||||
c.Fatalf("Could not restart daemon: %v", err)
|
c.Fatalf("Could not restart daemon: %v", err)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -177,7 +175,7 @@ func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
|
cmd := exec.Command("pgrep", "-f", pluginProcessName)
|
||||||
if out, ec, err := runCommandWithOutput(cmd); ec != 1 {
|
if out, ec, err := runCommandWithOutput(cmd); ec != 1 {
|
||||||
c.Fatalf("Expected exit code '1', got %d err: %v output: %s ", ec, err, out)
|
c.Fatalf("Expected exit code '1', got %d err: %v output: %s ", ec, err, out)
|
||||||
}
|
}
|
||||||
|
@ -195,20 +193,20 @@ func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) {
|
||||||
if err := s.d.Start(); err != nil {
|
if err := s.d.Start(); err != nil {
|
||||||
c.Fatalf("Could not start daemon: %v", err)
|
c.Fatalf("Could not start daemon: %v", err)
|
||||||
}
|
}
|
||||||
out, err := s.d.Cmd("plugin", "install", pluginName, "--grant-all-permissions")
|
out, err := s.d.Cmd("plugin", "install", pName, "--grant-all-permissions")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
|
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
out, err = s.d.Cmd("volume", "create", "-d", pluginName, volName)
|
out, err = s.d.Cmd("volume", "create", "-d", pName, volName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Fatalf("Could not create volume: %v %s", err, out)
|
c.Fatalf("Could not create volume: %v %s", err, out)
|
||||||
}
|
}
|
||||||
|
@ -223,7 +221,7 @@ func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) {
|
||||||
c.Fatalf("Could not list volume: %v %s", err, out)
|
c.Fatalf("Could not list volume: %v %s", err, out)
|
||||||
}
|
}
|
||||||
c.Assert(out, checker.Contains, volName)
|
c.Assert(out, checker.Contains, volName)
|
||||||
c.Assert(out, checker.Contains, pluginName)
|
c.Assert(out, checker.Contains, pName)
|
||||||
|
|
||||||
mountPoint, err := s.d.Cmd("volume", "inspect", volName, "--format", "{{.Mountpoint}}")
|
mountPoint, err := s.d.Cmd("volume", "inspect", volName, "--format", "{{.Mountpoint}}")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -278,12 +278,11 @@ func (s *DockerSuite) TestEventsImageLoad(c *check.C) {
|
||||||
func (s *DockerSuite) TestEventsPluginOps(c *check.C) {
|
func (s *DockerSuite) TestEventsPluginOps(c *check.C) {
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
|
|
||||||
pluginName := "tiborvass/no-remove:latest"
|
|
||||||
since := daemonUnixTime(c)
|
since := daemonUnixTime(c)
|
||||||
|
|
||||||
dockerCmd(c, "plugin", "install", pluginName, "--grant-all-permissions")
|
dockerCmd(c, "plugin", "install", pNameWithTag, "--grant-all-permissions")
|
||||||
dockerCmd(c, "plugin", "disable", pluginName)
|
dockerCmd(c, "plugin", "disable", pNameWithTag)
|
||||||
dockerCmd(c, "plugin", "remove", pluginName)
|
dockerCmd(c, "plugin", "remove", pNameWithTag)
|
||||||
|
|
||||||
out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c))
|
out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c))
|
||||||
events := strings.Split(out, "\n")
|
events := strings.Split(out, "\n")
|
||||||
|
@ -292,7 +291,7 @@ func (s *DockerSuite) TestEventsPluginOps(c *check.C) {
|
||||||
nEvents := len(events)
|
nEvents := len(events)
|
||||||
c.Assert(nEvents, checker.GreaterOrEqualThan, 4)
|
c.Assert(nEvents, checker.GreaterOrEqualThan, 4)
|
||||||
|
|
||||||
pluginEvents := eventActionsByIDAndType(c, events, pluginName, "plugin")
|
pluginEvents := eventActionsByIDAndType(c, events, pNameWithTag, "plugin")
|
||||||
c.Assert(pluginEvents, checker.HasLen, 4, check.Commentf("events: %v", events))
|
c.Assert(pluginEvents, checker.HasLen, 4, check.Commentf("events: %v", events))
|
||||||
|
|
||||||
c.Assert(pluginEvents[0], checker.Equals, "pull", check.Commentf(out))
|
c.Assert(pluginEvents[0], checker.Equals, "pull", check.Commentf(out))
|
||||||
|
|
|
@ -774,7 +774,7 @@ func (s *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *check.C) {
|
||||||
testRequires(c, DaemonIsLinux, Network, IsAmd64)
|
testRequires(c, DaemonIsLinux, Network, IsAmd64)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
npName = "mavenugo/test-docker-netplugin"
|
npName = "tiborvass/test-docker-netplugin"
|
||||||
npTag = "latest"
|
npTag = "latest"
|
||||||
npNameWithTag = npName + ":" + npTag
|
npNameWithTag = npName + ":" + npTag
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,9 +10,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
pName = "tiborvass/no-remove"
|
pluginProcessName = "no-remove"
|
||||||
pTag = "latest"
|
pName = "tiborvass/no-remove"
|
||||||
pNameWithTag = pName + ":" + pTag
|
pTag = "latest"
|
||||||
|
pNameWithTag = pName + ":" + pTag
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *DockerSuite) TestPluginBasicOps(c *check.C) {
|
func (s *DockerSuite) TestPluginBasicOps(c *check.C) {
|
||||||
|
|
86
oci/devices_linux.go
Normal file
86
oci/devices_linux.go
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package oci
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/devices"
|
||||||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Device transforms a libcontainer configs.Device to a specs.Device object.
|
||||||
|
func Device(d *configs.Device) specs.Device {
|
||||||
|
return specs.Device{
|
||||||
|
Type: string(d.Type),
|
||||||
|
Path: d.Path,
|
||||||
|
Major: d.Major,
|
||||||
|
Minor: d.Minor,
|
||||||
|
FileMode: fmPtr(int64(d.FileMode)),
|
||||||
|
UID: u32Ptr(int64(d.Uid)),
|
||||||
|
GID: u32Ptr(int64(d.Gid)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deviceCgroup(d *configs.Device) specs.DeviceCgroup {
|
||||||
|
t := string(d.Type)
|
||||||
|
return specs.DeviceCgroup{
|
||||||
|
Allow: true,
|
||||||
|
Type: &t,
|
||||||
|
Major: &d.Major,
|
||||||
|
Minor: &d.Minor,
|
||||||
|
Access: &d.Permissions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DevicesFromPath computes a list of devices and device permissions from paths (pathOnHost and pathInContainer) and cgroup permissions.
|
||||||
|
func DevicesFromPath(pathOnHost, pathInContainer, cgroupPermissions string) (devs []specs.Device, devPermissions []specs.DeviceCgroup, err error) {
|
||||||
|
resolvedPathOnHost := pathOnHost
|
||||||
|
|
||||||
|
// check if it is a symbolic link
|
||||||
|
if src, e := os.Lstat(pathOnHost); e == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||||
|
if linkedPathOnHost, e := filepath.EvalSymlinks(pathOnHost); e == nil {
|
||||||
|
resolvedPathOnHost = linkedPathOnHost
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device, err := devices.DeviceFromPath(resolvedPathOnHost, cgroupPermissions)
|
||||||
|
// if there was no error, return the device
|
||||||
|
if err == nil {
|
||||||
|
device.Path = pathInContainer
|
||||||
|
return append(devs, Device(device)), append(devPermissions, deviceCgroup(device)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the device is not a device node
|
||||||
|
// try to see if it's a directory holding many devices
|
||||||
|
if err == devices.ErrNotADevice {
|
||||||
|
|
||||||
|
// check if it is a directory
|
||||||
|
if src, e := os.Stat(resolvedPathOnHost); e == nil && src.IsDir() {
|
||||||
|
|
||||||
|
// mount the internal devices recursively
|
||||||
|
filepath.Walk(resolvedPathOnHost, func(dpath string, f os.FileInfo, e error) error {
|
||||||
|
childDevice, e := devices.DeviceFromPath(dpath, cgroupPermissions)
|
||||||
|
if e != nil {
|
||||||
|
// ignore the device
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the device to userSpecified devices
|
||||||
|
childDevice.Path = strings.Replace(dpath, resolvedPathOnHost, pathInContainer, 1)
|
||||||
|
devs = append(devs, Device(childDevice))
|
||||||
|
devPermissions = append(devPermissions, deviceCgroup(childDevice))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(devs) > 0 {
|
||||||
|
return devs, devPermissions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return devs, devPermissions, fmt.Errorf("error gathering device information while adding custom device %q: %s", pathOnHost, err)
|
||||||
|
}
|
20
oci/devices_unsupported.go
Normal file
20
oci/devices_unsupported.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package oci
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Device transforms a libcontainer configs.Device to a specs.Device object.
|
||||||
|
// Not implemented
|
||||||
|
func Device(d *configs.Device) specs.Device { return specs.Device{} }
|
||||||
|
|
||||||
|
// DevicesFromPath computes a list of devices and device permissions from paths (pathOnHost and pathInContainer) and cgroup permissions.
|
||||||
|
// Not implemented
|
||||||
|
func DevicesFromPath(pathOnHost, pathInContainer, cgroupPermissions string) (devs []specs.Device, devPermissions []specs.DeviceCgroup, err error) {
|
||||||
|
return nil, nil, errors.New("oci/devices: unsupported platform")
|
||||||
|
}
|
16
oci/namespaces.go
Normal file
16
oci/namespaces.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package oci
|
||||||
|
|
||||||
|
import specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
|
||||||
|
// RemoveNamespace removes the `nsType` namespace from OCI spec `s`
|
||||||
|
func RemoveNamespace(s *specs.Spec, nsType specs.NamespaceType) {
|
||||||
|
idx := -1
|
||||||
|
for i, n := range s.Linux.Namespaces {
|
||||||
|
if n.Type == nsType {
|
||||||
|
idx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx >= 0 {
|
||||||
|
s.Linux.Namespaces = append(s.Linux.Namespaces[:idx], s.Linux.Namespaces[idx+1:]...)
|
||||||
|
}
|
||||||
|
}
|
|
@ -126,7 +126,7 @@ func (ps *Store) updatePluginDB() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns a plugin matching the given name and capability.
|
// Get returns an enabled plugin matching the given name and capability.
|
||||||
func (ps *Store) Get(name, capability string, mode int) (plugingetter.CompatPlugin, error) {
|
func (ps *Store) Get(name, capability string, mode int) (plugingetter.CompatPlugin, error) {
|
||||||
var (
|
var (
|
||||||
p *v2.Plugin
|
p *v2.Plugin
|
||||||
|
@ -151,7 +151,12 @@ func (ps *Store) Get(name, capability string, mode int) (plugingetter.CompatPlug
|
||||||
p.Lock()
|
p.Lock()
|
||||||
p.RefCount += mode
|
p.RefCount += mode
|
||||||
p.Unlock()
|
p.Unlock()
|
||||||
return p.FilterByCap(capability)
|
if p.IsEnabled() {
|
||||||
|
return p.FilterByCap(capability)
|
||||||
|
}
|
||||||
|
// Plugin was found but it is disabled, so we should not fall back to legacy plugins
|
||||||
|
// but we should error out right away
|
||||||
|
return nil, ErrNotFound(fullName)
|
||||||
}
|
}
|
||||||
if _, ok := err.(ErrNotFound); !ok {
|
if _, ok := err.(ErrNotFound); !ok {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -170,7 +175,7 @@ func (ps *Store) Get(name, capability string, mode int) (plugingetter.CompatPlug
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllByCap returns a list of plugins matching the given capability.
|
// GetAllByCap returns a list of enabled plugins matching the given capability.
|
||||||
func (ps *Store) GetAllByCap(capability string) ([]plugingetter.CompatPlugin, error) {
|
func (ps *Store) GetAllByCap(capability string) ([]plugingetter.CompatPlugin, error) {
|
||||||
result := make([]plugingetter.CompatPlugin, 0, 1)
|
result := make([]plugingetter.CompatPlugin, 0, 1)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/oci"
|
||||||
"github.com/docker/docker/pkg/plugins"
|
"github.com/docker/docker/pkg/plugins"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
@ -104,6 +105,8 @@ func (p *Plugin) InitPlugin() error {
|
||||||
p.PluginObj.Settings.Mounts[i] = mount
|
p.PluginObj.Settings.Mounts[i] = mount
|
||||||
}
|
}
|
||||||
p.PluginObj.Settings.Env = make([]string, 0, len(p.PluginObj.Config.Env))
|
p.PluginObj.Settings.Env = make([]string, 0, len(p.PluginObj.Config.Env))
|
||||||
|
p.PluginObj.Settings.Devices = make([]types.PluginDevice, 0, len(p.PluginObj.Config.Linux.Devices))
|
||||||
|
copy(p.PluginObj.Settings.Devices, p.PluginObj.Config.Linux.Devices)
|
||||||
for _, env := range p.PluginObj.Config.Env {
|
for _, env := range p.PluginObj.Config.Env {
|
||||||
if env.Value != nil {
|
if env.Value != nil {
|
||||||
p.PluginObj.Settings.Env = append(p.PluginObj.Settings.Env, fmt.Sprintf("%s=%s", env.Name, *env.Value))
|
p.PluginObj.Settings.Env = append(p.PluginObj.Settings.Env, fmt.Sprintf("%s=%s", env.Name, *env.Value))
|
||||||
|
@ -176,7 +179,7 @@ next:
|
||||||
}
|
}
|
||||||
|
|
||||||
// range over all the devices in the config
|
// range over all the devices in the config
|
||||||
for _, device := range p.PluginObj.Config.Devices {
|
for _, device := range p.PluginObj.Config.Linux.Devices {
|
||||||
// found the device in the config
|
// found the device in the config
|
||||||
if device.Name == s.name {
|
if device.Name == s.name {
|
||||||
// is it settable ?
|
// is it settable ?
|
||||||
|
@ -216,38 +219,45 @@ next:
|
||||||
// ComputePrivileges takes the config file and computes the list of access necessary
|
// ComputePrivileges takes the config file and computes the list of access necessary
|
||||||
// for the plugin on the host.
|
// for the plugin on the host.
|
||||||
func (p *Plugin) ComputePrivileges() types.PluginPrivileges {
|
func (p *Plugin) ComputePrivileges() types.PluginPrivileges {
|
||||||
m := p.PluginObj.Config
|
c := p.PluginObj.Config
|
||||||
var privileges types.PluginPrivileges
|
var privileges types.PluginPrivileges
|
||||||
if m.Network.Type != "null" && m.Network.Type != "bridge" {
|
if c.Network.Type != "null" && c.Network.Type != "bridge" {
|
||||||
privileges = append(privileges, types.PluginPrivilege{
|
privileges = append(privileges, types.PluginPrivilege{
|
||||||
Name: "network",
|
Name: "network",
|
||||||
Description: "",
|
Description: "permissions to access a network",
|
||||||
Value: []string{m.Network.Type},
|
Value: []string{c.Network.Type},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for _, mount := range m.Mounts {
|
for _, mount := range c.Mounts {
|
||||||
if mount.Source != nil {
|
if mount.Source != nil {
|
||||||
privileges = append(privileges, types.PluginPrivilege{
|
privileges = append(privileges, types.PluginPrivilege{
|
||||||
Name: "mount",
|
Name: "mount",
|
||||||
Description: "",
|
Description: "host path to mount",
|
||||||
Value: []string{*mount.Source},
|
Value: []string{*mount.Source},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, device := range m.Devices {
|
for _, device := range c.Linux.Devices {
|
||||||
if device.Path != nil {
|
if device.Path != nil {
|
||||||
privileges = append(privileges, types.PluginPrivilege{
|
privileges = append(privileges, types.PluginPrivilege{
|
||||||
Name: "device",
|
Name: "device",
|
||||||
Description: "",
|
Description: "host device to access",
|
||||||
Value: []string{*device.Path},
|
Value: []string{*device.Path},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(m.Capabilities) > 0 {
|
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{
|
privileges = append(privileges, types.PluginPrivilege{
|
||||||
Name: "capabilities",
|
Name: "capabilities",
|
||||||
Description: "",
|
Description: "list of additional capabilities required",
|
||||||
Value: m.Capabilities,
|
Value: c.Linux.Capabilities,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return privileges
|
return privileges
|
||||||
|
@ -293,12 +303,40 @@ func (p *Plugin) InitSpec(s specs.Spec, libRoot string) (*specs.Spec, error) {
|
||||||
Readonly: false, // TODO: all plugins should be readonly? settable in config?
|
Readonly: false, // TODO: all plugins should be readonly? settable in config?
|
||||||
}
|
}
|
||||||
|
|
||||||
mounts := append(p.PluginObj.Settings.Mounts, types.PluginMount{
|
userMounts := make(map[string]struct{}, len(p.PluginObj.Config.Mounts))
|
||||||
|
for _, m := range p.PluginObj.Config.Mounts {
|
||||||
|
userMounts[m.Destination] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
mounts := append(p.PluginObj.Config.Mounts, types.PluginMount{
|
||||||
Source: &p.RuntimeSourcePath,
|
Source: &p.RuntimeSourcePath,
|
||||||
Destination: defaultPluginRuntimeDestination,
|
Destination: defaultPluginRuntimeDestination,
|
||||||
Type: "bind",
|
Type: "bind",
|
||||||
Options: []string{"rbind", "rshared"},
|
Options: []string{"rbind", "rshared"},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if p.PluginObj.Config.Network.Type != "" {
|
||||||
|
// TODO: if net == bridge, use libnetwork controller to create a new plugin-specific bridge, bind mount /etc/hosts and /etc/resolv.conf look at the docker code (allocateNetwork, initialize)
|
||||||
|
if p.PluginObj.Config.Network.Type == "host" {
|
||||||
|
oci.RemoveNamespace(&s, specs.NamespaceType("network"))
|
||||||
|
}
|
||||||
|
etcHosts := "/etc/hosts"
|
||||||
|
resolvConf := "/etc/resolv.conf"
|
||||||
|
mounts = append(mounts,
|
||||||
|
types.PluginMount{
|
||||||
|
Source: &etcHosts,
|
||||||
|
Destination: etcHosts,
|
||||||
|
Type: "bind",
|
||||||
|
Options: []string{"rbind", "ro"},
|
||||||
|
},
|
||||||
|
types.PluginMount{
|
||||||
|
Source: &resolvConf,
|
||||||
|
Destination: resolvConf,
|
||||||
|
Type: "bind",
|
||||||
|
Options: []string{"rbind", "ro"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
for _, mount := range mounts {
|
for _, mount := range mounts {
|
||||||
m := specs.Mount{
|
m := specs.Mount{
|
||||||
Destination: mount.Destination,
|
Destination: mount.Destination,
|
||||||
|
@ -323,6 +361,28 @@ func (p *Plugin) InitSpec(s specs.Spec, libRoot string) (*specs.Spec, error) {
|
||||||
s.Mounts = append(s.Mounts, m)
|
s.Mounts = append(s.Mounts, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i, m := range s.Mounts {
|
||||||
|
if strings.HasPrefix(m.Destination, "/dev/") {
|
||||||
|
if _, ok := userMounts[m.Destination]; ok {
|
||||||
|
s.Mounts = append(s.Mounts[:i], s.Mounts[i+1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.PluginObj.Config.Linux.DeviceCreation {
|
||||||
|
rwm := "rwm"
|
||||||
|
s.Linux.Resources.Devices = []specs.DeviceCgroup{{Allow: true, Access: &rwm}}
|
||||||
|
}
|
||||||
|
for _, dev := range p.PluginObj.Config.Linux.Devices {
|
||||||
|
path := *dev.Path
|
||||||
|
d, dPermissions, err := oci.DevicesFromPath(path, path, "rwm")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.Linux.Devices = append(s.Linux.Devices, d...)
|
||||||
|
s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, dPermissions...)
|
||||||
|
}
|
||||||
|
|
||||||
envs := make([]string, 1, len(p.PluginObj.Settings.Env)+1)
|
envs := make([]string, 1, len(p.PluginObj.Settings.Env)+1)
|
||||||
envs[0] = "PATH=" + system.DefaultPathEnv
|
envs[0] = "PATH=" + system.DefaultPathEnv
|
||||||
envs = append(envs, p.PluginObj.Settings.Env...)
|
envs = append(envs, p.PluginObj.Settings.Env...)
|
||||||
|
@ -332,12 +392,12 @@ func (p *Plugin) InitSpec(s specs.Spec, libRoot string) (*specs.Spec, error) {
|
||||||
if len(cwd) == 0 {
|
if len(cwd) == 0 {
|
||||||
cwd = "/"
|
cwd = "/"
|
||||||
}
|
}
|
||||||
s.Process = specs.Process{
|
s.Process.Terminal = false
|
||||||
Terminal: false,
|
s.Process.Args = args
|
||||||
Args: args,
|
s.Process.Cwd = cwd
|
||||||
Cwd: cwd,
|
s.Process.Env = envs
|
||||||
Env: envs,
|
|
||||||
}
|
s.Process.Capabilities = append(s.Process.Capabilities, p.PluginObj.Config.Linux.Capabilities...)
|
||||||
|
|
||||||
return &s, nil
|
return &s, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
|
||||||
golang.org/x/net 2beffdc2e92c8a3027590f898fe88f69af48a3f8 https://github.com/tonistiigi/net.git
|
golang.org/x/net 2beffdc2e92c8a3027590f898fe88f69af48a3f8 https://github.com/tonistiigi/net.git
|
||||||
golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9
|
golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9
|
||||||
github.com/docker/go-units 8a7beacffa3009a9ac66bad506b18ffdd110cf97
|
github.com/docker/go-units 8a7beacffa3009a9ac66bad506b18ffdd110cf97
|
||||||
github.com/docker/go-connections f512407a188ecb16f31a33dbc9c4e4814afc1b03
|
github.com/docker/go-connections 4ccf312bf1d35e5dbda654e57a9be4c3f3cd0366
|
||||||
|
|
||||||
github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
|
github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
|
||||||
github.com/imdario/mergo 0.2.1
|
github.com/imdario/mergo 0.2.1
|
||||||
|
|
16
vendor/github.com/docker/go-connections/sockets/sockets.go
generated
vendored
16
vendor/github.com/docker/go-connections/sockets/sockets.go
generated
vendored
|
@ -2,6 +2,7 @@
|
||||||
package sockets
|
package sockets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
@ -10,6 +11,9 @@ import (
|
||||||
// Why 32? See https://github.com/docker/docker/pull/8035.
|
// Why 32? See https://github.com/docker/docker/pull/8035.
|
||||||
const defaultTimeout = 32 * time.Second
|
const defaultTimeout = 32 * time.Second
|
||||||
|
|
||||||
|
// ErrProtocolNotAvailable is returned when a given transport protocol is not provided by the operating system.
|
||||||
|
var ErrProtocolNotAvailable = errors.New("protocol not available")
|
||||||
|
|
||||||
// ConfigureTransport configures the specified Transport according to the
|
// ConfigureTransport configures the specified Transport according to the
|
||||||
// specified proto and addr.
|
// specified proto and addr.
|
||||||
// If the proto is unix (using a unix socket to communicate) or npipe the
|
// If the proto is unix (using a unix socket to communicate) or npipe the
|
||||||
|
@ -17,17 +21,9 @@ const defaultTimeout = 32 * time.Second
|
||||||
func ConfigureTransport(tr *http.Transport, proto, addr string) error {
|
func ConfigureTransport(tr *http.Transport, proto, addr string) error {
|
||||||
switch proto {
|
switch proto {
|
||||||
case "unix":
|
case "unix":
|
||||||
// No need for compression in local communications.
|
return configureUnixTransport(tr, proto, addr)
|
||||||
tr.DisableCompression = true
|
|
||||||
tr.Dial = func(_, _ string) (net.Conn, error) {
|
|
||||||
return net.DialTimeout(proto, addr, defaultTimeout)
|
|
||||||
}
|
|
||||||
case "npipe":
|
case "npipe":
|
||||||
// No need for compression in local communications.
|
return configureNpipeTransport(tr, proto, addr)
|
||||||
tr.DisableCompression = true
|
|
||||||
tr.Dial = func(_, _ string) (net.Conn, error) {
|
|
||||||
return DialPipe(addr, defaultTimeout)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
tr.Proxy = http.ProxyFromEnvironment
|
tr.Proxy = http.ProxyFromEnvironment
|
||||||
dialer, err := DialerFromEnvironment(&net.Dialer{
|
dialer, err := DialerFromEnvironment(&net.Dialer{
|
||||||
|
|
20
vendor/github.com/docker/go-connections/sockets/sockets_unix.go
generated
vendored
20
vendor/github.com/docker/go-connections/sockets/sockets_unix.go
generated
vendored
|
@ -3,11 +3,31 @@
|
||||||
package sockets
|
package sockets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const maxUnixSocketPathSize = len(syscall.RawSockaddrUnix{}.Path)
|
||||||
|
|
||||||
|
func configureUnixTransport(tr *http.Transport, proto, addr string) error {
|
||||||
|
if len(addr) > maxUnixSocketPathSize {
|
||||||
|
return fmt.Errorf("Unix socket path %q is too long", addr)
|
||||||
|
}
|
||||||
|
// No need for compression in local communications.
|
||||||
|
tr.DisableCompression = true
|
||||||
|
tr.Dial = func(_, _ string) (net.Conn, error) {
|
||||||
|
return net.DialTimeout(proto, addr, defaultTimeout)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureNpipeTransport(tr *http.Transport, proto, addr string) error {
|
||||||
|
return ErrProtocolNotAvailable
|
||||||
|
}
|
||||||
|
|
||||||
// DialPipe connects to a Windows named pipe.
|
// DialPipe connects to a Windows named pipe.
|
||||||
// This is not supported on other OSes.
|
// This is not supported on other OSes.
|
||||||
func DialPipe(_ string, _ time.Duration) (net.Conn, error) {
|
func DialPipe(_ string, _ time.Duration) (net.Conn, error) {
|
||||||
|
|
14
vendor/github.com/docker/go-connections/sockets/sockets_windows.go
generated
vendored
14
vendor/github.com/docker/go-connections/sockets/sockets_windows.go
generated
vendored
|
@ -2,11 +2,25 @@ package sockets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
"github.com/Microsoft/go-winio"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func configureUnixTransport(tr *http.Transport, proto, addr string) error {
|
||||||
|
return ErrProtocolNotAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureNpipeTransport(tr *http.Transport, proto, addr string) error {
|
||||||
|
// No need for compression in local communications.
|
||||||
|
tr.DisableCompression = true
|
||||||
|
tr.Dial = func(_, _ string) (net.Conn, error) {
|
||||||
|
return DialPipe(addr, defaultTimeout)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// DialPipe connects to a Windows named pipe.
|
// DialPipe connects to a Windows named pipe.
|
||||||
func DialPipe(addr string, timeout time.Duration) (net.Conn, error) {
|
func DialPipe(addr string, timeout time.Duration) (net.Conn, error) {
|
||||||
return winio.DialPipe(addr, &timeout)
|
return winio.DialPipe(addr, &timeout)
|
||||||
|
|
Loading…
Add table
Reference in a new issue