Merge pull request #47706 from elezar/bump-container-device-interface

Update tags.cncf.io/container-device-interface to v0.7.1
This commit is contained in:
Sebastiaan van Stijn 2024-04-16 15:46:49 +02:00 committed by GitHub
commit b7c059886c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 272 additions and 140 deletions

View file

@ -110,7 +110,7 @@ require (
google.golang.org/protobuf v1.33.0 google.golang.org/protobuf v1.33.0
gotest.tools/v3 v3.5.1 gotest.tools/v3 v3.5.1
resenje.org/singleflight v0.4.1 resenje.org/singleflight v0.4.1
tags.cncf.io/container-device-interface v0.6.2 tags.cncf.io/container-device-interface v0.7.1
) )
require ( require (
@ -228,5 +228,5 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.90.1 // indirect k8s.io/klog/v2 v2.90.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect
tags.cncf.io/container-device-interface/specs-go v0.6.0 // indirect tags.cncf.io/container-device-interface/specs-go v0.7.0 // indirect
) )

View file

@ -1106,7 +1106,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
tags.cncf.io/container-device-interface v0.6.2 h1:dThE6dtp/93ZDGhqaED2Pu374SOeUkBfuvkLuiTdwzg= tags.cncf.io/container-device-interface v0.7.1 h1:MATNCbAD1su9U6zwQe5BrQ2vGGp1GBayD70bYaxYCNE=
tags.cncf.io/container-device-interface v0.6.2/go.mod h1:Shusyhjs1A5Na/kqPVLL0KqnHQHuunol9LFeUNkuGVE= tags.cncf.io/container-device-interface v0.7.1/go.mod h1:h1JVuOqTQVORp8DziaWKUCDNzAmN+zeCbqbqD30D0ZQ=
tags.cncf.io/container-device-interface/specs-go v0.6.0 h1:V+tJJN6dqu8Vym6p+Ru+K5mJ49WL6Aoc5SJFSY0RLsQ= tags.cncf.io/container-device-interface/specs-go v0.7.0 h1:w/maMGVeLP6TIQJVYT5pbqTi8SCw/iHZ+n4ignuGHqg=
tags.cncf.io/container-device-interface/specs-go v0.6.0/go.mod h1:hMAwAbMZyBLdmYqWgYcKH0F/yctNpV3P35f+/088A80= tags.cncf.io/container-device-interface/specs-go v0.7.0/go.mod h1:hMAwAbMZyBLdmYqWgYcKH0F/yctNpV3P35f+/088A80=

7
vendor/modules.txt vendored
View file

@ -1600,13 +1600,12 @@ resenje.org/singleflight
# sigs.k8s.io/yaml v1.3.0 # sigs.k8s.io/yaml v1.3.0
## explicit; go 1.12 ## explicit; go 1.12
sigs.k8s.io/yaml sigs.k8s.io/yaml
# tags.cncf.io/container-device-interface v0.6.2 # tags.cncf.io/container-device-interface v0.7.1
## explicit; go 1.19 ## explicit; go 1.20
tags.cncf.io/container-device-interface/internal/multierror
tags.cncf.io/container-device-interface/internal/validation tags.cncf.io/container-device-interface/internal/validation
tags.cncf.io/container-device-interface/internal/validation/k8s tags.cncf.io/container-device-interface/internal/validation/k8s
tags.cncf.io/container-device-interface/pkg/cdi tags.cncf.io/container-device-interface/pkg/cdi
tags.cncf.io/container-device-interface/pkg/parser tags.cncf.io/container-device-interface/pkg/parser
# tags.cncf.io/container-device-interface/specs-go v0.6.0 # tags.cncf.io/container-device-interface/specs-go v0.7.0
## explicit; go 1.19 ## explicit; go 1.19
tags.cncf.io/container-device-interface/specs-go tags.cncf.io/container-device-interface/specs-go

View file

