From e8cec5a0daabff9560d32c0c2ba3252cbe95b6a3 Mon Sep 17 00:00:00 2001 From: Krisztian Litkey Date: Tue, 2 Jul 2024 12:07:15 +0300 Subject: [PATCH] device-injector: add support for CDI injection. Add support for injecting annotated CDI devices using the new native NRI CDI injection API. Signed-off-by: Krisztian Litkey --- plugins/device-injector/README.md | 29 +++++++++- plugins/device-injector/device-injector.go | 66 ++++++++++++++++++++-- 2 files changed, 90 insertions(+), 5 deletions(-) diff --git a/plugins/device-injector/README.md b/plugins/device-injector/README.md index 5c594d66..7fa56272 100644 --- a/plugins/device-injector/README.md +++ b/plugins/device-injector/README.md @@ -1,6 +1,6 @@ ## Device Injector Plugin -This sample plugin can inject devices and mounts into containers using +This sample plugin can inject devices, CDI devices and mounts into containers using pod annotations. ### Device Annotations @@ -26,6 +26,33 @@ The annotation syntax for device injection is `file_mode`, `uid` and `gid` can be omitted, the rest are mandatory. +### CDI Device Annotations + +Devices are annotated using the `cdi-devices.nri.io` annotation key prefix. +The key `cdi-devices.nri.io/container.$CONTAINER_NAME` annotates CDI devices +to be injected into `$CONTAINER_NAME`. The keys `cdi-devices.nri.io` and +`cdi-devices.nri.io/pod` annotate CDI devices to be injected into all +containers of the pod. + +The annotation value syntax is an array of CDI device names to inject. For +instance, the following annotation + +``` +metadata: + name: bash + annotations: + cdi-devices.nri.io/container.c0: | + - vendor0.com/device=null + cdi-devices.nri.io/container.c1: | + - vendor0.com/device=zero + cdi-devices.nri.io/container.mgmt: | + - vendor0.com/device=all +``` + +requests the injection of the vendor0.com/device=null, vendor0.com/device=zero, +and vendor0.com/device=all CDI devices, to the c0, c1, and mgmt containers of +the pod. + ### Mount Annotations Mounts are annotated in a similar manner to devices, but using the diff --git a/plugins/device-injector/device-injector.go b/plugins/device-injector/device-injector.go index 3c19cd2b..69539031 100644 --- a/plugins/device-injector/device-injector.go +++ b/plugins/device-injector/device-injector.go @@ -35,6 +35,8 @@ const ( deviceKey = "devices.nri.io" // Prefix of the key used for mount annotations. mountKey = "mounts.nri.io" + // Prefix of the key used for CDI device annotations. + cdiDeviceKey = "cdi-devices.nri.io" ) var ( @@ -69,10 +71,11 @@ type plugin struct { // CreateContainer handles container creation requests. func (p *plugin) CreateContainer(_ context.Context, pod *api.PodSandbox, container *api.Container) (*api.ContainerAdjustment, []*api.ContainerUpdate, error) { var ( - ctrName string - devices []device - mounts []mount - err error + ctrName string + devices []device + cdiDevices []string + mounts []mount + err error ) ctrName = containerName(pod, container) @@ -104,6 +107,31 @@ func (p *plugin) CreateContainer(_ context.Context, pod *api.PodSandbox, contain } } + // inject CDI devices to container + cdiDevices, err = parseCDIDevices(container.Name, pod.Annotations) + if err != nil { + return nil, nil, err + } + + if len(cdiDevices) == 0 { + log.Infof("%s: no CDI devices annotated...", ctrName) + } else { + if verbose { + dump(ctrName, "annotated CDI devices", devices) + } + + for _, name := range cdiDevices { + adjust.AddCDIDevice( + &api.CDIDevice{ + Name: name, + }, + ) + if !verbose { + log.Infof("%s: injected CDI device %q...", ctrName, name) + } + } + } + // inject mounts to container mounts, err = parseMounts(container.Name, pod.Annotations) if err != nil { @@ -162,6 +190,36 @@ func parseDevices(ctr string, annotations map[string]string) ([]device, error) { return devices, nil } +func parseCDIDevices(ctr string, annotations map[string]string) ([]string, error) { + var ( + key string + annotation []byte + cdiDevices []string + ) + + // look up effective device annotation and unmarshal devices + for _, key = range []string{ + cdiDeviceKey + "/container." + ctr, + cdiDeviceKey + "/pod", + cdiDeviceKey, + } { + if value, ok := annotations[key]; ok { + annotation = []byte(value) + break + } + } + + if annotation == nil { + return nil, nil + } + + if err := yaml.Unmarshal(annotation, &cdiDevices); err != nil { + return nil, fmt.Errorf("invalid CDI device annotation %q: %w", key, err) + } + + return cdiDevices, nil +} + func parseMounts(ctr string, annotations map[string]string) ([]mount, error) { var ( key string