Skip to content

Commit b8f51d9

Browse files
authored
Merge pull request #4084 from elezar/add-cdi-support
Support CDI devices in --device flag
2 parents dc2eb3b + dbd9d5d commit b8f51d9

File tree

7 files changed

+520
-34
lines changed

7 files changed

+520
-34
lines changed

cli/command/container/opts.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"strings"
1414
"time"
1515

16+
cdi "github.com/container-orchestrated-devices/container-device-interface/pkg/parser"
1617
"github.com/docker/cli/cli/compose/loader"
1718
"github.com/docker/cli/opts"
1819
"github.com/docker/docker/api/types/container"
@@ -449,12 +450,17 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
449450
// parsing flags, we haven't yet sent a _ping to the daemon to determine
450451
// what operating system it is.
451452
deviceMappings := []container.DeviceMapping{}
453+
var cdiDeviceNames []string
452454
for _, device := range copts.devices.GetAll() {
453455
var (
454456
validated string
455457
deviceMapping container.DeviceMapping
456458
err error
457459
)
460+
if cdi.IsQualifiedName(device) {
461+
cdiDeviceNames = append(cdiDeviceNames, device)
462+
continue
463+
}
458464
validated, err = validateDevice(device, serverOS)
459465
if err != nil {
460466
return nil, err
@@ -559,6 +565,15 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
559565
}
560566
}
561567

568+
deviceRequests := copts.gpus.Value()
569+
if len(cdiDeviceNames) > 0 {
570+
cdiDeviceRequest := container.DeviceRequest{
571+
Driver: "cdi",
572+
DeviceIDs: cdiDeviceNames,
573+
}
574+
deviceRequests = append(deviceRequests, cdiDeviceRequest)
575+
}
576+
562577
resources := container.Resources{
563578
CgroupParent: copts.cgroupParent,
564579
Memory: copts.memory.Value(),
@@ -589,7 +604,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
589604
Ulimits: copts.ulimits.GetList(),
590605
DeviceCgroupRules: copts.deviceCgroupRules.GetAll(),
591606
Devices: deviceMappings,
592-
DeviceRequests: copts.gpus.Value(),
607+
DeviceRequests: deviceRequests,
593608
}
594609

