mirror of
https://github.com/containers/podman
synced 2024-10-19 08:44:11 +00:00
build(deps): bump github.com/container-orchestrated-devices/container-device-interface
Bumps [github.com/container-orchestrated-devices/container-device-interface](https://github.com/container-orchestrated-devices/container-device-interface) from 0.4.0 to 0.5.0. - [Release notes](https://github.com/container-orchestrated-devices/container-device-interface/releases) - [Commits](https://github.com/container-orchestrated-devices/container-device-interface/compare/v0.4.0...v0.5.0) --- updated-dependencies: - dependency-name: github.com/container-orchestrated-devices/container-device-interface dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
parent
89ab5c9fab
commit
e3f029cb83
2
go.mod
2
go.mod
|
@ -8,7 +8,7 @@ require (
|
|||
github.com/buger/goterm v1.0.4
|
||||
github.com/checkpoint-restore/checkpointctl v0.0.0-20220321135231-33f4a66335f0
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.4.0
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.5.0
|
||||
github.com/containernetworking/cni v1.1.2
|
||||
github.com/containernetworking/plugins v1.1.1
|
||||
github.com/containers/buildah v1.27.0
|
||||
|
|
4
go.sum
4
go.sum
|
@ -281,8 +281,8 @@ github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h
|
|||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
||||
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.4.0 h1:b/mROkfDr1W8fJ25T66iVheHFnWixgyxTOSbO8i7jp4=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.4.0/go.mod h1:E1zcucIkq9P3eyNmY+68dBQsTcsXJh9cgRo2IVNScKQ=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.5.0 h1:BPFG0J1R8bW7z69DtG98K+/l8jsVYXD/o2fmgKXby2s=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.5.0/go.mod h1:ZToWfSyUH5l9Rk7/bjkUUkNLz4b1mE+CVUVafuikDPY=
|
||||
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
|
||||
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
|
||||
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
|
||||
|
|
292
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go
generated
vendored
292
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go
generated
vendored
|
@ -22,6 +22,8 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
cdi "github.com/container-orchestrated-devices/container-device-interface/specs-go"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
oci "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -33,30 +35,46 @@ type Option func(*Cache) error
|
|||
// Cache stores CDI Specs loaded from Spec directories.
|
||||
type Cache struct {
|
||||
sync.Mutex
|
||||
specDirs []string
|
||||
specs map[string][]*Spec
|
||||
devices map[string]*Device
|
||||
errors map[string][]error
|
||||
specDirs []string
|
||||
specs map[string][]*Spec
|
||||
devices map[string]*Device
|
||||
errors map[string][]error
|
||||
dirErrors map[string]error
|
||||
|
||||
autoRefresh bool
|
||||
watch *watch
|
||||
}
|
||||
|
||||
// WithAutoRefresh returns an option to control automatic Cache refresh.
|
||||
// By default auto-refresh is enabled, the list of Spec directories are
|
||||
// monitored and the Cache is automatically refreshed whenever a change
|
||||
// is detected. This option can be used to disable this behavior when a
|
||||
// manually refreshed mode is preferable.
|
||||
func WithAutoRefresh(autoRefresh bool) Option {
|
||||
return func(c *Cache) error {
|
||||
c.autoRefresh = autoRefresh
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewCache creates a new CDI Cache. The cache is populated from a set
|
||||
// of CDI Spec directories. These can be specified using a WithSpecDirs
|
||||
// option. The default set of directories is exposed in DefaultSpecDirs.
|
||||
func NewCache(options ...Option) (*Cache, error) {
|
||||
c := &Cache{}
|
||||
|
||||
if err := c.Configure(options...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(c.specDirs) == 0 {
|
||||
c.Configure(WithSpecDirs(DefaultSpecDirs...))
|
||||
c := &Cache{
|
||||
autoRefresh: true,
|
||||
watch: &watch{},
|
||||
}
|
||||
|
||||
return c, c.Refresh()
|
||||
WithSpecDirs(DefaultSpecDirs...)(c)
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
return c, c.configure(options...)
|
||||
}
|
||||
|
||||
// Configure applies options to the cache. Updates the cache if options have
|
||||
// changed.
|
||||
// Configure applies options to the Cache. Updates and refreshes the
|
||||
// Cache if options have changed.
|
||||
func (c *Cache) Configure(options ...Option) error {
|
||||
if len(options) == 0 {
|
||||
return nil
|
||||
|
@ -65,17 +83,54 @@ func (c *Cache) Configure(options ...Option) error {
|
|||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
return c.configure(options...)
|
||||
}
|
||||
|
||||
// Configure the Cache. Start/stop CDI Spec directory watch, refresh
|
||||
// the Cache if necessary.
|
||||
func (c *Cache) configure(options ...Option) error {
|
||||
var err error
|
||||
|
||||
for _, o := range options {
|
||||
if err := o(c); err != nil {
|
||||
if err = o(c); err != nil {
|
||||
return errors.Wrapf(err, "failed to apply cache options")
|
||||
}
|
||||
}
|
||||
|
||||
c.dirErrors = make(map[string]error)
|
||||
|
||||
c.watch.stop()
|
||||
if c.autoRefresh {
|
||||
c.watch.setup(c.specDirs, c.dirErrors)
|
||||
c.watch.start(&c.Mutex, c.refresh, c.dirErrors)
|
||||
}
|
||||
c.refresh()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Refresh rescans the CDI Spec directories and refreshes the Cache.
|
||||
// In manual refresh mode the cache is always refreshed. In auto-
|
||||
// refresh mode the cache is only refreshed if it is out of date.
|
||||
func (c *Cache) Refresh() error {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
// force a refresh in manual mode
|
||||
if refreshed, err := c.refreshIfRequired(!c.autoRefresh); refreshed {
|
||||
return err
|
||||
}
|
||||
|
||||
// collect and return cached errors, much like refresh() does it
|
||||
var result error
|
||||
for _, err := range c.errors {
|
||||
result = multierror.Append(result, err...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Refresh the Cache by rescanning CDI Spec directories and files.
|
||||
func (c *Cache) refresh() error {
|
||||
var (
|
||||
specs = map[string][]*Spec{}
|
||||
devices = map[string]*Device{}
|
||||
|
@ -135,9 +190,6 @@ func (c *Cache) Refresh() error {
|
|||
delete(devices, conflict)
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.specs = specs
|
||||
c.devices = devices
|
||||
c.errors = specErrors
|
||||
|
@ -149,6 +201,17 @@ func (c *Cache) Refresh() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RefreshIfRequired triggers a refresh if necessary.
|
||||
func (c *Cache) refreshIfRequired(force bool) (bool, error) {
|
||||
// We need to refresh if
|
||||
// - it's forced by an explicitly call to Refresh() in manual mode
|
||||
// - a missing Spec dir appears (added to watch) in auto-refresh mode
|
||||
if force || (c.autoRefresh && c.watch.update(c.dirErrors)) {
|
||||
return true, c.refresh()
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// InjectDevices injects the given qualified devices to an OCI Spec. It
|
||||
// returns any unresolvable devices and an error if injection fails for
|
||||
// any of the devices.
|
||||
|
@ -162,6 +225,8 @@ func (c *Cache) InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, e
|
|||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.refreshIfRequired(false)
|
||||
|
||||
edits := &ContainerEdits{}
|
||||
specs := map[*Spec]struct{}{}
|
||||
|
||||
|
@ -190,11 +255,46 @@ func (c *Cache) InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, e
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// WriteSpec writes a Spec file with the given content. Priority is used
|
||||
// as an index into the list of Spec directories to pick a directory for
|
||||
// the file, adjusting for any under- or overflows. If name has a "json"
|
||||
// or "yaml" extension it choses the encoding. Otherwise JSON encoding
|
||||
// is used with a "json" extension.
|
||||
func (c *Cache) WriteSpec(raw *cdi.Spec, name string) error {
|
||||
var (
|
||||
specDir string
|
||||
path string
|
||||
prio int
|
||||
spec *Spec
|
||||
err error
|
||||
)
|
||||
|
||||
if len(c.specDirs) == 0 {
|
||||
return errors.New("no Spec directories to write to")
|
||||
}
|
||||
|
||||
prio = len(c.specDirs) - 1
|
||||
specDir = c.specDirs[prio]
|
||||
path = filepath.Join(specDir, name)
|
||||
if ext := filepath.Ext(path); ext != ".json" && ext != ".yaml" {
|
||||
path += ".json"
|
||||
}
|
||||
|
||||
spec, err = NewSpec(raw, path, prio)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return spec.Write(true)
|
||||
}
|
||||
|
||||
// GetDevice returns the cached device for the given qualified name.
|
||||
func (c *Cache) GetDevice(device string) *Device {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.refreshIfRequired(false)
|
||||
|
||||
return c.devices[device]
|
||||
}
|
||||
|
||||
|
@ -205,6 +305,8 @@ func (c *Cache) ListDevices() []string {
|
|||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.refreshIfRequired(false)
|
||||
|
||||
for name := range c.devices {
|
||||
devices = append(devices, name)
|
||||
}
|
||||
|
@ -220,6 +322,8 @@ func (c *Cache) ListVendors() []string {
|
|||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.refreshIfRequired(false)
|
||||
|
||||
for vendor := range c.specs {
|
||||
vendors = append(vendors, vendor)
|
||||
}
|
||||
|
@ -238,6 +342,8 @@ func (c *Cache) ListClasses() []string {
|
|||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.refreshIfRequired(false)
|
||||
|
||||
for _, specs := range c.specs {
|
||||
for _, spec := range specs {
|
||||
cmap[spec.GetClass()] = struct{}{}
|
||||
|
@ -256,6 +362,8 @@ func (c *Cache) GetVendorSpecs(vendor string) []*Spec {
|
|||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.refreshIfRequired(false)
|
||||
|
||||
return c.specs[vendor]
|
||||
}
|
||||
|
||||
|
@ -268,12 +376,158 @@ func (c *Cache) GetSpecErrors(spec *Spec) []error {
|
|||
// GetErrors returns all errors encountered during the last
|
||||
// cache refresh.
|
||||
func (c *Cache) GetErrors() map[string][]error {
|
||||
return c.errors
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
errors := map[string][]error{}
|
||||
for path, errs := range c.errors {
|
||||
errors[path] = errs
|
||||
}
|
||||
for path, err := range c.dirErrors {
|
||||
errors[path] = []error{err}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
// GetSpecDirectories returns the CDI Spec directories currently in use.
|
||||
func (c *Cache) GetSpecDirectories() []string {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
dirs := make([]string, len(c.specDirs))
|
||||
copy(dirs, c.specDirs)
|
||||
return dirs
|
||||
}
|
||||
|
||||
// GetSpecDirErrors returns any errors related to configured Spec directories.
|
||||
func (c *Cache) GetSpecDirErrors() map[string]error {
|
||||
if c.dirErrors == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
errors := make(map[string]error)
|
||||
for dir, err := range c.dirErrors {
|
||||
errors[dir] = err
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
// Our fsnotify helper wrapper.
|
||||
type watch struct {
|
||||
watcher *fsnotify.Watcher
|
||||
tracked map[string]bool
|
||||
}
|
||||
|
||||
// Setup monitoring for the given Spec directories.
|
||||
func (w *watch) setup(dirs []string, dirErrors map[string]error) {
|
||||
var (
|
||||
dir string
|
||||
err error
|
||||
)
|
||||
w.tracked = make(map[string]bool)
|
||||
for _, dir = range dirs {
|
||||
w.tracked[dir] = false
|
||||
}
|
||||
|
||||
w.watcher, err = fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
for _, dir := range dirs {
|
||||
dirErrors[dir] = errors.Wrap(err, "failed to create watcher")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
w.update(dirErrors)
|
||||
}
|
||||
|
||||
// Start watching Spec directories for relevant changes.
|
||||
func (w *watch) start(m *sync.Mutex, refresh func() error, dirErrors map[string]error) {
|
||||
go w.watch(m, refresh, dirErrors)
|
||||
}
|
||||
|
||||
// Stop watching directories.
|
||||
func (w *watch) stop() {
|
||||
if w.watcher == nil {
|
||||
return
|
||||
}
|
||||
|
||||
w.watcher.Close()
|
||||
w.tracked = nil
|
||||
}
|
||||
|
||||
// Watch Spec directory changes, triggering a refresh if necessary.
|
||||
func (w *watch) watch(m *sync.Mutex, refresh func() error, dirErrors map[string]error) {
|
||||
watch := w.watcher
|
||||
if watch == nil {
|
||||
return
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watch.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.Op & (fsnotify.Rename | fsnotify.Remove | fsnotify.Write)) == 0 {
|
||||
continue
|
||||
}
|
||||
if event.Op == fsnotify.Write {
|
||||
if ext := filepath.Ext(event.Name); ext != ".json" && ext != ".yaml" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
m.Lock()
|
||||
if event.Op == fsnotify.Remove && w.tracked[event.Name] {
|
||||
w.update(dirErrors, event.Name)
|
||||
} else {
|
||||
w.update(dirErrors)
|
||||
}
|
||||
refresh()
|
||||
m.Unlock()
|
||||
|
||||
case _, ok := <-watch.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update watch with pending/missing or removed directories.
|
||||
func (w *watch) update(dirErrors map[string]error, removed ...string) bool {
|
||||
var (
|
||||
dir string
|
||||
ok bool
|
||||
err error
|
||||
update bool
|
||||
)
|
||||
|
||||
for dir, ok = range w.tracked {
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
|
||||
err = w.watcher.Add(dir)
|
||||
if err == nil {
|
||||
w.tracked[dir] = true
|
||||
delete(dirErrors, dir)
|
||||
update = true
|
||||
} else {
|
||||
w.tracked[dir] = false
|
||||
dirErrors[dir] = errors.Wrap(err, "failed to monitor for changes")
|
||||
}
|
||||
}
|
||||
|
||||
for _, dir = range removed {
|
||||
w.tracked[dir] = false
|
||||
dirErrors[dir] = errors.New("directory removed")
|
||||
update = true
|
||||
}
|
||||
|
||||
return update
|
||||
}
|
||||
|
|
|
@ -85,11 +85,13 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
|
|||
}
|
||||
|
||||
for _, d := range e.DeviceNodes {
|
||||
dev := d.ToOCI()
|
||||
if err := fillMissingInfo(&dev); err != nil {
|
||||
dn := DeviceNode{d}
|
||||
|
||||
err := dn.fillMissingInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dev := d.ToOCI()
|
||||
if dev.UID == nil && spec.Process != nil {
|
||||
if uid := spec.Process.User.UID; uid > 0 {
|
||||
dev.UID = &uid
|
||||
|
@ -288,26 +290,31 @@ func ensureOCIHooks(spec *oci.Spec) {
|
|||
}
|
||||
|
||||
// fillMissingInfo fills in missing mandatory attributes from the host device.
|
||||
func fillMissingInfo(dev *oci.LinuxDevice) error {
|
||||
if dev.Type != "" && (dev.Major != 0 || dev.Type == "p") {
|
||||
return nil
|
||||
}
|
||||
hostDev, err := runc.DeviceFromPath(dev.Path, "rwm")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to stat CDI host device %q", dev.Path)
|
||||
func (d *DeviceNode) fillMissingInfo() error {
|
||||
if d.HostPath == "" {
|
||||
d.HostPath = d.Path
|
||||
}
|
||||
|
||||
if dev.Type == "" {
|
||||
dev.Type = string(hostDev.Type)
|
||||
if d.Type != "" && (d.Major != 0 || d.Type == "p") {
|
||||
return nil
|
||||
}
|
||||
|
||||
hostDev, err := runc.DeviceFromPath(d.HostPath, "rwm")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to stat CDI host device %q", d.HostPath)
|
||||
}
|
||||
|
||||
if d.Type == "" {
|
||||
d.Type = string(hostDev.Type)
|
||||
} else {
|
||||
if dev.Type != string(hostDev.Type) {
|
||||
return errors.Errorf("CDI device %q, host type mismatch (%s, %s)",
|
||||
dev.Path, dev.Type, string(hostDev.Type))
|
||||
if d.Type != string(hostDev.Type) {
|
||||
return errors.Errorf("CDI device (%q, %q), host type mismatch (%s, %s)",
|
||||
d.Path, d.HostPath, d.Type, string(hostDev.Type))
|
||||
}
|
||||
}
|
||||
if dev.Major == 0 && dev.Type != "p" {
|
||||
dev.Major = hostDev.Major
|
||||
dev.Minor = hostDev.Minor
|
||||
if d.Major == 0 && d.Type != "p" {
|
||||
d.Major = hostDev.Major
|
||||
d.Minor = hostDev.Minor
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -67,6 +67,21 @@
|
|||
//
|
||||
// Cache Refresh
|
||||
//
|
||||
// By default the CDI Spec cache monitors the configured Spec directories
|
||||
// and automatically refreshes itself when necessary. This behavior can be
|
||||
// disabled using the WithAutoRefresh(false) option.
|
||||
//
|
||||
// Failure to set up monitoring for a Spec directory causes the directory to
|
||||
// get ignored and an error to be recorded among the Spec directory errors.
|
||||
// These errors can be queried using the GetSpecDirErrors() function. If the
|
||||
// error condition is transient, for instance a missing directory which later
|
||||
// gets created, the corresponding error will be removed once the condition
|
||||
// is over.
|
||||
//
|
||||
// With auto-refresh enabled injecting any CDI devices can be done without
|
||||
// an explicit call to Refresh(), using a code snippet similar to the
|
||||
// following:
|
||||
//
|
||||
// In a runtime implementation one typically wants to make sure the
|
||||
// CDI Spec cache is up to date before performing device injection.
|
||||
// A code snippet similar to the following accmplishes that:
|
||||
|
@ -146,5 +161,5 @@
|
|||
// schema names which switch the used schema to the in-repo validation
|
||||
// schema embedded into the binary or the now default no-op schema
|
||||
// correspondingly. Other names are interpreted as the path to the actual
|
||||
/// validation schema to load and use.
|
||||
// validation schema to load and use.
|
||||
package cdi
|
||||
|
|
|
@ -130,7 +130,7 @@ func ValidateVendorName(vendor string) error {
|
|||
}
|
||||
}
|
||||
if !isAlphaNumeric(rune(vendor[len(vendor)-1])) {
|
||||
return errors.Errorf("invalid vendor %q, should end with letter", vendor)
|
||||
return errors.Errorf("invalid vendor %q, should end with a letter or digit", vendor)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -158,7 +158,7 @@ func ValidateClassName(class string) error {
|
|||
}
|
||||
}
|
||||
if !isAlphaNumeric(rune(class[len(class)-1])) {
|
||||
return errors.Errorf("invalid class %q, should end with letter", class)
|
||||
return errors.Errorf("invalid class %q, should end with a letter or digit", class)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -172,8 +172,11 @@ func ValidateDeviceName(name string) error {
|
|||
if name == "" {
|
||||
return errors.Errorf("invalid (empty) device name")
|
||||
}
|
||||
if !isLetter(rune(name[0])) {
|
||||
return errors.Errorf("invalid name %q, should start with letter", name)
|
||||
if !isAlphaNumeric(rune(name[0])) {
|
||||
return errors.Errorf("invalid class %q, should start with a letter or digit", name)
|
||||
}
|
||||
if len(name) == 1 {
|
||||
return nil
|
||||
}
|
||||
for _, c := range string(name[1 : len(name)-1]) {
|
||||
switch {
|
||||
|
@ -185,7 +188,7 @@ func ValidateDeviceName(name string) error {
|
|||
}
|
||||
}
|
||||
if !isAlphaNumeric(rune(name[len(name)-1])) {
|
||||
return errors.Errorf("invalid name %q, should start with letter", name)
|
||||
return errors.Errorf("invalid name %q, should end with a letter or digit", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package cdi
|
|||
import (
|
||||
"sync"
|
||||
|
||||
cdi "github.com/container-orchestrated-devices/container-device-interface/specs-go"
|
||||
oci "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
@ -40,6 +41,8 @@ type Registry interface {
|
|||
// RegistryRefresher is the registry interface for refreshing the
|
||||
// cache of CDI Specs and devices.
|
||||
//
|
||||
// Configure reconfigures the registry with the given options.
|
||||
//
|
||||
// Refresh rescans all CDI Spec directories and updates the
|
||||
// state of the cache to reflect any changes. It returns any
|
||||
// errors encountered during the refresh.
|
||||
|
@ -50,10 +53,15 @@ type Registry interface {
|
|||
// GetSpecDirectories returns the set up CDI Spec directories
|
||||
// currently in use. The directories are returned in the scan
|
||||
// order of Refresh().
|
||||
//
|
||||
// GetSpecDirErrors returns any errors related to the configured
|
||||
// Spec directories.
|
||||
type RegistryRefresher interface {
|
||||
Configure(...Option) error
|
||||
Refresh() error
|
||||
GetErrors() map[string][]error
|
||||
GetSpecDirectories() []string
|
||||
GetSpecDirErrors() map[string]error
|
||||
}
|
||||
|
||||
// RegistryResolver is the registry interface for injecting CDI
|
||||
|
@ -90,11 +98,15 @@ type RegistryDeviceDB interface {
|
|||
//
|
||||
// GetSpecErrors returns any errors for the Spec encountered during
|
||||
// the last cache refresh.
|
||||
//
|
||||
// WriteSpec writes the Spec with the given content and name to the
|
||||
// last Spec directory.
|
||||
type RegistrySpecDB interface {
|
||||
ListVendors() []string
|
||||
ListClasses() []string
|
||||
GetVendorSpecs(vendor string) []*Spec
|
||||
GetSpecErrors(*Spec) []error
|
||||
WriteSpec(raw *cdi.Spec, name string) error
|
||||
}
|
||||
|
||||
type registry struct {
|
||||
|
|
|
@ -45,10 +45,11 @@ var (
|
|||
// WithSpecDirs returns an option to override the CDI Spec directories.
|
||||
func WithSpecDirs(dirs ...string) Option {
|
||||
return func(c *Cache) error {
|
||||
c.specDirs = make([]string, len(dirs))
|
||||
specDirs := make([]string, len(dirs))
|
||||
for i, dir := range dirs {
|
||||
c.specDirs[i] = filepath.Clean(dir)
|
||||
specDirs[i] = filepath.Clean(dir)
|
||||
}
|
||||
c.specDirs = specDirs
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package cdi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -35,6 +36,7 @@ var (
|
|||
"0.2.0": {},
|
||||
"0.3.0": {},
|
||||
"0.4.0": {},
|
||||
"0.5.0": {},
|
||||
}
|
||||
|
||||
// Externally set CDI Spec validation function.
|
||||
|
@ -68,7 +70,7 @@ func ReadSpec(path string, priority int) (*Spec, error) {
|
|||
return nil, errors.Wrapf(err, "failed to read CDI Spec %q", path)
|
||||
}
|
||||
|
||||
raw, err := parseSpec(data)
|
||||
raw, err := ParseSpec(data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse CDI Spec %q", path)
|
||||
}
|
||||
|
@ -109,6 +111,56 @@ func NewSpec(raw *cdi.Spec, path string, priority int) (*Spec, error) {
|
|||
return spec, nil
|
||||
}
|
||||
|
||||
// Write the CDI Spec to the file associated with it during instantiation
|
||||
// by NewSpec() or ReadSpec().
|
||||
func (s *Spec) Write(overwrite bool) error {
|
||||
var (
|
||||
data []byte
|
||||
dir string
|
||||
tmp *os.File
|
||||
err error
|
||||
)
|
||||
|
||||
err = validateSpec(s.Spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if filepath.Ext(s.path) == ".yaml" {
|
||||
data, err = yaml.Marshal(s.Spec)
|
||||
} else {
|
||||
data, err = json.Marshal(s.Spec)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to marshal Spec file")
|
||||
}
|
||||
|
||||
dir = filepath.Dir(s.path)
|
||||
err = os.MkdirAll(dir, 0o755)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create Spec dir")
|
||||
}
|
||||
|
||||
tmp, err = os.CreateTemp(dir, "spec.*.tmp")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create Spec file")
|
||||
}
|
||||
_, err = tmp.Write(data)
|
||||
tmp.Close()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write Spec file")
|
||||
}
|
||||
|
||||
err = renameIn(dir, filepath.Base(tmp.Name()), filepath.Base(s.path), overwrite)
|
||||
|
||||
if err != nil {
|
||||
os.Remove(tmp.Name())
|
||||
err = errors.Wrap(err, "failed to write Spec file")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// GetVendor returns the vendor of this Spec.
|
||||
func (s *Spec) GetVendor() string {
|
||||
return s.vendor
|
||||
|
@ -183,8 +235,8 @@ func validateVersion(version string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Parse raw CDI Spec file data.
|
||||
func parseSpec(data []byte) (*cdi.Spec, error) {
|
||||
// ParseSpec parses CDI Spec data into a raw CDI Spec.
|
||||
func ParseSpec(data []byte) (*cdi.Spec, error) {
|
||||
var raw *cdi.Spec
|
||||
err := yaml.UnmarshalStrict(data, &raw)
|
||||
if err != nil {
|
||||
|
|
48
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_linux.go
generated
vendored
Normal file
48
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
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 cdi
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Rename src to dst, both relative to the directory dir. If dst already exists
|
||||
// refuse renaming with an error unless overwrite is explicitly asked for.
|
||||
func renameIn(dir, src, dst string, overwrite bool) error {
|
||||
var flags uint
|
||||
|
||||
dirf, err := os.Open(dir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "rename failed")
|
||||
}
|
||||
defer dirf.Close()
|
||||
|
||||
if !overwrite {
|
||||
flags = unix.RENAME_NOREPLACE
|
||||
}
|
||||
|
||||
dirFd := int(dirf.Fd())
|
||||
err = unix.Renameat2(dirFd, src, dirFd, dst, flags)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "rename failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
39
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_other.go
generated
vendored
Normal file
39
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_other.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
/*
|
||||
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 cdi
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Rename src to dst, both relative to the directory dir. If dst already exists
|
||||
// refuse renaming with an error unless overwrite is explicitly asked for.
|
||||
func renameIn(dir, src, dst string, overwrite bool) error {
|
||||
src = filepath.Join(dir, src)
|
||||
dst = filepath.Join(dir, dst)
|
||||
|
||||
_, err := os.Stat(dst)
|
||||
if err == nil && !overwrite {
|
||||
return os.ErrExist
|
||||
}
|
||||
|
||||
return os.Rename(src, dst)
|
||||
}
|
|
@ -3,7 +3,7 @@ package specs
|
|||
import "os"
|
||||
|
||||
// CurrentVersion is the current version of the Spec.
|
||||
const CurrentVersion = "0.4.0"
|
||||
const CurrentVersion = "0.5.0"
|
||||
|
||||
// Spec is the base configuration for CDI
|
||||
type Spec struct {
|
||||
|
@ -31,6 +31,7 @@ type ContainerEdits struct {
|
|||
// DeviceNode represents a device node that needs to be added to the OCI spec.
|
||||
type DeviceNode struct {
|
||||
Path string `json:"path"`
|
||||
HostPath string `json:"hostPath,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Major int64 `json:"major,omitempty"`
|
||||
Minor int64 `json:"minor,omitempty"`
|
||||
|
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
@ -61,7 +61,7 @@ github.com/checkpoint-restore/go-criu/v5/rpc
|
|||
github.com/checkpoint-restore/go-criu/v5/stats
|
||||
# github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
||||
github.com/chzyer/readline
|
||||
# github.com/container-orchestrated-devices/container-device-interface v0.4.0
|
||||
# github.com/container-orchestrated-devices/container-device-interface v0.5.0
|
||||
## explicit
|
||||
github.com/container-orchestrated-devices/container-device-interface/pkg/cdi
|
||||
github.com/container-orchestrated-devices/container-device-interface/specs-go
|
||||
|
|
Loading…
Reference in a new issue