Skip to content

Commit 9c1a1bd

Browse files
authored
Merge pull request #85 from zvonkok/annotations
Added Annotations to CDI Spec
2 parents fcab9ad + 7321bf2 commit 9c1a1bd

File tree

14 files changed

+634
-48
lines changed

14 files changed

+634
-48
lines changed

README.md

Lines changed: 97 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,64 +4,85 @@
44

55
## What is CDI?
66

7-
CDI (Container Device Interface), is a [specification](SPEC.md), for container runtimes, to support third party devices.
7+
CDI (Container Device Interface), is a [specification](SPEC.md), for container-
8+
runtimes, to support third-party devices.
89

9-
It introduces an abstract notion of a device as a resource. Such devices are uniquely specified by a fully-qualified name that is constructed from a vendor ID, a device class, and a name that is unique per vendor ID-device class pair.
10+
It introduces an abstract notion of a device as a resource. Such devices are
11+
uniquely specified by a fully-qualified name that is constructed from a vendor
12+
ID, a device class, and a name that is unique per vendor ID-device class pair.
1013

1114
```
1215
vendor.com/class=unique_name
1316
```
1417

15-
The combination of vendor ID and device class (`vendor.com/class` in the above example) is referred to as the device kind.
18+
The combination of vendor ID and device class (`vendor.com/class` in the above
19+
example) is referred to as the device kind.
1620

17-
CDI concerns itself only with enabling container to be device aware. Areas like resource management are explicitly left out of CDI (and is expected to be handled by the orchestrator). Because of this focus, the CDI specification is simple to implement and allows great flexibility to runtimes and orchestrators.
21+
CDI concerns itself only with enabling containers to be device aware. Areas like
22+
resource management are explicitly left out of CDI (and are expected to be
23+
handled by the orchestrator). Because of this focus, the CDI specification is
24+
simple to implement and allows great flexibility for runtimes and orchestrators.
1825

19-
Note: The CDI model is based on the Container Networking Interface (CNI) model and specification.
26+
Note: The CDI model is based on the Container Networking Interface (CNI) model
27+
and specification.
2028

2129
## Why is CDI needed?
2230

23-
On Linux, enabling a container to be device aware used to be as simple as exposing a device node in that container.
24-
However, as devices and software grows more complex, vendors want to perform more operations, such as:
25-
26-
- Exposing a device to a container can require exposing more than one device node, mounting files from the runtime namespace or hide procfs entries.
27-
- Performing compatibility checks between the container and the device (e.g: Can this container run on this device).
28-
- Performing runtime specific operations (e.g: VM vs linux containers based runtimes).
29-
- Performing device specific operations (e.g: scrubbing the memory of a GPU or reconfiguring an FPGA).
30-
31-
In the absence of a standard for third party devices, vendors often have to write and maintain multiple plugins for different runtimes or even directly contribute vendor specific code in the runtime.
32-
Additionally runtimes don't uniformly expose a plugin system (or even expose a plugin system at all) leading to duplication of the functionality in higher level abstractions (such as Kubernetes device plugins).
31+
On Linux, enabling a container to be device aware used to be as simple as
32+
exposing a device node in that container. However, as devices and software grows
33+
more complex, vendors want to perform more operations, such as:
34+
35+
- Exposing a device to a container can require exposing more than one device
36+
node, mounting files from the runtime namespace, or hiding procfs entries.
37+
- Performing compatibility checks between the container and the device (e.g: Can
38+
this container run on this device).
39+
- Performing runtime-specific operations (e.g: VM vs Linux containers-based
40+
runtimes).
41+
- Performing device-specific operations (e.g: scrubbing the memory of a GPU or
42+
reconfiguring an FPGA).
43+
44+
In the absence of a standard for third-party devices, vendors often have to
45+
write and maintain multiple plugins for different runtimes or even directly
46+
contribute vendor-specific code in the runtime. Additionally, runtimes don't
47+
uniformly expose a plugin system (or even expose a plugin system at all) leading
48+
to duplication of the functionality in higher-level abstractions (such as
49+
Kubernetes device plugins).
3350

3451
## How does CDI work?
3552

3653
For CDI to work the following needs to be done:
3754

38-
- CDI file containing update for the OCI spec in JSON format should be present in the CDI
39-
spec directory. Default directories are /etc/cdi and /var/run/cdi
40-
41-
- Fully qualified device name should be passed to the runtime either
42-
using command line parameters for podman or using container annotations
43-
for CRI-O and Containerd
44-
45-
- Container runtime should be able to find CDI file by the device name
46-
and update container config using CDI file content.
55+
- CDI file containing updates for the OCI spec in JSON format should be present
56+
in the CDI spec directory. Default directories are `/etc/cdi` and
57+
`/var/run/cdi`
58+
- Fully qualified device name should be passed to the runtime either using
59+
command line parameters for podman or using container annotations for CRI-O
60+
and containerd
61+
- Container runtime should be able to find the CDI file by the device name and
62+
update the container config using CDI file content.
4763