@ -1,82 +0,0 @@
/*
Copyright © 2022 The CDI Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package multierror
import (
"strings"
)
// New combines several errors into a single error. Parameters that are nil are
// ignored. If no errors are passed in or all parameters are nil, then the
// result is also nil.
func New(errors ...error) error {
// Filter out nil entries.
numErrors := 0
for _, err := range errors {
if err != nil {
errors[numErrors] = err
numErrors++
}
}
if numErrors == 0 {
return nil
}
return multiError(errors[0:numErrors])
}
// multiError is the underlying implementation used by New.
//
// Beware that a null multiError is not the same as a nil error.
type multiError []error
// multiError returns all individual error strings concatenated with "\n"
func (e multiError) Error() string {
var builder strings.Builder
for i, err := range e {
if i > 0 {
_, _ = builder.WriteString("\n")
}
_, _ = builder.WriteString(err.Error())
}
return builder.String()
}
// Append returns a new multi error all errors concatenated. Errors that are
// multi errors get flattened, nil is ignored.
func Append(err error, errors ...error) error {
var result multiError
if m, ok := err.(multiError); ok {
result = m
} else if err != nil {
result = append(result, err)
}
for _, e := range errors {
if e == nil {
continue
}
if m, ok := e.(multiError); ok {
result = append(result, m...)
} else {
result = append(result, e)
}
}
if len(result) == 0 {
return nil
}
return result
}

View file

@ -20,10 +20,9 @@ limitations under the License.
package k8s package k8s
import ( import (
"errors"
"fmt" "fmt"
"strings" "strings"
"tags.cncf.io/container-device-interface/internal/multierror"
) )
// TotalAnnotationSizeLimitB defines the maximum size of all annotations in characters. // TotalAnnotationSizeLimitB defines the maximum size of all annotations in characters.
@ -31,17 +30,17 @@ const TotalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
// ValidateAnnotations validates that a set of annotations are correctly defined. // ValidateAnnotations validates that a set of annotations are correctly defined.
func ValidateAnnotations(annotations map[string]string, path string) error { func ValidateAnnotations(annotations map[string]string, path string) error {
errors := multierror.New() errs := []error{}
for k := range annotations { for k := range annotations {
// The rule is QualifiedName except that case doesn't matter, so convert to lowercase before checking. // The rule is QualifiedName except that case doesn't matter, so convert to lowercase before checking.
for _, msg := range IsQualifiedName(strings.ToLower(k)) { for _, msg := range IsQualifiedName(strings.ToLower(k)) {
errors = multierror.Append(errors, fmt.Errorf("%v.%v is invalid: %v", path, k, msg)) errs = append(errs, fmt.Errorf("%v.%v is invalid: %v", path, k, msg))
} }
} }
if err := ValidateAnnotationsSize(annotations); err != nil { if err := ValidateAnnotationsSize(annotations); err != nil {
errors = multierror.Append(errors, fmt.Errorf("%v is too long: %v", path, err)) errs = append(errs, fmt.Errorf("%v is too long: %v", path, err))
} }
return errors return errors.Join(errs...)
} }
// ValidateAnnotationsSize validates that a set of annotations is not too large. // ValidateAnnotationsSize validates that a set of annotations is not too large.

View file

@ -28,12 +28,11 @@ import (
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
oci "github.com/opencontainers/runtime-spec/specs-go" oci "github.com/opencontainers/runtime-spec/specs-go"
"tags.cncf.io/container-device-interface/internal/multierror"
cdi "tags.cncf.io/container-device-interface/specs-go" cdi "tags.cncf.io/container-device-interface/specs-go"
) )
// Option is an option to change some aspect of default CDI behavior. // Option is an option to change some aspect of default CDI behavior.
type Option func(*Cache) error type Option func(*Cache)
// Cache stores CDI Specs loaded from Spec directories. // Cache stores CDI Specs loaded from Spec directories.
type Cache struct { type Cache struct {
@ -54,16 +53,27 @@ type Cache struct {
// is detected. This option can be used to disable this behavior when a // is detected. This option can be used to disable this behavior when a
// manually refreshed mode is preferable. // manually refreshed mode is preferable.
func WithAutoRefresh(autoRefresh bool) Option { func WithAutoRefresh(autoRefresh bool) Option {
return func(c *Cache) error { return func(c *Cache) {
c.autoRefresh = autoRefresh c.autoRefresh = autoRefresh
return nil
} }
} }
// NewCache creates a new CDI Cache. The cache is populated from a set // NewCache creates a new CDI Cache. The cache is populated from a set
// of CDI Spec directories. These can be specified using a WithSpecDirs // of CDI Spec directories. These can be specified using a WithSpecDirs
// option. The default set of directories is exposed in DefaultSpecDirs. // option. The default set of directories is exposed in DefaultSpecDirs.
//
// Note:
//
// The error returned by this function is always nil and it is only
// returned to maintain API compatibility with consumers.
func NewCache(options ...Option) (*Cache, error) { func NewCache(options ...Option) (*Cache, error) {
return newCache(options...), nil
}
// newCache creates a CDI cache with the supplied options.
// This function allows testing without handling the nil error returned by the
// NewCache function.
func newCache(options ...Option) *Cache {
c := &Cache{ c := &Cache{
autoRefresh: true, autoRefresh: true,
watch: &watch{}, watch: &watch{},
@ -73,7 +83,8 @@ func NewCache(options ...Option) (*Cache, error) {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
return c, c.configure(options...) c.configure(options...)
return c
} }
// Configure applies options to the Cache. Updates and refreshes the // Configure applies options to the Cache. Updates and refreshes the
@ -86,18 +97,16 @@ func (c *Cache) Configure(options ...Option) error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
return c.configure(options...) c.configure(options...)
return nil
} }
// Configure the Cache. Start/stop CDI Spec directory watch, refresh // Configure the Cache. Start/stop CDI Spec directory watch, refresh
// the Cache if necessary. // the Cache if necessary.
func (c *Cache) configure(options ...Option) error { func (c *Cache) configure(options ...Option) {
var err error
for _, o := range options { for _, o := range options {
if err = o(c); err != nil { o(c)
return fmt.Errorf("failed to apply cache options: %w", err)
}
} }
c.dirErrors = make(map[string]error) c.dirErrors = make(map[string]error)
@ -108,8 +117,6 @@ func (c *Cache) configure(options ...Option) error {
c.watch.start(&c.Mutex, c.refresh, c.dirErrors) c.watch.start(&c.Mutex, c.refresh, c.dirErrors)
} }
c.refresh() c.refresh()
return nil
} }
// Refresh rescans the CDI Spec directories and refreshes the Cache. // Refresh rescans the CDI Spec directories and refreshes the Cache.
@ -125,11 +132,11 @@ func (c *Cache) Refresh() error {
} }
// collect and return cached errors, much like refresh() does it // collect and return cached errors, much like refresh() does it
var result error errs := []error{}
for _, errors := range c.errors { for _, specErrs := range c.errors {
result = multierror.Append(result, errors...) errs = append(errs, errors.Join(specErrs...))
} }
return result return errors.Join(errs...)
} }
// Refresh the Cache by rescanning CDI Spec directories and files. // Refresh the Cache by rescanning CDI Spec directories and files.
@ -139,12 +146,10 @@ func (c *Cache) refresh() error {
devices = map[string]*Device{} devices = map[string]*Device{}
conflicts = map[string]struct{}{} conflicts = map[string]struct{}{}
specErrors = map[string][]error{} specErrors = map[string][]error{}
result []error
) )
// collect errors per spec file path and once globally // collect errors per spec file path and once globally
collectError := func(err error, paths ...string) { collectError := func(err error, paths ...string) {
result = append(result, err)
for _, path := range paths { for _, path := range paths {
specErrors[path] = append(specErrors[path], err) specErrors[path] = append(specErrors[path], err)
} }
@ -197,7 +202,11 @@ func (c *Cache) refresh() error {
c.devices = devices c.devices = devices
c.errors = specErrors c.errors = specErrors
return multierror.New(result...) errs := []error{}
for _, specErrs := range specErrors {
errs = append(errs, errors.Join(specErrs...))
}
return errors.Join(errs...)
} }
// RefreshIfRequired triggers a refresh if necessary. // RefreshIfRequired triggers a refresh if necessary.

View file

@ -144,6 +144,20 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
} }
} }
if e.IntelRdt != nil {
// The specgen is missing functionality to set all parameters so we
// just piggy-back on it to initialize all structs and the copy over.
specgen.SetLinuxIntelRdtClosID(e.IntelRdt.ClosID)
spec.Linux.IntelRdt = e.IntelRdt.ToOCI()
}
for _, additionalGID := range e.AdditionalGIDs {
if additionalGID == 0 {
continue
}
specgen.AddProcessAdditionalGid(additionalGID)
}
return nil return nil
} }
@ -171,6 +185,11 @@ func (e *ContainerEdits) Validate() error {
return err return err
} }
} }
if e.IntelRdt != nil {
if err := ValidateIntelRdt(e.IntelRdt); err != nil {
return err
}
}
return nil return nil
} }
@ -192,6 +211,10 @@ func (e *ContainerEdits) Append(o *ContainerEdits) *ContainerEdits {
e.DeviceNodes = append(e.DeviceNodes, o.DeviceNodes...) e.DeviceNodes = append(e.DeviceNodes, o.DeviceNodes...)
e.Hooks = append(e.Hooks, o.Hooks...) e.Hooks = append(e.Hooks, o.Hooks...)
e.Mounts = append(e.Mounts, o.Mounts...) e.Mounts = append(e.Mounts, o.Mounts...)
if o.IntelRdt != nil {
e.IntelRdt = o.IntelRdt
}
e.AdditionalGIDs = append(e.AdditionalGIDs, o.AdditionalGIDs...)
return e return e
} }
@ -202,7 +225,25 @@ func (e *ContainerEdits) isEmpty() bool {
if e == nil { if e == nil {
return false return false
} }
return len(e.Env)+len(e.DeviceNodes)+len(e.Hooks)+len(e.Mounts) == 0 if len(e.Env) > 0 {
return false
}
if len(e.DeviceNodes) > 0 {
return false
}
if len(e.Hooks) > 0 {
return false
}
if len(e.Mounts) > 0 {
return false
}
if len(e.AdditionalGIDs) > 0 {
return false
}
if e.IntelRdt != nil {
return false
}
return true
} }
// ValidateEnv validates the given environment variables. // ValidateEnv validates the given environment variables.
@ -280,6 +321,15 @@ func (m *Mount) Validate() error {
return nil return nil
} }
// ValidateIntelRdt validates the IntelRdt configuration.
func ValidateIntelRdt(i *specs.IntelRdt) error {
// ClosID must be a valid Linux filename
if len(i.ClosID) >= 4096 || i.ClosID == "." || i.ClosID == ".." || strings.ContainsAny(i.ClosID, "/\n") {
return errors.New("invalid ClosID")
}
return nil
}
// Ensure OCI Spec hooks are not nil so we can add hooks. // Ensure OCI Spec hooks are not nil so we can add hooks.
func ensureOCIHooks(spec *oci.Spec) { func ensureOCIHooks(spec *oci.Spec) {
if spec.Hooks == nil { if spec.Hooks == nil {

View file

@ -0,0 +1,70 @@
/*
Copyright © 2024 The CDI Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cdi
import (
"sync"
oci "github.com/opencontainers/runtime-spec/specs-go"
)
var (
defaultCache *Cache
getDefaultOnce sync.Once
)
func getOrCreateDefaultCache(options ...Option) (*Cache, bool) {
var created bool
getDefaultOnce.Do(func() {
defaultCache = newCache(options...)
created = true
})
return defaultCache, created
}
// GetDefaultCache returns the default CDI cache instance.
func GetDefaultCache() *Cache {
cache, _ := getOrCreateDefaultCache()
return cache
}
// Configure applies options to the default CDI cache. Updates and refreshes
// the default cache if options are not empty.
func Configure(options ...Option) error {
cache, created := getOrCreateDefaultCache(options...)
if len(options) == 0 || created {
return nil
}
return cache.Configure(options...)
}
// Refresh explicitly refreshes the default CDI cache instance.
func Refresh() error {
return GetDefaultCache().Refresh()
}
// InjectDevices injects the given qualified devices to the given OCI Spec.
// using the default CDI cache instance to resolve devices.
func InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, error) {
return GetDefaultCache().InjectDevices(ociSpec, devices...)
}
// GetErrors returns all errors encountered during the last refresh of
// the default CDI cache instance.
func GetErrors() map[string][]error {
return GetDefaultCache().GetErrors()
}

View file

@ -29,8 +29,22 @@
// the vast majority of CDI consumers need. The API should be usable both // the vast majority of CDI consumers need. The API should be usable both
// by OCI runtime clients and runtime implementations. // by OCI runtime clients and runtime implementations.
// //
// # Default CDI Cache
//
// There is a default CDI cache instance which is always implicitly
// available and instantiated the first time it is referenced directly
// or indirectly. The most frequently used cache functions are available
// as identically named package level functions which operate on the
// default cache instance. Moreover, the registry also operates on the
// same default cache. We plan to deprecate the registry and eventually
// remove it in a future release.
//
// # CDI Registry // # CDI Registry
// //
// Note: the Registry and its related interfaces are deprecated and will
// be removed in a future version. Please use the default cache and its
// related package-level function instead.
//
// The primary interface to interact with CDI devices is the Registry. It // The primary interface to interact with CDI devices is the Registry. It
// is essentially a cache of all Specs and devices discovered in standard // is essentially a cache of all Specs and devices discovered in standard
// CDI directories on the host. The registry has two main functionality, // CDI directories on the host. The registry has two main functionality,

View file

@ -29,6 +29,11 @@ import (
// //
// The most commonly used Registry functions are for refreshing the // The most commonly used Registry functions are for refreshing the
// registry and injecting CDI devices into an OCI Spec. // registry and injecting CDI devices into an OCI Spec.
//
// Deprecated: Registry is deprecated and will be removed in a future
// version. Please update your code to use the corresponding package-
// level functions Configure(), Refresh(), InjectDevices(), GetErrors(),
// and GetDefaultCache().
type Registry interface { type Registry interface {
RegistryResolver RegistryResolver
RegistryRefresher RegistryRefresher
@ -54,6 +59,10 @@ type Registry interface {
// //
// GetSpecDirErrors returns any errors related to the configured // GetSpecDirErrors returns any errors related to the configured
// Spec directories. // Spec directories.
//
// Deprecated: RegistryRefresher is deprecated and will be removed
// in a future version. Please use the default cache and its related
// package-level functions instead.
type RegistryRefresher interface { type RegistryRefresher interface {
Configure(...Option) error Configure(...Option) error
Refresh() error Refresh() error
@ -68,6 +77,10 @@ type RegistryRefresher interface {
// InjectDevices takes an OCI Spec and injects into it a set of // InjectDevices takes an OCI Spec and injects into it a set of
// CDI devices given by qualified name. It returns the names of // CDI devices given by qualified name. It returns the names of
// any unresolved devices and an error if injection fails. // any unresolved devices and an error if injection fails.
//
// Deprecated: RegistryRefresher is deprecated and will be removed
// in a future version. Please use the default cache and its related
// package-level functions instead.
type RegistryResolver interface { type RegistryResolver interface {
InjectDevices(spec *oci.Spec, device ...string) (unresolved []string, err error) InjectDevices(spec *oci.Spec, device ...string) (unresolved []string, err error)
} }
@ -79,6 +92,12 @@ type RegistryResolver interface {
// //
// ListDevices returns a slice with the names of qualified device // ListDevices returns a slice with the names of qualified device
// known. The returned slice is sorted. // known. The returned slice is sorted.
//
// Deprecated: RegistryDeviceDB is deprecated and will be removed
// in a future version. Please use the default cache and its related
// package-level functions instead.
// and will be removed in a future version. Please use the default
// cache and its related package-level functions instead.
type RegistryDeviceDB interface { type RegistryDeviceDB interface {
GetDevice(device string) *Device GetDevice(device string) *Device
ListDevices() []string ListDevices() []string
@ -99,6 +118,10 @@ type RegistryDeviceDB interface {
// //
// WriteSpec writes the Spec with the given content and name to the // WriteSpec writes the Spec with the given content and name to the
// last Spec directory. // last Spec directory.
//
// Deprecated: RegistrySpecDB is deprecated and will be removed
// in a future version. Please use the default cache and its related
// package-level functions instead.
type RegistrySpecDB interface { type RegistrySpecDB interface {
ListVendors() []string ListVendors() []string
ListClasses() []string ListClasses() []string
@ -121,30 +144,35 @@ var (
// GetRegistry returns the CDI registry. If any options are given, those // GetRegistry returns the CDI registry. If any options are given, those
// are applied to the registry. // are applied to the registry.
//
// Deprecated: GetRegistry is deprecated and will be removed in a future
// version. Please use the default cache and its related package-level
// functions instead.
func GetRegistry(options ...Option) Registry { func GetRegistry(options ...Option) Registry {
var new bool
initOnce.Do(func() { initOnce.Do(func() {
reg, _ = getRegistry(options...) reg = &registry{GetDefaultCache()}
new = true
}) })
if !new && len(options) > 0 { if len(options) > 0 {
reg.Configure(options...) // We don't care about errors here
reg.Refresh() _ = reg.Configure(options...)
} }
return reg return reg
} }
// DeviceDB returns the registry interface for querying devices. // DeviceDB returns the registry interface for querying devices.
//
// Deprecated: DeviceDB is deprecated and will be removed in a future
// version. Please use the default cache and its related package-level
// functions instead.
func (r *registry) DeviceDB() RegistryDeviceDB { func (r *registry) DeviceDB() RegistryDeviceDB {
return r return r
} }
// SpecDB returns the registry interface for querying Specs. // SpecDB returns the registry interface for querying Specs.
//
// Deprecated: SpecDB is deprecated and will be removed in a future
// version. Please use the default cache and its related package-level
// functions instead.
func (r *registry) SpecDB() RegistrySpecDB { func (r *registry) SpecDB() RegistrySpecDB {
return r return r
} }
func getRegistry(options ...Option) (*registry, error) {
c, err := NewCache(options...)
return &registry{c}, err
}

View file

@ -44,13 +44,12 @@ var (
// WithSpecDirs returns an option to override the CDI Spec directories. // WithSpecDirs returns an option to override the CDI Spec directories.
func WithSpecDirs(dirs ...string) Option { func WithSpecDirs(dirs ...string) Option {
return func(c *Cache) error { return func(c *Cache) {
specDirs := make([]string, len(dirs)) specDirs := make([]string, len(dirs))
for i, dir := range dirs { for i, dir := range dirs {
specDirs[i] = filepath.Clean(dir) specDirs[i] = filepath.Clean(dir)
} }
c.specDirs = specDirs c.specDirs = specDirs
return nil
} }
} }

View file

@ -19,7 +19,6 @@ package cdi
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -62,7 +61,7 @@ type Spec struct {
// assigned the given priority. If reading or parsing the Spec // assigned the given priority. If reading or parsing the Spec
// data fails ReadSpec returns a nil Spec and an error. // data fails ReadSpec returns a nil Spec and an error.
func ReadSpec(path string, priority int) (*Spec, error) { func ReadSpec(path string, priority int) (*Spec, error) {
data, err := ioutil.ReadFile(path) data, err := os.ReadFile(path)
switch { switch {
case os.IsNotExist(err): case os.IsNotExist(err):
return nil, err return nil, err

View file

@ -39,6 +39,7 @@ const (
v040 version = "v0.4.0" v040 version = "v0.4.0"
v050 version = "v0.5.0" v050 version = "v0.5.0"
v060 version = "v0.6.0" v060 version = "v0.6.0"
v070 version = "v0.7.0"
// vEarliest is the earliest supported version of the CDI specification // vEarliest is the earliest supported version of the CDI specification
vEarliest version = v030 vEarliest version = v030
@ -54,6 +55,7 @@ var validSpecVersions = requiredVersionMap{
v040: requiresV040, v040: requiresV040,
v050: requiresV050, v050: requiresV050,
v060: requiresV060, v060: requiresV060,
v070: requiresV070,
} }
// MinimumRequiredVersion determines the minimum spec version for the input spec. // MinimumRequiredVersion determines the minimum spec version for the input spec.
@ -118,6 +120,29 @@ func (r requiredVersionMap) requiredVersion(spec *cdi.Spec) version {
return minVersion return minVersion
} }
// requiresV070 returns true if the spec uses v0.7.0 features
func requiresV070(spec *cdi.Spec) bool {
if spec.ContainerEdits.IntelRdt != nil {
return true
}
// The v0.7.0 spec allows additional GIDs to be specified at a spec level.
if len(spec.ContainerEdits.AdditionalGIDs) > 0 {
return true
}
for _, d := range spec.Devices {
if d.ContainerEdits.IntelRdt != nil {
return true
}
// The v0.7.0 spec allows additional GIDs to be specified at a device level.
if len(d.ContainerEdits.AdditionalGIDs) > 0 {
return true
}
}
return false
}
// requiresV060 returns true if the spec uses v0.6.0 features // requiresV060 returns true if the spec uses v0.6.0 features
func requiresV060(spec *cdi.Spec) bool { func requiresV060(spec *cdi.Spec) bool {
// The v0.6.0 spec allows annotations to be specified at a spec level // The v0.6.0 spec allows annotations to be specified at a spec level

View file

@ -3,7 +3,7 @@ package specs
import "os" import "os"
// CurrentVersion is the current version of the Spec. // CurrentVersion is the current version of the Spec.
const CurrentVersion = "0.6.0" const CurrentVersion = "0.7.0"
// Spec is the base configuration for CDI // Spec is the base configuration for CDI
type Spec struct { type Spec struct {
@ -29,6 +29,8 @@ type ContainerEdits struct {
DeviceNodes []*DeviceNode `json:"deviceNodes,omitempty"` DeviceNodes []*DeviceNode `json:"deviceNodes,omitempty"`
Hooks []*Hook `json:"hooks,omitempty"` Hooks []*Hook `json:"hooks,omitempty"`
Mounts []*Mount `json:"mounts,omitempty"` Mounts []*Mount `json:"mounts,omitempty"`
IntelRdt *IntelRdt `json:"intelRdt,omitempty"`
AdditionalGIDs []uint32 `json:"additionalGids,omitempty"`
} }
// DeviceNode represents a device node that needs to be added to the OCI spec. // DeviceNode represents a device node that needs to be added to the OCI spec.
@ -60,3 +62,12 @@ type Hook struct {
Env []string `json:"env,omitempty"` Env []string `json:"env,omitempty"`
Timeout *int `json:"timeout,omitempty"` Timeout *int `json:"timeout,omitempty"`
} }
// IntelRdt describes the Linux IntelRdt parameters to set in the OCI spec.
type IntelRdt struct {
ClosID string `json:"closID,omitempty"`
L3CacheSchema string `json:"l3CacheSchema,omitempty"`
MemBwSchema string `json:"memBwSchema,omitempty"`
EnableCMT bool `json:"enableCMT,omitempty"`
EnableMBM bool `json:"enableMBM,omitempty"`
}

View file

@ -36,3 +36,14 @@ func (d *DeviceNode) ToOCI() spec.LinuxDevice {
GID: d.GID, GID: d.GID,
} }
} }
// ToOCI returns the opencontainers runtime Spec LinuxIntelRdt for this IntelRdt config.
func (i *IntelRdt) ToOCI() *spec.LinuxIntelRdt {
return &spec.LinuxIntelRdt{
ClosID: i.ClosID,
L3CacheSchema: i.L3CacheSchema,
MemBwSchema: i.MemBwSchema,
EnableCMT: i.EnableCMT,
EnableMBM: i.EnableMBM,
}
}