Add support for passing device into docker driver

This commit is contained in:
Preetha Appan
2017-11-06 12:27:13 -06:00
parent 28779af0fd
commit 85c5218b78
3 changed files with 100 additions and 0 deletions

View File

@@ -142,6 +142,12 @@ type DockerMount struct {
VolumeOptions []*DockerVolumeOptions `mapstructure:"volume_options"`
}
type DockerDevice struct {
HostPath string `mapstructure:"host_path"`
ContainerPath string `mapstructure:"container_path"`
CgroupPermissions string `mapstructure:"cgroup_permissions"`
}
type DockerVolumeOptions struct {
NoCopy bool `mapstructure:"no_copy"`
Labels []map[string]string `mapstructure:"labels"`
@@ -190,6 +196,7 @@ type DockerDriverConfig struct {
ForcePull bool `mapstructure:"force_pull"` // Always force pull before running image, useful if your tags are mutable
MacAddress string `mapstructure:"mac_address"` // Pin mac address to container
SecurityOpt []string `mapstructure:"security_opt"` // Flags to pass directly to security-opt
Devices []DockerDevice `mapstructure:"devices"` // To allow mounting USB or other serial control devices
}
// Validate validates a docker driver config
@@ -197,6 +204,22 @@ func (c *DockerDriverConfig) Validate() error {
if c.ImageName == "" {
return fmt.Errorf("Docker Driver needs an image name")
}
if len(c.Devices) > 0 {
for _, dev := range c.Devices {
if dev.HostPath == "" {
return fmt.Errorf("host path must be set in configuration for devices")
}
if dev.CgroupPermissions != "" {
for _, c := range dev.CgroupPermissions {
ch := string(c)
if ch != "r" && ch != "w" && ch != "m" {
return fmt.Errorf("invalid cgroup permission string: %q", dev.CgroupPermissions)
}
}
}
}
}
return nil
}
@@ -537,6 +560,9 @@ func (d *DockerDriver) Validate(config map[string]interface{}) error {
"security_opt": {
Type: fields.TypeArray,
},
"devices": {
Type: fields.TypeArray,
},
},
}
@@ -1020,6 +1046,20 @@ func (d *DockerDriver) createContainerConfig(ctx *ExecContext, task *structs.Tas
}
}
if len(driverConfig.Devices) > 0 {
var devices []docker.Device
for _, device := range driverConfig.Devices {
if device.HostPath != "" {
dev := docker.Device{
PathOnHost: device.HostPath,
PathInContainer: device.ContainerPath,
CgroupPermissions: device.CgroupPermissions}
devices = append(devices, dev)
}
}
hostConfig.Devices = devices
}
// Setup mounts
for _, m := range driverConfig.Mounts {
hm := docker.HostMount{

View File

@@ -1803,3 +1803,44 @@ func TestDockerDriver_OOMKilled(t *testing.T) {
t.Fatalf("timeout")
}
}
func TestDockerDriver_Devices_IsInvalidConfig(t *testing.T) {
if !tu.IsTravis() {
t.Parallel()
}
if !testutil.DockerIsConnected(t) {
t.Skip("Docker not connected")
}
brokenConfigs := []interface{}{
map[string]interface{}{
"host_path": "",
},
map[string]interface{}{
"host_path": "/dev/sda1",
"cgroup_permissions": "rxb",
},
}
test_cases := []struct {
deviceConfig interface{}
err error
}{
{[]interface{}{brokenConfigs[0]}, fmt.Errorf("host path must be set in configuration for devices")},
{[]interface{}{brokenConfigs[1]}, fmt.Errorf("invalid cgroup permission string: \"rxb\"")},
}
for _, tc := range test_cases {
task, _, _ := dockerTask(t)
task.Config["devices"] = tc.deviceConfig
ctx := testDockerDriverContexts(t, task)
driver := NewDockerDriver(ctx.DriverCtx)
copyImage(t, ctx.ExecCtx.TaskDir, "busybox.tar")
defer ctx.AllocDir.Destroy()
if _, err := driver.Prestart(ctx.ExecCtx, task); err == nil || err.Error() != tc.err.Error() {
t.Fatalf("error expected in prestart, got %v, expected %v", err, tc.err)
}
}
}

View File

@@ -280,7 +280,26 @@ The `docker` driver supports the following configuration in the job spec. Only
]
}
```
* `devices` - (Optional) A list of
[devices](https://docs.docker.com/engine/reference/commandline/run/#add-host-device-to-container-device)
to be exposed the container. `host_path` is the only required field. By default, the container will be able to
`read`, `write` and `mknod` these devices. Use the optional `cgroup_permissions` field to restrict permissions.
```hcl
config {
devices = [
{
host_path = "/dev/sda1"
container_path = "/dev/xvdc"
cgroup_permissions = "r"
},
{
host_path = "/dev/sda2"
container_path = "/dev/xvdd"
}
]
}
```
### Container Name
Nomad creates a container after pulling an image. Containers are named