4864
## How to configure CDI?
4965

5066
### CRI-O configuration
5167

52-
In CRI-O CDI support is enabled by default. It is configured with the default `/etc/cdi, /var/run/cdi`
53-
CDI directory locations. Therefore you can start using CDI simply by dropping CDI configuration files
54-
in either of those directories, static configuration into `/etc/cdi` and dynamically updated one into
55-
`/var/run/cdi`. If you are unsure of the configured directories you can run this command to find them
56-
out:
68+
In CRI-O CDI support is enabled by default. It is configured with the default
69+
`/etc/cdi, /var/run/cdi` CDI directory locations. Therefore you can start using
70+
CDI simply by dropping CDI configuration files in either of those directories,
71+
static configuration into `/etc/cdi` and dynamically updated one into
72+
`/var/run/cdi`. If you are unsure of the configured directories you can run this
73+
command to find them out:
5774

5875
```bash
5976
$ crio config |& grep -B1 -A5 cdi_spec_dirs
6077
```
6178

6279
### Containerd configuration
6380

64-
To enable and configure CDI support in the [containerd runtime](https://github.com/containerd/containerd) 2 configuration options `enable_cdi` and `cdi_spec_dirs` should be set in the `plugins."io.containerd.grpc.v1.cri` section of the containerd configuration file (`/etc/containerd/config.toml` by default):
81+
To enable and configure CDI support in the [containerd
82+
runtime](https://github.com/containerd/containerd) 2 configuration options
83+
`enable_cdi` and `cdi_spec_dirs` should be set in the
84+
`plugins."io.containerd.grpc.v1.cri` section of the containerd configuration
85+
file (`/etc/containerd/config.toml` by default):
6586

6687
```
6788
[plugins."io.containerd.grpc.v1.cri"]
@@ -70,19 +91,29 @@ To enable and configure CDI support in the [containerd runtime](https://github.c
7091
```
7192

7293
Remember to restart containerd for any configuration changes to take effect.
73-
7494
### Podman configuration
7595

76-
[podman](https://github.com/containers/podman) does not require any specific configuration to enable CDI support and processes specified `--device` flags directly. If fully-qualified device selectors (e.g. `vendor.com/device=myDevice`) are included the CDI specifications at the default location (`/etc/cdi` and `/var/run/cdi`) are checked for matching devices.
96+
[podman](https://github.com/containers/podman) does not require any specific
97+
configuration to enable CDI support and processes specified `--device` flags
98+
directly. If fully-qualified device selectors (e.g.
99+
`vendor.com/device=myDevice`) are included the CDI specifications at the default
100+
location (`/etc/cdi` and `/var/run/cdi`) are checked for matching devices.
77101

78-
*Note:* Although initial support was added in [`v3.2.0`](https://github.com/containers/podman/releases/tag/v3.2.0) this was updated for the tagged `v0.3.0` CDI spec in [`v4.1.0-rc.1`](https://github.com/containers/podman/releases/tag/v4.1.0-rc1) with [commit a234e4e](https://github.com/containers/podman/commit/a234e4e19662e172472877ce69523f4afea5c12e).
102+
*Note:* Although initial support was added in
103+
[`v3.2.0`](https://github.com/containers/podman/releases/tag/v3.2.0) this was
104+
updated for the tagged `v0.3.0` CDI spec in
105+
[`v4.1.0-rc.1`](https://github.com/containers/podman/releases/tag/v4.1.0-rc1)
106+
with [commit
107+
a234e4e](https://github.com/containers/podman/commit/a234e4e19662e172472877ce69523f4afea5c12e).
79108

80109
## Examples
110+
### Full-blown CDI specification
111+
81112
```bash
82113
$ mkdir /etc/cdi
83114
$ cat > /etc/cdi/vendor.json <<EOF
84115
{
85-
"cdiVersion": "0.5.0",
116+
"cdiVersion": "0.6.0",
86117
"kind": "vendor.com/device",
87118
"devices": [
88119
{
@@ -117,16 +148,46 @@ $ cat > /etc/cdi/vendor.json <<EOF
117148
EOF
118149
```
119150

120-
Assuming this specification has been generated and is available in either `/etc/cdi` or `/var/run/cdi` (or whereever a CDI-enabled consumer is configured to read CDI specifications from), the devices can be accessed through their fully-qualified device names.
151+
Assuming this specification has been generated and is available in either
152+
`/etc/cdi` or `/var/run/cdi` (or whereever a CDI-enabled consumer is configured
153+
to read CDI specifications from), the devices can be accessed through their
154+
fully-qualified device names.
121155

122156
For example, in the case of `podman` the CLI for accessing the device would be:
123157
```
124158
$ podman run --device vendor.com/device=myDevice ...
125159
```
126160

161+
### Using Annotations per device to add meta-information
162+
163+
```bash
164+
$ mkdir /etc/cdi
165+
$ cat > /etc/cdi/vendor-annotations.json <<EOF
166+
{
167+
"cdiVersion": "0.6.0",
168+
"kind": "vendor.com/device",
169+
"devices": [
170+
{
171+
"name": "myDevice",
172+
"annotations": {
173+
"whatever": "false"
174+
"whenever": "true"
175+
}
176+
"containerEdits": {
177+
"deviceNodes": [
178+
{"path": "/dev/vfio/71"}
179+
]
180+
}
181+
}
182+
]
183+
}
184+
EOF
185+
```
186+
187+
127188
## Issues and Contributing
128189

129-
[Checkout the Contributing document!](CONTRIBUTING.md)
190+
[Check out the Contributing document!](CONTRIBUTING.md)
130191

131192
* Please let us know by [filing a new issue](https://github.com/container-orchestrated-devices/container-device-interface/issues/new)
132193
* You can contribute by opening a [pull request](https://help.github.com/articles/using-pull-requests/)

SPEC.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
## Version
1010

11-
This is CDI **spec** version **0.5.0**.
11+
This is CDI **spec** version **0.6.0**.
1212

1313
### Update policy
1414

@@ -26,6 +26,7 @@ Released versions of the spec are available as Git tags.
2626
| v0.3.0 | | Initial tagged release of Spec |
2727
| v0.4.0 | | Added `type` field to Mount specification |
2828
| v0.5.0 | | Add `HostPath` to `DeviceNodes` |
29+
| v0.6.0 | | Add `Annotations` field to `Spec` and `Device` specifications |
2930

3031
*Note*: The initial release of a **spec** with version `v0.x.0` will be tagged as
3132
`v0.x.0` with subsequent changes to the API applicable to this version tagged as `v0.x.y`.
@@ -80,13 +81,25 @@ The key words "must", "must not", "required", "shall", "shall not", "should", "s
8081

8182
```
8283
{
83-
"cdiVersion": "0.5.0",
84+
"cdiVersion": "0.6.0",
8485
"kind": "<name>",
8586
87+
// This field contains a set of key-value pairs that may be used to provide
88+
// additional information to a consumer on the spec.
89+
"annotations": { (optional)
90+
"key": "value"
91+
},
92+
8693
"devices": [
8794
{
8895
"name": "<name>",
8996
97+
// This field contains a set of key-value pairs that may be used to provide
98+
// additional information to a consumer on the specific device.
99+
"annotations": { (optional)
100+
"key": "value"
101+
},
102+
90103
// Same as the below containerSpec field.
91104
// This field should only be applied to the Container's OCI spec
92105
// if that specific device is requested.

internal/validation/k8s/objectmeta.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
Copyright 2014 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Adapted from k8s.io/apimachinery/pkg/api/validation:
18+
// https://github.com/kubernetes/apimachinery/blob/7687996c715ee7d5c8cf1e3215e607eb065a4221/pkg/api/validation/objectmeta.go
19+
20+
package k8s
21+
22+
import (
23+
"fmt"
24+
"strings"
25+
26+
"github.com/container-orchestrated-devices/container-device-interface/internal/multierror"
27+
)
28+
29+
// TotalAnnotationSizeLimitB defines the maximum size of all annotations in characters.
30+
const TotalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
31+
32+
// ValidateAnnotations validates that a set of annotations are correctly defined.
33+
func ValidateAnnotations(annotations map[string]string, path string) error {
34+
errors := multierror.New()
35+
for k := range annotations {
36+
// The rule is QualifiedName except that case doesn't matter, so convert to lowercase before checking.
37+
for _, msg := range IsQualifiedName(strings.ToLower(k)) {
38+
errors = multierror.Append(errors, fmt.Errorf("%v.%v is invalid: %v", path, k, msg))
39+
}
40+
}
41+
if err := ValidateAnnotationsSize(annotations); err != nil {
42+
errors = multierror.Append(errors, fmt.Errorf("%v is too long: %v", path, err))
43+
}
44+
return errors
45+
}
46+
47+
// ValidateAnnotationsSize validates that a set of annotations is not too large.
48+
func ValidateAnnotationsSize(annotations map[string]string) error {
49+
var totalSize int64
50+
for k, v := range annotations {
51+
totalSize += (int64)(len(k)) + (int64)(len(v))
52+
}
53+
if totalSize > (int64)(TotalAnnotationSizeLimitB) {
54+
return fmt.Errorf("annotations size %d is larger than limit %d", totalSize, TotalAnnotationSizeLimitB)
55+
}
56+
return nil
57+
}

0 commit comments

Comments
 (0)