Skip to content

Commit

Permalink
Add support for devices
Browse files Browse the repository at this point in the history
Signed-off-by: Zik Aeroh <48577114+zikaeroh@users.noreply.github.com>
  • Loading branch information
zikaeroh committed Mar 5, 2023
1 parent df50c3a commit 8d68df6
Show file tree
Hide file tree
Showing 7 changed files with 649 additions and 161 deletions.
9 changes: 9 additions & 0 deletions agent/exec/dockerapi/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,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 agent/exec/dockerapi/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,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)
}
}
32 changes: 32 additions & 0 deletions api/api.pb.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5677,6 +5677,14 @@ file {
type_name: ".docker.swarmkit.v1.ContainerSpec.Ulimit"
json_name: "ulimits"
}
field {
name: "Devices"
number: 30
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 @@ -5775,6 +5783,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
675 changes: 514 additions & 161 deletions api/specs.pb.go

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions api/specs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,14 @@ message ContainerSpec {
// Ulimits defines the list of ulimits to set in the container. This option
// is equivalent to passing --ulimit to docker run.
repeated Ulimit ulimits = 29;

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

repeated DeviceMapping Devices = 30;
}

// EndpointSpec defines the properties that can be configured to
Expand Down
49 changes: 49 additions & 0 deletions 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 cmd/swarmctl/service/flagparser/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,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 @@ -150,6 +151,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

0 comments on commit 8d68df6

Please sign in to comment.