Documentation ¶
Overview ¶
Package cdi has the primary purpose of providing an API for interacting with CDI and consuming CDI devices.
For more information about Container Device Interface, please refer to https://github.com/container-orchestrated-devices/container-device-interface
Container Device Interface ¶
Container Device Interface, or CDI for short, provides comprehensive third party device support for container runtimes. CDI uses vendor provided specification files, CDI Specs for short, to describe how a container's runtime environment should be modified when one or more of the vendor-specific devices is injected into the container. Beyond describing the low level platform-specific details of how to gain basic access to a device, CDI Specs allow more fine-grained device initialization, and the automatic injection of any necessary vendor- or device-specific software that might be required for a container to use a device or take full advantage of it.
In the CDI device model containers request access to a device using fully qualified device names, qualified names for short, consisting of a vendor identifier, a device class and a device name or identifier. These pieces of information together uniquely identify a device among all device vendors, classes and device instances.
This package implements an API for easy consumption of CDI. The API implements discovery, loading and caching of CDI Specs and injection of CDI devices into containers. This is the most common functionality the vast majority of CDI consumers need. The API should be usable both by OCI runtime clients and runtime implementations.
CDI Registry ¶
The primary interface to interact with CDI devices is the Registry. It is essentially a cache of all Specs and devices discovered in standard CDI directories on the host. The registry has two main functionality, injecting devices into an OCI Spec and refreshing the cache of CDI Specs and devices.
Device Injection ¶
Using the Registry one can inject CDI devices into a container with code similar to the following snippet:
import ( "fmt" "strings" log "github.com/sirupsen/logrus" "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi" oci "github.com/opencontainers/runtime-spec/specs-go" ) func injectCDIDevices(spec *oci.Spec, devices []string) error { log.Debug("pristine OCI Spec: %s", dumpSpec(spec)) unresolved, err := cdi.GetRegistry().InjectDevices(spec, devices) if err != nil { return fmt.Errorf("CDI device injection failed: %w", err) } log.Debug("CDI-updated OCI Spec: %s", dumpSpec(spec)) return nil }
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:
import ( "fmt" "strings" log "github.com/sirupsen/logrus" "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi" oci "github.com/opencontainers/runtime-spec/specs-go" ) func injectCDIDevices(spec *oci.Spec, devices []string) error { registry := cdi.GetRegistry() if err := registry.Refresh(); err != nil { // Note: // It is up to the implementation to decide whether // to abort injection on errors. A failed Refresh() // does not necessarily render the registry unusable. // For instance, a parse error in a Spec file for // vendor A does not have any effect on devices of // vendor B... log.Warnf("pre-injection Refresh() failed: %v", err) } log.Debug("pristine OCI Spec: %s", dumpSpec(spec)) unresolved, err := registry.InjectDevices(spec, devices) if err != nil { return fmt.Errorf("CDI device injection failed: %w", err) } log.Debug("CDI-updated OCI Spec: %s", dumpSpec(spec)) return nil }
Generated Spec Files, Multiple Directories, Device Precedence ¶
It is often necessary to generate Spec files dynamically. On some systems the available or usable set of CDI devices might change dynamically which then needs to be reflected in CDI Specs. For some device classes it makes sense to enumerate the available devices at every boot and generate Spec file entries for each device found. Some CDI devices might need special client- or request-specific configuration which can only be fulfilled by dynamically generated client-specific entries in transient Spec files.
CDI can collect Spec files from multiple directories. Spec files are automatically assigned priorities according to which directory they were loaded from. The later a directory occurs in the list of CDI directories to scan, the higher priority Spec files loaded from that directory are assigned to. When two or more Spec files define the same device, conflict is resolved by choosing the definition from the Spec file with the highest priority.
The default CDI directory configuration is chosen to encourage separating dynamically generated CDI Spec files from static ones. The default directories are '/etc/cdi' and '/var/run/cdi'. By putting dynamically generated Spec files under '/var/run/cdi', those take precedence over static ones in '/etc/cdi'. With this scheme, static Spec files, typically installed by distro-specific packages, go into '/etc/cdi' while all the dynamically generated Spec files, transient or other, go into '/var/run/cdi'.
Spec File Generation ¶
CDI offers two functions for writing and removing dynamically generated Specs from CDI Spec directories. These functions, WriteSpec() and RemoveSpec() implicitly follow the principle of separating dynamic Specs from the rest and therefore always write to and remove Specs from the last configured directory.
Corresponding functions are also provided for generating names for Spec files. These functions follow a simple naming convention to ensure that multiple entities generating Spec files simultaneously on the same host do not end up using conflicting Spec file names. GenerateSpecName(), GenerateNameForSpec(), GenerateTransientSpecName(), and GenerateTransientNameForSpec() all generate names which can be passed as such to WriteSpec() and subsequently to RemoveSpec().
Generating a Spec file for a vendor/device class can be done with a code snippet similar to the following:
import (
"fmt" ... "github.com/container-orchestrated-devices/container-device-interface/specs-go" "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
)
func generateDeviceSpecs() error { registry := cdi.GetRegistry() spec := &specs.Spec{ Version: specs.CurrentVersion, Kind: vendor+"/"+class, } for _, dev := range enumerateDevices() { spec.Devices = append(spec.Devices, specs.Device{ Name: dev.Name, ContainerEdits: getContainerEditsForDevice(dev), }) } specName, err := cdi.GenerateNameForSpec(spec) if err != nil { return fmt.Errorf("failed to generate Spec name: %w", err) } return registry.SpecDB().WriteSpec(spec, specName) }
Similarly, generating and later cleaning up transient Spec files can be done with code fragments similar to the following. These transient Spec files are temporary Spec files with container-specific parametrization. They are typically created before the associated container is created and removed once that container is removed.
import (
"fmt" ... "github.com/container-orchestrated-devices/container-device-interface/specs-go" "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
)
func generateTransientSpec(ctr Container) error { registry := cdi.GetRegistry() devices := getContainerDevs(ctr, vendor, class) spec := &specs.Spec{ Version: specs.CurrentVersion, Kind: vendor+"/"+class, } for _, dev := range devices { spec.Devices = append(spec.Devices, specs.Device{ // the generated name needs to be unique within the // vendor/class domain on the host/node. Name: generateUniqueDevName(dev, ctr), ContainerEdits: getEditsForContainer(dev), }) } // transientID is expected to guarantee that the Spec file name // generated using <vendor, class, transientID> is unique within // the host/node. If more than one device is allocated with the // same vendor/class domain, either all generated Spec entries // should go to a single Spec file (like in this sample snippet), // or transientID should be unique for each generated Spec file. transientID := getSomeSufficientlyUniqueIDForContainer(ctr) specName, err := cdi.GenerateNameForTransientSpec(vendor, class, transientID) if err != nil { return fmt.Errorf("failed to generate Spec name: %w", err) } return registry.SpecDB().WriteSpec(spec, specName) }
func removeTransientSpec(ctr Container) error { registry := cdi.GetRegistry() transientID := getSomeSufficientlyUniqueIDForContainer(ctr) specName := cdi.GenerateNameForTransientSpec(vendor, class, transientID) return registry.SpecDB().RemoveSpec(specName) }
CDI Spec Validation ¶
This package performs both syntactic and semantic validation of CDI Spec file data when a Spec file is loaded via the registry or using the ReadSpec API function. As part of the semantic verification, the Spec file is verified against the CDI Spec JSON validation schema.
If a valid externally provided JSON validation schema is found in the filesystem at /etc/cdi/schema/schema.json it is loaded and used as the default validation schema. If such a file is not found or fails to load, an embedded no-op schema is used.
The used validation schema can also be changed programmatically using the SetSchema API convenience function. This function also accepts the special "builtin" (BuiltinSchemaName) and "none" (NoneSchemaName) 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.
Index ¶
- Constants
- Variables
- func AnnotationKey(pluginName, deviceID string) (string, error)
- func AnnotationValue(devices []string) (string, error)
- func GenerateNameForSpec(raw *cdi.Spec) (string, error)
- func GenerateNameForTransientSpec(raw *cdi.Spec, transientID string) (string, error)
- func GenerateSpecName(vendor, class string) string
- func GenerateTransientSpecName(vendor, class, transientID string) string
- func IsQualifiedName(device string) booldeprecated
- func MinimumRequiredVersion(spec *cdi.Spec) (string, error)
- func ParseAnnotations(annotations map[string]string) ([]string, []string, error)
- func ParseDevice(device string) (string, string, string)deprecated
- func ParseQualifiedName(device string) (string, string, string, error)deprecated
- func ParseQualifier(kind string) (string, string)deprecated
- func ParseSpec(data []byte) (*cdi.Spec, error)
- func QualifiedName(vendor, class, name string) stringdeprecated
- func SetSpecValidator(fn func(*cdi.Spec) error)
- func UpdateAnnotations(annotations map[string]string, plugin string, deviceID string, ...) (map[string]string, error)
- func ValidateClassName(class string) errordeprecated
- func ValidateDeviceName(name string) errordeprecated
- func ValidateEnv(env []string) error
- func ValidateVendorName(vendor string) errordeprecated
- type Cache
- func (c *Cache) Configure(options ...Option) error
- func (c *Cache) GetDevice(device string) *Device
- func (c *Cache) GetErrors() map[string][]error
- func (c *Cache) GetSpecDirErrors() map[string]error
- func (c *Cache) GetSpecDirectories() []string
- func (c *Cache) GetSpecErrors(spec *Spec) []error
- func (c *Cache) GetVendorSpecs(vendor string) []*Spec
- func (c *Cache) InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, error)
- func (c *Cache) ListClasses() []string
- func (c *Cache) ListDevices() []string
- func (c *Cache) ListVendors() []string
- func (c *Cache) Refresh() error
- func (c *Cache) RemoveSpec(name string) error
- func (c *Cache) WriteSpec(raw *cdi.Spec, name string) error
- type ContainerEdits
- type Device
- type DeviceNode
- type Hook
- type Mount
- type Option
- type Registry
- type RegistryDeviceDB
- type RegistryRefresher
- type RegistryResolver
- type RegistrySpecDB
- type Spec
Constants ¶
const ( // PrestartHook is the name of the OCI "prestart" hook. PrestartHook = "prestart" // CreateRuntimeHook is the name of the OCI "createRuntime" hook. CreateRuntimeHook = "createRuntime" // CreateContainerHook is the name of the OCI "createContainer" hook. CreateContainerHook = "createContainer" // StartContainerHook is the name of the OCI "startContainer" hook. StartContainerHook = "startContainer" // PoststartHook is the name of the OCI "poststart" hook. PoststartHook = "poststart" // PoststopHook is the name of the OCI "poststop" hook. PoststopHook = "poststop" )
const ( // DefaultStaticDir is the default directory for static CDI Specs. DefaultStaticDir = "/etc/cdi" // DefaultDynamicDir is the default directory for generated CDI Specs DefaultDynamicDir = "/var/run/cdi" )
const (
// AnnotationPrefix is the prefix for CDI container annotation keys.
AnnotationPrefix = "cdi.k8s.io/"
)
const ( // CurrentVersion is the current version of the CDI Spec. CurrentVersion = cdi.CurrentVersion )
Variables ¶
var ( // DefaultSpecDirs is the default Spec directory configuration. // While altering this variable changes the package defaults, // the preferred way of overriding the default directories is // to use a WithSpecDirs options. Otherwise the change is only // effective if it takes place before creating the Registry or // other Cache instances. DefaultSpecDirs = []string{DefaultStaticDir, DefaultDynamicDir} // ErrStopScan can be returned from a ScanSpecFunc to stop the scan. ErrStopScan = errors.New("stop Spec scan") )
Functions ¶
func AnnotationKey ¶
AnnotationKey returns a unique annotation key for an device allocation by a K8s device plugin. pluginName should be in the format of "vendor.device-type". deviceID is the ID of the device the plugin is allocating. It is used to make sure that the generated key is unique even if multiple allocations by a single plugin needs to be annotated.
func AnnotationValue ¶
AnnotationValue returns an annotation value for the given devices.
func GenerateNameForSpec ¶ added in v0.5.3
GenerateNameForSpec generates a name for the given Spec using GenerateSpecName with the vendor and class taken from the Spec. On success it returns the generated name and a nil error. If the Spec does not contain a valid vendor or class, it returns an empty name and a non-nil error.
func GenerateNameForTransientSpec ¶ added in v0.5.3
GenerateNameForTransientSpec generates a name for the given transient Spec using GenerateTransientSpecName with the vendor and class taken from the Spec. On success it returns the generated name and a nil error. If the Spec does not contain a valid vendor or class, it returns an an empty name and a non-nil error.
func GenerateSpecName ¶ added in v0.5.3
GenerateSpecName generates a vendor+class scoped Spec file name. The name can be passed to WriteSpec() to write a Spec file to the file system.
vendor and class should match the vendor and class of the CDI Spec. The file name is generated without a ".json" or ".yaml" extension. The caller can append the desired extension to choose a particular encoding. Otherwise WriteSpec() will use its default encoding.
This function always returns the same name for the same vendor/class combination. Therefore it cannot be used as such to generate multiple Spec file names for a single vendor and class.
func GenerateTransientSpecName ¶ added in v0.5.3
GenerateTransientSpecName generates a vendor+class scoped transient Spec file name. The name can be passed to WriteSpec() to write a Spec file to the file system.
Transient Specs are those whose lifecycle is tied to that of some external entity, for instance a container. vendor and class should match the vendor and class of the CDI Spec. transientID should be unique among all CDI users on the same host that might generate transient Spec files using the same vendor/class combination. If the external entity to which the lifecycle of the transient Spec is tied to has a unique ID of its own, then this is usually a good choice for transientID.
The file name is generated without a ".json" or ".yaml" extension. The caller can append the desired extension to choose a particular encoding. Otherwise WriteSpec() will use its default encoding.
func IsQualifiedName
deprecated
func MinimumRequiredVersion ¶ added in v0.5.4
MinimumRequiredVersion determines the minimum spec version for the input spec.
func ParseAnnotations ¶
ParseAnnotations parses annotations for CDI device injection requests. The keys and devices from all such requests are collected into slices which are returned as the result. All devices are expected to be fully qualified CDI device names. If any device fails this check empty slices are returned along with a non-nil error. The annotations are expected to be formatted by, or in a compatible fashion to UpdateAnnotations().
func ParseDevice
deprecated
ParseDevice tries to split a device name into vendor, class, and name. If this fails, for instance in the case of unqualified device names, ParseDevice returns an empty vendor and class together with name set to the verbatim input.
Deprecated: use parser.ParseDevice instead
func ParseQualifiedName
deprecated
ParseQualifiedName splits a qualified name into device vendor, class, and name. If the device fails to parse as a qualified name, or if any of the split components fail to pass syntax validation, vendor and class are returned as empty, together with the verbatim input as the name and an error describing the reason for failure.
Deprecated: use parser.ParseQualifiedName instead
func ParseQualifier
deprecated
ParseQualifier splits a device qualifier into vendor and class. The syntax for a device qualifier is
"<vendor>/<class>"
If parsing fails, an empty vendor and the class set to the verbatim input is returned.
Deprecated: use parser.ParseQualifier instead
func QualifiedName
deprecated
QualifiedName returns the qualified name for a device. The syntax for a qualified device names is
"<vendor>/<class>=<name>".
A valid vendor and class name may contain the following runes:
'A'-'Z', 'a'-'z', '0'-'9', '.', '-', '_'.
A valid device name may contain the following runes:
'A'-'Z', 'a'-'z', '0'-'9', '-', '_', '.', ':'
Deprecated: use parser.QualifiedName instead
func SetSpecValidator ¶ added in v0.3.2
SetSpecValidator sets a CDI Spec validator function. This function is used for extra CDI Spec content validation whenever a Spec file loaded (using ReadSpec() or written (using WriteSpec()).
func UpdateAnnotations ¶
func UpdateAnnotations(annotations map[string]string, plugin string, deviceID string, devices []string) (map[string]string, error)
UpdateAnnotations updates annotations with a plugin-specific CDI device injection request for the given devices. Upon any error a non-nil error is returned and annotations are left intact. By convention plugin should be in the format of "vendor.device-type".
func ValidateClassName
deprecated
ValidateClassName checks the validity of class name. A class name may contain the following ASCII characters:
- upper- and lowercase letters ('A'-'Z', 'a'-'z')
- digits ('0'-'9')
- underscore, dash, and dot ('_', '-', and '.')
Deprecated: use parser.ValidateClassName instead
func ValidateDeviceName
deprecated
ValidateDeviceName checks the validity of a device name. A device name may contain the following ASCII characters:
- upper- and lowercase letters ('A'-'Z', 'a'-'z')
- digits ('0'-'9')
- underscore, dash, dot, colon ('_', '-', '.', ':')
Deprecated: use parser.ValidateDeviceName instead
func ValidateEnv ¶
ValidateEnv validates the given environment variables.
func ValidateVendorName
deprecated
ValidateVendorName checks the validity of a vendor name. A vendor name may contain the following ASCII characters:
- upper- and lowercase letters ('A'-'Z', 'a'-'z')
- digits ('0'-'9')
- underscore, dash, and dot ('_', '-', and '.')
Deprecated: use parser.ValidateVendorName instead
Types ¶
type Cache ¶
Cache stores CDI Specs loaded from Spec directories.
func NewCache ¶
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 (*Cache) Configure ¶
Configure applies options to the Cache. Updates and refreshes the Cache if options have changed.
func (*Cache) GetSpecDirErrors ¶ added in v0.5.0
GetSpecDirErrors returns any errors related to configured Spec directories.
func (*Cache) GetSpecDirectories ¶
GetSpecDirectories returns the CDI Spec directories currently in use.
func (*Cache) GetSpecErrors ¶
GetSpecErrors returns all errors encountered for the spec during the last cache refresh.
func (*Cache) GetVendorSpecs ¶
GetVendorSpecs returns all specs for the given vendor.
func (*Cache) InjectDevices ¶
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.
func (*Cache) ListClasses ¶
ListClasses lists all device classes known to the cache.
func (*Cache) ListDevices ¶
ListDevices lists all cached devices by qualified name.
func (*Cache) ListVendors ¶
ListVendors lists all vendors known to the cache.
func (*Cache) Refresh ¶
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 (*Cache) RemoveSpec ¶ added in v0.5.3
RemoveSpec removes a Spec with the given name from the highest priority Spec directory. This function can be used to remove a Spec previously written by WriteSpec(). If the file exists and its removal fails RemoveSpec returns an error.
type ContainerEdits ¶
type ContainerEdits struct {
*specs.ContainerEdits
}
ContainerEdits represent updates to be applied to an OCI Spec. These updates can be specific to a CDI device, or they can be specific to a CDI Spec. In the former case these edits should be applied to all OCI Specs where the corresponding CDI device is injected. In the latter case, these edits should be applied to all OCI Specs where at least one devices from the CDI Spec is injected.
func (*ContainerEdits) Append ¶
func (e *ContainerEdits) Append(o *ContainerEdits) *ContainerEdits
Append other edits into this one. If called with a nil receiver, allocates and returns newly allocated edits.
func (*ContainerEdits) Apply ¶
func (e *ContainerEdits) Apply(spec *oci.Spec) error
Apply edits to the given OCI Spec. Updates the OCI Spec in place. Returns an error if the update fails.
func (*ContainerEdits) Validate ¶
func (e *ContainerEdits) Validate() error
Validate container edits.
type Device ¶
Device represents a CDI device of a Spec.
func (*Device) ApplyEdits ¶
ApplyEdits applies the device-speific container edits to an OCI Spec.
func (*Device) GetQualifiedName ¶
GetQualifiedName returns the qualified name for this device.
type DeviceNode ¶
type DeviceNode struct {
*specs.DeviceNode
}
DeviceNode is a CDI Spec DeviceNode wrapper, used for validating DeviceNodes.
type Hook ¶
type Hook struct {
*specs.Hook
}
Hook is a CDI Spec Hook wrapper, used for validating hooks.
type Mount ¶
type Mount struct {
*specs.Mount
}
Mount is a CDI Mount wrapper, used for validating mounts.
type Option ¶
Option is an option to change some aspect of default CDI behavior.
func WithAutoRefresh ¶ added in v0.5.0
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 WithSpecDirs ¶
WithSpecDirs returns an option to override the CDI Spec directories.
type Registry ¶
type Registry interface { RegistryResolver RegistryRefresher DeviceDB() RegistryDeviceDB SpecDB() RegistrySpecDB }
Registry keeps a cache of all CDI Specs installed or generated on the host. Registry is the primary interface clients should use to interact with CDI.
The most commonly used Registry functions are for refreshing the registry and injecting CDI devices into an OCI Spec.
func GetRegistry ¶
GetRegistry returns the CDI registry. If any options are given, those are applied to the registry.
type RegistryDeviceDB ¶
RegistryDeviceDB is the registry interface for querying devices.
GetDevice returns the CDI device for the given qualified name. If the device is not GetDevice returns nil.
ListDevices returns a slice with the names of qualified device known. The returned slice is sorted.
type RegistryRefresher ¶
type RegistryRefresher interface { Configure(...Option) error Refresh() error GetErrors() map[string][]error GetSpecDirectories() []string GetSpecDirErrors() map[string]error }
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.
GetErrors returns all errors encountered for any of the scanned Spec files during the last cache refresh.
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 RegistryResolver ¶
type RegistryResolver interface {
InjectDevices(spec *oci.Spec, device ...string) (unresolved []string, err error)
}
RegistryResolver is the registry interface for injecting CDI devices into an OCI Spec.
InjectDevices takes an OCI Spec and injects into it a set of CDI devices given by qualified name. It returns the names of any unresolved devices and an error if injection fails.
type RegistrySpecDB ¶
type RegistrySpecDB interface { ListVendors() []string ListClasses() []string GetVendorSpecs(vendor string) []*Spec GetSpecErrors(*Spec) []error WriteSpec(raw *cdi.Spec, name string) error RemoveSpec(name string) error }
RegistrySpecDB is the registry interface for querying CDI Specs.
ListVendors returns a slice with all vendors known. The returned slice is sorted.
ListClasses returns a slice with all classes known. The returned slice is sorted.
GetVendorSpecs returns a slice of all Specs for the vendor.
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 Spec ¶
Spec represents a single CDI Spec. It is usually loaded from a file and stored in a cache. The Spec has an associated priority. This priority is inherited from the associated priority of the CDI Spec directory that contains the CDI Spec file and is used to resolve conflicts if multiple CDI Spec files contain entries for the same fully qualified device.
func ReadSpec ¶
ReadSpec reads the given CDI Spec file. The resulting Spec is assigned the given priority. If reading or parsing the Spec data fails ReadSpec returns a nil Spec and an error.
func (*Spec) ApplyEdits ¶
ApplyEdits applies the Spec's global-scope container edits to an OCI Spec.
func (*Spec) GetPriority ¶
GetPriority returns the priority of this Spec.