mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 02:15:43 +03:00
Add support for passing device into docker driver
This commit is contained in:
@@ -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{
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user