Skip to content

Commit ee12044

Browse files
authored
Merge pull request #43 from klihub/devel/crio-integration
devel: better support for runtime integration
2 parents 44b2a85 + 10f8f04 commit ee12044

File tree

11 files changed

+1324
-79
lines changed

11 files changed

+1324
-79
lines changed

go.mod

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,25 @@ module github.com/container-orchestrated-devices/container-device-interface
33
go 1.14
44

55
require (
6-
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
76
github.com/blang/semver v3.5.1+incompatible // indirect
8-
github.com/coreos/etcd v3.3.10+incompatible // indirect
9-
github.com/coreos/go-etcd v2.0.0+incompatible // indirect
10-
github.com/cpuguy83/go-md2man v1.0.10 // indirect
11-
github.com/davecgh/go-spew v1.1.1 // indirect
7+
github.com/checkpoint-restore/go-criu/v5 v5.3.0 // indirect
8+
github.com/cilium/ebpf v0.7.0 // indirect
9+
github.com/containerd/console v1.0.3 // indirect
10+
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
1211
github.com/fsnotify/fsnotify v1.5.1 // indirect
13-
github.com/hashicorp/go-multierror v1.1.1 // indirect
14-
github.com/mitchellh/go-homedir v1.1.0 // indirect
15-
github.com/opencontainers/runtime-spec v1.0.2
16-
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e // indirect
12+
github.com/godbus/dbus/v5 v5.0.6 // indirect
13+
github.com/hashicorp/go-multierror v1.1.1
14+
github.com/moby/sys/mountinfo v0.5.0 // indirect
15+
github.com/opencontainers/runc v1.0.3
16+
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
17+
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e
1718
github.com/opencontainers/selinux v1.10.0 // indirect
18-
github.com/pkg/errors v0.9.1 // indirect
19-
github.com/sirupsen/logrus v1.8.1 // indirect
20-
github.com/spf13/cobra v1.2.1 // indirect
21-
github.com/spf13/viper v1.8.1 // indirect
19+
github.com/pkg/errors v0.9.1
20+
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921 // indirect
21+
github.com/spf13/cobra v1.2.1
2222
github.com/stretchr/testify v1.7.0
23-
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
24-
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 // indirect
2523
github.com/xeipuuv/gojsonschema v1.2.0
26-
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 // indirect
27-
gopkg.in/fsnotify.v1 v1.4.7 // indirect
28-
gopkg.in/yaml.v2 v2.4.0 // indirect
29-
sigs.k8s.io/yaml v1.3.0 // indirect
24+
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c // indirect
25+
gopkg.in/fsnotify.v1 v1.4.7
26+
sigs.k8s.io/yaml v1.3.0
3027
)

go.sum

Lines changed: 61 additions & 28 deletions
Large diffs are not rendered by default.

pkg/cdi/annotations.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
Copyright © 2021-2022 The CDI 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+
package cdi
18+
19+
import (
20+
"strings"
21+
22+
"github.com/pkg/errors"
23+
)
24+
25+
const (
26+
// AnnotationPrefix is the prefix for CDI container annotation keys.
27+
AnnotationPrefix = "cdi.k8s.io/"
28+
)
29+
30+
// UpdateAnnotations updates annotations with a plugin-specific CDI device
31+
// injection request for the given devices. Upon any error a non-nil error
32+
// is returned and annotations are left intact. By convention plugin should
33+
// be in the format of "vendor.device-type".
34+
func UpdateAnnotations(annotations map[string]string, plugin string, deviceID string, devices []string) (map[string]string, error) {
35+
key, err := AnnotationKey(plugin, deviceID)
36+
if err != nil {
37+
return annotations, errors.Wrap(err, "CDI annotation failed")
38+
}
39+
if _, ok := annotations[key]; ok {
40+
return annotations, errors.Errorf("CDI annotation failed, key %q used", key)
41+
}
42+
value, err := AnnotationValue(devices)
43+
if err != nil {
44+
return annotations, errors.Wrap(err, "CDI annotation failed")
45+
}
46+
47+
if annotations == nil {
48+
annotations = make(map[string]string)
49+
}
50+
annotations[key] = value
51+
52+
return annotations, nil
53+
}
54+
55+
// ParseAnnotations parses annotations for CDI device injection requests.
56+
// The keys and devices from all such requests are collected into slices
57+
// which are returned as the result. All devices are expected to be fully
58+
// qualified CDI device names. If any device fails this check empty slices
59+
// are returned along with a non-nil error. The annotations are expected
60+
// to be formatted by, or in a compatible fashion to UpdateAnnotations().
61+
func ParseAnnotations(annotations map[string]string) ([]string, []string, error) {
62+
var (
63+
keys []string
64+
devices []string
65+
)
66+
67+
for key, value := range annotations {
68+
if !strings.HasPrefix(key, AnnotationPrefix) {
69+
continue
70+
}
71+
for _, d := range strings.Split(value, ",") {
72+
if !IsQualifiedName(d) {
73+
return nil, nil, errors.Errorf("invalid CDI device name %q", d)
74+
}
75+
devices = append(devices, d)
76+
}
77+
keys = append(keys, key)
78+
}
79+
80+
return keys, devices, nil
81+
}
82+
83+
// AnnotationKey returns a unique annotation key for an device allocation
84+
// by a K8s device plugin. pluginName should be in the format of
85+
// "vendor.device-type". deviceID is the ID of the device the plugin is
86+
// allocating. It is used to make sure that the generated key is unique
87+
// even if multiple allocations by a single plugin needs to be annotated.
88+
func AnnotationKey(pluginName, deviceID string) (string, error) {
89+
const maxNameLen = 63
90+
91+
if pluginName == "" {
92+
return "", errors.New("invalid plugin name, empty")
93+
}
94+
if deviceID == "" {
95+
return "", errors.New("invalid deviceID, empty")
96+
}
97+
98+
name := pluginName + "_" + strings.ReplaceAll(deviceID, "/", "_")
99+
100+
if len(name) > maxNameLen {
101+
return "", errors.Errorf("invalid plugin+deviceID %q, too long", name)
102+
}
103+
104+
if c := rune(name[0]); !isAlphaNumeric(c) {
105+
return "", errors.Errorf("invalid name %q, first '%c' should be alphanumeric",
106+
name, c)
107+
}
108+
if len(name) > 2 {
109+
for _, c := range name[1 : len(name)-1] {
110+
switch {
111+
case isAlphaNumeric(c):
112+
case c == '_' || c == '-' || c == '.':
113+
default:
114+
return "", errors.Errorf("invalid name %q, invalid charcter '%c'",
115+
name, c)
116+
}
117+
}
118+
}
119+
if c := rune(name[len(name)-1]); !isAlphaNumeric(c) {
120+
return "", errors.Errorf("invalid name %q, last '%c' should be alphanumeric",
121+
name, c)
122+
}
123+
124+
return AnnotationPrefix + name, nil
125+
}
126+
127+
// AnnotationValue returns an annotation value for the given devices.
128+
func AnnotationValue(devices []string) (string, error) {
129+
value, sep := "", ""
130+
for _, d := range devices {
131+
if _, _, _, err := ParseQualifiedName(d); err != nil {
132+
return "", err
133+
}
134+
value += sep + d
135+
sep = ","
136+
}
137+
138+
return value, nil
139+
}

0 commit comments

Comments
 (0)