Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for devices #3186

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions api/api.pb.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5810,6 +5810,14 @@ file {
type: TYPE_INT64
json_name: "oomScoreAdj"
}
field {
name: "Devices"
number: 31
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".docker.swarmkit.v1.ContainerSpec.DeviceMapping"
json_name: "Devices"
}
nested_type {
name: "LabelsEntry"
field {
Expand Down Expand Up @@ -5908,6 +5916,30 @@ file {
json_name: "hard"
}
}
nested_type {
name: "DeviceMapping"
field {
name: "pathOnHost"
number: 1
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "pathOnHost"
}
field {
name: "pathInContainer"
number: 2
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "pathInContainer"
}
field {
name: "cgroupPermissions"
number: 3
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "cgroupPermissions"
}
}
enum_type {
name: "Isolation"
value {
Expand Down
679 changes: 516 additions & 163 deletions api/specs.pb.go

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions api/specs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,13 @@ message ContainerSpec {
// OOmScoreAdj defines the relative value used for destroying a container during an OOM
// Values are between -1000 and 1000
int64 oom_score_adj = 30;

message DeviceMapping {
string pathOnHost = 1;
string pathInContainer = 2;
string cgroupPermissions = 3;
}
repeated DeviceMapping Devices = 31;
}

// EndpointSpec defines the properties that can be configured to
Expand Down
49 changes: 49 additions & 0 deletions swarmd/cmd/swarmctl/service/flagparser/device.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package flagparser

import (
"strings"

"github.com/moby/swarmkit/v2/api"
"github.com/pkg/errors"
"github.com/spf13/pflag"
)

func parseDevice(flags *pflag.FlagSet, spec *api.ServiceSpec) error {
if flags.Changed("device") {
container := spec.Task.GetContainer()
if container == nil {
return nil
}

devices, err := flags.GetStringSlice("device")
if err != nil {
return err
}

container.Devices = make([]*api.ContainerSpec_DeviceMapping, len(devices))

for i, device := range devices {
parts := strings.Split(device, ":")
if len(parts) < 1 || len(parts) > 3 {
return errors.Wrap(err, "failed to parse device")
}

mapping := &api.ContainerSpec_DeviceMapping{
PathOnHost: parts[0],
PathInContainer: parts[0],
}

if len(parts) > 1 {
mapping.PathInContainer = parts[1]
}

if len(parts) == 3 {
mapping.CgroupPermissions = parts[2]
}

container.Devices[i] = mapping
}
}

return nil
}
5 changes: 5 additions & 0 deletions swarmd/cmd/swarmctl/service/flagparser/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func AddServiceFlags(flags *pflag.FlagSet) {
flags.StringSlice("volume", nil, "define a volume mount")
flags.StringSlice("tmpfs", nil, "define a tmpfs mount")
flags.StringSlice("npipe", nil, "define a npipe mount")
flags.StringSlice("device", nil, "device options")

flags.String("log-driver", "", "specify a log driver")
flags.StringSlice("log-opt", nil, "log driver options, as key value pairs")
Expand Down Expand Up @@ -151,6 +152,10 @@ func Merge(cmd *cobra.Command, spec *api.ServiceSpec, c api.ControlClient) error
return err
}

if err := parseDevice(flags, spec); err != nil {
return err
}

driver, err := common.ParseLogDriverFlags(flags)
if err != nil {
return err
Expand Down
9 changes: 9 additions & 0 deletions swarmd/dockerexec/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,15 @@ func (c *containerConfig) resources() enginecontainer.Resources {
}
}

resources.Devices = make([]enginecontainer.DeviceMapping, len(c.spec().Devices))
for i, device := range c.spec().Devices {
resources.Devices[i] = enginecontainer.DeviceMapping{
PathOnHost: device.PathOnHost,
PathInContainer: device.PathInContainer,
CgroupPermissions: device.CgroupPermissions,
}
}

// If no limits are specified let the engine use its defaults.
//
// TODO(aluzzardi): We might want to set some limits anyway otherwise
Expand Down
32 changes: 32 additions & 0 deletions swarmd/dockerexec/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,35 @@ func TestUlimits(t *testing.T) {
t.Fatalf("expected %v, got %v", expected, actual)
}
}

func TestDevices(t *testing.T) {
c := containerConfig{
task: &api.Task{
Spec: api.TaskSpec{
Runtime: &api.TaskSpec_Container{
Container: &api.ContainerSpec{
Devices: []*api.ContainerSpec_DeviceMapping{
{
PathOnHost: "/dev/dri/card0",
PathInContainer: "/dev/card0",
CgroupPermissions: "ro",
},
},
},
},
},
},
}

expected := []enginecontainer.DeviceMapping{
{
PathOnHost: "/dev/dri/card0",
PathInContainer: "/dev/card0",
CgroupPermissions: "ro",
},
}
actual := c.resources().Devices
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("expected %v, got %v", expected, actual)
}
}