595610
config := &container.Config{

cli/command/container/opts_test.go

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -417,39 +417,91 @@ func TestParseWithExpose(t *testing.T) {
417417

418418
func TestParseDevice(t *testing.T) {
419419
skip.If(t, runtime.GOOS != "linux") // Windows and macOS validate server-side
420-
valids := map[string]container.DeviceMapping{
421-
"/dev/snd": {
422-
PathOnHost: "/dev/snd",
423-
PathInContainer: "/dev/snd",
424-
CgroupPermissions: "rwm",
425-
},
426-
"/dev/snd:rw": {
427-
PathOnHost: "/dev/snd",
428-
PathInContainer: "/dev/snd",
429-
CgroupPermissions: "rw",
430-
},
431-
"/dev/snd:/something": {
432-
PathOnHost: "/dev/snd",
433-
PathInContainer: "/something",
434-
CgroupPermissions: "rwm",
435-
},
436-
"/dev/snd:/something:rw": {
437-
PathOnHost: "/dev/snd",
438-
PathInContainer: "/something",
439-
CgroupPermissions: "rw",
440-
},
441-
}
442-
for device, deviceMapping := range valids {
443-
_, hostconfig, _, err := parseRun([]string{fmt.Sprintf("--device=%v", device), "img", "cmd"})
444-
if err != nil {
445-
t.Fatal(err)
446-
}
447-
if len(hostconfig.Devices) != 1 {
448-
t.Fatalf("Expected 1 devices, got %v", hostconfig.Devices)
449-
}
450-
if hostconfig.Devices[0] != deviceMapping {
451-
t.Fatalf("Expected %v, got %v", deviceMapping, hostconfig.Devices)
452-
}
420+
testCases := []struct {
421+
devices []string
422+
deviceMapping *container.DeviceMapping
423+
deviceRequests []container.DeviceRequest
424+
}{
425+
{
426+
devices: []string{"/dev/snd"},
427+
deviceMapping: &container.DeviceMapping{
428+
PathOnHost: "/dev/snd",
429+
PathInContainer: "/dev/snd",
430+
CgroupPermissions: "rwm",
431+
},
432+
},
433+
{
434+
devices: []string{"/dev/snd:rw"},
435+
deviceMapping: &container.DeviceMapping{
436+
PathOnHost: "/dev/snd",
437+
PathInContainer: "/dev/snd",
438+
CgroupPermissions: "rw",
439+
},
440+
},
441+
{
442+
devices: []string{"/dev/snd:/something"},
443+
deviceMapping: &container.DeviceMapping{
444+
PathOnHost: "/dev/snd",
445+
PathInContainer: "/something",
446+
CgroupPermissions: "rwm",
447+
},
448+
},
449+
{
450+
devices: []string{"/dev/snd:/something:rw"},
451+
deviceMapping: &container.DeviceMapping{
452+
PathOnHost: "/dev/snd",
453+
PathInContainer: "/something",
454+
CgroupPermissions: "rw",
455+
},
456+
},
457+
{
458+
devices: []string{"vendor.com/class=name"},
459+
deviceMapping: nil,
460+
deviceRequests: []container.DeviceRequest{
461+
{
462+
Driver: "cdi",
463+
DeviceIDs: []string{"vendor.com/class=name"},
464+
},
465+
},
466+
},
467+
{
468+
devices: []string{"vendor.com/class=name", "/dev/snd:/something:rw"},
469+
deviceMapping: &container.DeviceMapping{
470+
PathOnHost: "/dev/snd",
471+
PathInContainer: "/something",
472+
CgroupPermissions: "rw",
473+
},
474+
deviceRequests: []container.DeviceRequest{
475+
{
476+
Driver: "cdi",
477+
DeviceIDs: []string{"vendor.com/class=name"},
478+
},
479+
},
480+
},
481+
}
482+
483+
for _, tc := range testCases {
484+
t.Run(fmt.Sprintf("%s", tc.devices), func(t *testing.T) {
485+
var args []string
486+
for _, d := range tc.devices {
487+
args = append(args, fmt.Sprintf("--device=%v", d))
488+
}
489+
args = append(args, "img", "cmd")
490+
491+
_, hostconfig, _, err := parseRun(args)
492+
493+
assert.NilError(t, err)
494+
495+
if tc.deviceMapping != nil {
496+
if assert.Check(t, is.Len(hostconfig.Devices, 1)) {
497+
assert.Check(t, is.DeepEqual(*tc.deviceMapping, hostconfig.Devices[0]))
498+
}
499+
} else {
500+
assert.Check(t, is.Len(hostconfig.Devices, 0))
501+
}
502+
503+
assert.Check(t, is.DeepEqual(tc.deviceRequests, hostconfig.DeviceRequests))
504+
})
453505
}
454506
}
455507

vendor.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ go 1.18
88

99
require (
1010
dario.cat/mergo v1.0.0
11+
github.com/container-orchestrated-devices/container-device-interface v0.5.5-0.20230516140309-1e6752771dc5
1112
github.com/containerd/containerd v1.6.21
1213
github.com/creack/pty v1.1.18
1314
github.com/docker/distribution v2.8.2+incompatible

vendor.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
8484
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
8585
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
8686
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
87+
github.com/container-orchestrated-devices/container-device-interface v0.5.5-0.20230516140309-1e6752771dc5 h1:qJTKvM6AD0paTZodYyHV540e01I6+Uhq5vkKBi4byvQ=
88+
github.com/container-orchestrated-devices/container-device-interface v0.5.5-0.20230516140309-1e6752771dc5/go.mod h1:OQlgtJtDrOxSQ1BWODC8OZK1tzi9W69wek+Jy17ndzo=
8789
github.com/containerd/containerd v1.6.21 h1:eSTAmnvDKRPWan+MpSSfNyrtleXd86ogK9X8fMWpe/Q=
8890
github.com/containerd/containerd v1.6.21/go.mod h1:apei1/i5Ux2FzrK6+DM/suEsGuK/MeVOfy8tR2q7Wnw=
8991
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=

vendor/github.com/container-orchestrated-devices/container-device-interface/LICENSE

Lines changed: 201 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)