From cddb43f6d195c5343d2e631830ab23de844bcd22 Mon Sep 17 00:00:00 2001 From: Ed Bartosh Date: Thu, 8 Aug 2024 18:20:06 +0300 Subject: [PATCH 1/2] Remove deprecated registry API Signed-off-by: Ed Bartosh --- cmd/cdi/cmd/cdi-api.go | 2 +- cmd/cdi/cmd/classes.go | 4 +- cmd/cdi/cmd/devices.go | 6 +- cmd/cdi/cmd/dirs.go | 2 +- cmd/cdi/cmd/monitor.go | 6 +- cmd/cdi/cmd/root.go | 17 +- cmd/cdi/cmd/specs.go | 6 +- cmd/cdi/cmd/validate.go | 15 +- cmd/cdi/cmd/vendors.go | 2 +- pkg/cdi/doc.go | 61 ++- pkg/cdi/registry.go | 178 -------- pkg/cdi/registry_test.go | 823 ------------------------------------ pkg/cdi/regressions_test.go | 14 +- pkg/cdi/spec-dirs.go | 3 +- 14 files changed, 68 insertions(+), 1071 deletions(-) delete mode 100644 pkg/cdi/registry.go delete mode 100644 pkg/cdi/registry_test.go diff --git a/cmd/cdi/cmd/cdi-api.go b/cmd/cdi/cmd/cdi-api.go index ed89d52a..3e60a23c 100644 --- a/cmd/cdi/cmd/cdi-api.go +++ b/cmd/cdi/cmd/cdi-api.go @@ -339,7 +339,7 @@ func cdiPrintCacheErrors() { return } - fmt.Printf("CDI Cache has errors:\n") + fmt.Printf("CDI cache has errors:\n") for path, specErrors := range cdiErrors { fmt.Printf("Spec file %s:\n", path) for idx, err := range specErrors { diff --git a/cmd/cdi/cmd/classes.go b/cmd/cdi/cmd/classes.go index ec7bd3b4..b32058d0 100644 --- a/cmd/cdi/cmd/classes.go +++ b/cmd/cdi/cmd/classes.go @@ -20,11 +20,11 @@ import ( "github.com/spf13/cobra" ) -// classesCmd is our command for listing device classes in the registry. +// classesCmd is our command for listing device classes in the cache. var classesCmd = &cobra.Command{ Use: "classes", Short: "List CDI device classes", - Long: `List CDI device classes found in the registry.`, + Long: `List CDI device classes found in the cache.`, Run: func(cmd *cobra.Command, args []string) { cdiListClasses() }, diff --git a/cmd/cdi/cmd/devices.go b/cmd/cdi/cmd/devices.go index f58daea1..8ef65ae5 100644 --- a/cmd/cdi/cmd/devices.go +++ b/cmd/cdi/cmd/devices.go @@ -25,13 +25,13 @@ type devicesFlags struct { output string } -// devicesCmd is our command for listing devices found in the CDI registry. +// devicesCmd is our command for listing devices found in the CDI cache. var devicesCmd = &cobra.Command{ Aliases: []string{"devs", "dev"}, Use: "devices", - Short: "List devices in the CDI registry", + Short: "List devices in the CDI cache", Long: ` -The 'devices' command lists devices found in the CDI registry.`, +The 'devices' command lists devices found in the CDI cache.`, Run: func(cmd *cobra.Command, args []string) { cdiListDevices(devicesCfg.verbose, devicesCfg.output) }, diff --git a/cmd/cdi/cmd/dirs.go b/cmd/cdi/cmd/dirs.go index 13b1ee4b..84a0bf92 100644 --- a/cmd/cdi/cmd/dirs.go +++ b/cmd/cdi/cmd/dirs.go @@ -25,7 +25,7 @@ var dirsCmd = &cobra.Command{ Use: "dirs", Short: "Show CDI Spec directories in use", Long: ` -Show which directories are used by the registry to discover and +Show which directories are used by the cache to discover and load CDI Specs. The later an entry is in the list the higher its priority. This priority is inherited by Spec files loaded from the directory and is used to resolve device conflicts. If there diff --git a/cmd/cdi/cmd/monitor.go b/cmd/cdi/cmd/monitor.go index ed040bce..d0cf74d8 100644 --- a/cmd/cdi/cmd/monitor.go +++ b/cmd/cdi/cmd/monitor.go @@ -48,8 +48,8 @@ information to show upon each refresh.`, func monitorSpecDirs(args ...string) { var ( - registry = cdi.GetRegistry() - specDirs = registry.GetSpecDirectories() + cache = cdi.GetDefaultCache() + specDirs = cache.GetSpecDirectories() dirWatch *fsnotify.Watcher err error done chan error @@ -81,7 +81,7 @@ func monitorSpecDirs(args ...string) { go func() { var ( - // don't print registry content more often than this + // don't print cache content more often than this oneSecond = 1 * time.Second timer *time.Timer ) diff --git a/cmd/cdi/cmd/root.go b/cmd/cdi/cmd/root.go index 4ae72ac3..ec067549 100644 --- a/cmd/cdi/cmd/root.go +++ b/cmd/cdi/cmd/root.go @@ -35,13 +35,13 @@ var ( // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "cdi", - Short: "Inspect and interact with the CDI Registry", + Short: "Inspect and interact with the CDI cache", Long: ` The 'cdi' utility allows you to inspect and interact with the -CDI Registry. Various commands are available for listing CDI +CDI cache. Various commands are available for listing CDI Spec files, vendors, classes, devices, validating the content -of the registry, injecting devices into OCI Specs, and for -monitoring changes in the Registry. +of the cache, injecting devices into OCI Specs, and for +monitoring changes in the cache. See cdi --help for a list of available commands. You can get additional help about by using 'cdi -h'.`, @@ -68,11 +68,16 @@ func initSpecDirs() { cdi.SetSpecValidator(validate.WithSchema(s)) if len(specDirs) > 0 { - cdi.GetRegistry( + cache, err := cdi.NewCache( cdi.WithSpecDirs(specDirs...), ) - if len(cdi.GetRegistry().GetErrors()) > 0 { + if err != nil { + fmt.Printf("failed to create CDI cache: %v\n", err) + os.Exit(1) + } + if len(cache.GetErrors()) > 0 { cdiPrintCacheErrors() + os.Exit(1) } } } diff --git a/cmd/cdi/cmd/specs.go b/cmd/cdi/cmd/specs.go index 60bd82f3..b2488a3d 100644 --- a/cmd/cdi/cmd/specs.go +++ b/cmd/cdi/cmd/specs.go @@ -34,10 +34,10 @@ var specsCmd = &cobra.Command{ Use: "specs [vendor-list]", Short: "List available CDI Specs", Long: fmt.Sprintf(` -The 'specs' command lists all CDI Specs present in the registry. +The 'specs' command lists all CDI Specs present in the cache. If a vendor list is given, only CDI Specs by the given vendors are -listed. The CDI Specs are discovered and loaded to the registry -from CDI Spec directories. The default CDI Spec directories are: +listed. The CDI Specs are discovered and loaded to the cache from +CDI Spec directories. The default CDI Spec directories are: %s.`, strings.Join(cdi.DefaultSpecDirs, ", ")), Run: func(cmd *cobra.Command, vendors []string) { cdiListSpecs(specCfg.verbose, specCfg.output, vendors...) diff --git a/cmd/cdi/cmd/validate.go b/cmd/cdi/cmd/validate.go index c96e43d9..9dc8faf9 100644 --- a/cmd/cdi/cmd/validate.go +++ b/cmd/cdi/cmd/validate.go @@ -26,22 +26,23 @@ import ( "tags.cncf.io/container-device-interface/pkg/cdi" ) -// validateCmd is our CDI command for validating CDI Spec files in the registry. +// validateCmd is our CDI command for validating CDI Spec files in the cache. var validateCmd = &cobra.Command{ Use: "validate", - Short: "List CDI registry errors", + Short: "List CDI cache errors", Long: ` The 'validate' command lists errors encountered during the population -of the CDI registry. It exits with an exit status of 1 if any errors -were reported by the registry.`, +of the CDI cache. It exits with an exit status of 1 if any errors +were reported by the cache.`, Run: func(cmd *cobra.Command, args []string) { - cdiErrors := cdi.GetRegistry().GetErrors() + cache := cdi.GetDefaultCache() + cdiErrors := cache.GetErrors() if len(cdiErrors) == 0 { - fmt.Printf("No CDI Registry errors.\n") + fmt.Printf("No CDI cache errors.\n") return } - fmt.Printf("CDI Registry has errors:\n") + fmt.Printf("CDI cache has errors:\n") for path, specErrors := range cdiErrors { fmt.Printf("Spec file %s:\n", path) for idx, err := range specErrors { diff --git a/cmd/cdi/cmd/vendors.go b/cmd/cdi/cmd/vendors.go index c82bec3f..c78370d7 100644 --- a/cmd/cdi/cmd/vendors.go +++ b/cmd/cdi/cmd/vendors.go @@ -24,7 +24,7 @@ import ( var vendorsCmd = &cobra.Command{ Use: "vendors", Short: "List vendors", - Long: `List vendors with CDI Specs in the registry.`, + Long: `List vendors with CDI Specs in the cache.`, Run: func(cmd *cobra.Command, args []string) { cdiListVendors() }, diff --git a/pkg/cdi/doc.go b/pkg/cdi/doc.go index 0ea07145..e5bdd845 100644 --- a/pkg/cdi/doc.go +++ b/pkg/cdi/doc.go @@ -35,25 +35,11 @@ // 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 -// -// 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 -// 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. +// default cache instance. // // # Device Injection // -// Using the Registry one can inject CDI devices into a container with code +// Using the Cache one can inject CDI devices into a container with code // similar to the following snippet: // // import ( @@ -63,13 +49,14 @@ // log "github.com/sirupsen/logrus" // // "tags.cncf.io/container-device-interface/pkg/cdi" -// oci "github.com/opencontainers/runtime-spec/specs-go" +// "github.com/opencontainers/runtime-spec/specs-go" // ) // -// func injectCDIDevices(spec *oci.Spec, devices []string) error { +// func injectCDIDevices(spec *specs.Spec, devices []string) error { // log.Debug("pristine OCI Spec: %s", dumpSpec(spec)) // -// unresolved, err := cdi.GetRegistry().InjectDevices(spec, devices) +// cache := cdi.GetDefaultCache() +// unresolved, err := cache.InjectDevices(spec, devices) // if err != nil { // return fmt.Errorf("CDI device injection failed: %w", err) // } @@ -106,17 +93,17 @@ // log "github.com/sirupsen/logrus" // // "tags.cncf.io/container-device-interface/pkg/cdi" -// oci "github.com/opencontainers/runtime-spec/specs-go" +// "github.com/opencontainers/runtime-spec/specs-go" // ) // -// func injectCDIDevices(spec *oci.Spec, devices []string) error { -// registry := cdi.GetRegistry() +// func injectCDIDevices(spec *specs.Spec, devices []string) error { +// cache := cdi.GetDefaultCache() // -// if err := registry.Refresh(); err != nil { +// if err := cache.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. +// // does not necessarily render the cache unusable. // // For instance, a parse error in a Spec file for // // vendor A does not have any effect on devices of // // vendor B... @@ -125,7 +112,7 @@ // // log.Debug("pristine OCI Spec: %s", dumpSpec(spec)) // -// unresolved, err := registry.InjectDevices(spec, devices) +// unresolved, err := cache.InjectDevices(spec, devices) // if err != nil { // return fmt.Errorf("CDI device injection failed: %w", err) // } @@ -182,17 +169,17 @@ // Generating a Spec file for a vendor/device class can be done with a // code snippet similar to the following: // -// import ( +// import ( // // "fmt" // ... // "tags.cncf.io/container-device-interface/specs-go" // "tags.cncf.io/container-device-interface/pkg/cdi" // -// ) +// ) // // func generateDeviceSpecs() error { -// registry := cdi.GetRegistry() +// cache := specs.GetDefaultCache() // spec := &specs.Spec{ // Version: specs.CurrentVersion, // Kind: vendor+"/"+class, @@ -210,7 +197,7 @@ // return fmt.Errorf("failed to generate Spec name: %w", err) // } // -// return registry.SpecDB().WriteSpec(spec, specName) +// return cache.WriteSpec(spec, specName) // } // // Similarly, generating and later cleaning up transient Spec files can be @@ -219,17 +206,17 @@ // They are typically created before the associated container is created // and removed once that container is removed. // -// import ( +// import ( // // "fmt" -// ... +// // "tags.cncf.io/container-device-interface/specs-go" // "tags.cncf.io/container-device-interface/pkg/cdi" // -// ) +// ) // // func generateTransientSpec(ctr Container) error { -// registry := cdi.GetRegistry() +// cache := specs.GetDefaultCache() // devices := getContainerDevs(ctr, vendor, class) // spec := &specs.Spec{ // Version: specs.CurrentVersion, @@ -257,21 +244,21 @@ // return fmt.Errorf("failed to generate Spec name: %w", err) // } // -// return registry.SpecDB().WriteSpec(spec, specName) +// return cache.WriteSpec(spec, specName) // } // // func removeTransientSpec(ctr Container) error { -// registry := cdi.GetRegistry() +// cache := specs.GetDefaultCache() // transientID := getSomeSufficientlyUniqueIDForContainer(ctr) // specName := cdi.GenerateNameForTransientSpec(vendor, class, transientID) // -// return registry.SpecDB().RemoveSpec(specName) +// return cache.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 +// Spec file data when a Spec file is loaded via the cache or using // the ReadSpec API function. As part of the semantic verification, the // Spec file is verified against the CDI Spec JSON validation schema. // diff --git a/pkg/cdi/registry.go b/pkg/cdi/registry.go deleted file mode 100644 index 3113a05a..00000000 --- a/pkg/cdi/registry.go +++ /dev/null @@ -1,178 +0,0 @@ -/* - Copyright © 2021 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" - cdi "tags.cncf.io/container-device-interface/specs-go" -) - -// 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. -// -// 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 { - RegistryResolver - RegistryRefresher - DeviceDB() RegistryDeviceDB - SpecDB() RegistrySpecDB -} - -// 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. -// -// 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 { - Configure(...Option) error - Refresh() error - GetErrors() map[string][]error - GetSpecDirectories() []string - GetSpecDirErrors() map[string]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. -// -// 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 { - InjectDevices(spec *oci.Spec, device ...string) (unresolved []string, err error) -} - -// 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. -// -// 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 { - GetDevice(device string) *Device - ListDevices() []string -} - -// 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. -// -// 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 { - ListVendors() []string - ListClasses() []string - GetVendorSpecs(vendor string) []*Spec - GetSpecErrors(*Spec) []error - WriteSpec(raw *cdi.Spec, name string) error - RemoveSpec(name string) error -} - -type registry struct { - *Cache -} - -var _ Registry = ®istry{} - -var ( - reg *registry - initOnce sync.Once -) - -// GetRegistry returns the CDI registry. If any options are given, those -// 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 { - initOnce.Do(func() { - reg = ®istry{GetDefaultCache()} - }) - if len(options) > 0 { - // We don't care about errors here - _ = reg.Configure(options...) - } - return reg -} - -// 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 { - return r -} - -// 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 { - return r -} diff --git a/pkg/cdi/registry_test.go b/pkg/cdi/registry_test.go deleted file mode 100644 index 8dd89bb6..00000000 --- a/pkg/cdi/registry_test.go +++ /dev/null @@ -1,823 +0,0 @@ -/* - Copyright © 2021 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 ( - "path/filepath" - "testing" - - oci "github.com/opencontainers/runtime-spec/specs-go" - "github.com/stretchr/testify/require" -) - -func TestRegistryResolver(t *testing.T) { - type specDirs struct { - etc map[string]string - run map[string]string - } - type testCase struct { - name string - cdiSpecs specDirs - ociSpec *oci.Spec - devices []string - result *oci.Spec - unresolved []string - } - for _, tc := range []*testCase{ - { - name: "empty OCI Spec, inject one device", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: - env: - - VENDOR1_SPEC_VAR1=VAL1 -devices: - - name: "dev1" - containerEdits: - env: - - "VENDOR1_VAR1=VAL1" - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 -`, - }, - }, - ociSpec: &oci.Spec{}, - devices: []string{ - "vendor1.com/device=dev1", - }, - result: &oci.Spec{ - Process: &oci.Process{ - Env: []string{ - "VENDOR1_SPEC_VAR1=VAL1", - "VENDOR1_VAR1=VAL1", - }, - }, - Linux: &oci.Linux{ - Devices: []oci.LinuxDevice{ - { - Path: "/dev/vendor1-dev1", - Type: "b", - Major: 10, - Minor: 1, - }, - }, - Resources: &oci.LinuxResources{ - Devices: []oci.LinuxDeviceCgroup{ - { - Allow: true, - Type: "b", - Major: int64ptr(10), - Minor: int64ptr(1), - Access: "rwm", - }, - }, - }, - }, - }, - }, - { - name: "non-empty OCI Spec, inject one device", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: - env: - - VENDOR1_SPEC_VAR1=VAL1 -devices: - - name: "dev1" - containerEdits: - env: - - "VENDOR1_VAR1=VAL1" - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 -`, - }, - }, - ociSpec: &oci.Spec{ - Process: &oci.Process{ - Env: []string{ - "ORIG_VAR1=VAL1", - "ORIG_VAR2=VAL2", - }, - }, - Linux: &oci.Linux{ - Devices: []oci.LinuxDevice{ - { - Path: "/dev/null", - }, - { - Path: "/dev/zero", - }, - }, - }, - }, - devices: []string{ - "vendor1.com/device=dev1", - }, - result: &oci.Spec{ - Process: &oci.Process{ - Env: []string{ - "ORIG_VAR1=VAL1", - "ORIG_VAR2=VAL2", - "VENDOR1_SPEC_VAR1=VAL1", - "VENDOR1_VAR1=VAL1", - }, - }, - Linux: &oci.Linux{ - Devices: []oci.LinuxDevice{ - { - Path: "/dev/null", - }, - { - Path: "/dev/zero", - }, - { - Path: "/dev/vendor1-dev1", - Type: "b", - Major: 10, - Minor: 1, - }, - }, - Resources: &oci.LinuxResources{ - Devices: []oci.LinuxDeviceCgroup{ - { - Allow: true, - Type: "b", - Major: int64ptr(10), - Minor: int64ptr(1), - Access: "rwm", - }, - }, - }, - }, - }, - }, - { - name: "non-empty OCI Spec, inject several devices, hooks", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: - env: - - VENDOR1_SPEC_VAR1=VAL1 -devices: - - name: "dev1" - containerEdits: - env: - - "VENDOR1_DEV1=VAL1" - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 - - name: "dev2" - containerEdits: - env: - - "VENDOR1_DEV2=VAL2" - deviceNodes: - - path: "/dev/vendor1-dev2" - type: b - major: 10 - minor: 2 - hooks: - - hookName: prestart - path: "/usr/local/bin/prestart-vendor-hook" - args: - - "--verbose" - env: - - "HOOK_ENV1=PRESTART_VAL1" - - hookName: createRuntime - path: "/usr/local/bin/cr-vendor-hook" - args: - - "--debug" - env: - - "HOOK_ENV1=CREATE_RUNTIME_VAL1" - - name: "dev3" - containerEdits: - env: - - "VENDOR1_DEV3=VAL3" - deviceNodes: - - path: "/dev/vendor1-dev3" - type: b - major: 10 - minor: 3 -`, - }, - }, - ociSpec: &oci.Spec{ - Process: &oci.Process{ - Env: []string{ - "ORIG_VAR1=VAL1", - "ORIG_VAR2=VAL2", - }, - }, - Linux: &oci.Linux{ - Devices: []oci.LinuxDevice{ - { - Path: "/dev/null", - }, - { - Path: "/dev/zero", - }, - }, - }, - }, - devices: []string{ - "vendor1.com/device=dev1", - "vendor1.com/device=dev2", - "vendor1.com/device=dev3", - }, - result: &oci.Spec{ - Process: &oci.Process{ - Env: []string{ - "ORIG_VAR1=VAL1", - "ORIG_VAR2=VAL2", - "VENDOR1_SPEC_VAR1=VAL1", - "VENDOR1_DEV1=VAL1", - "VENDOR1_DEV2=VAL2", - "VENDOR1_DEV3=VAL3", - }, - }, - Hooks: &oci.Hooks{ - Prestart: []oci.Hook{ - { - Path: "/usr/local/bin/prestart-vendor-hook", - Args: []string{"--verbose"}, - Env: []string{"HOOK_ENV1=PRESTART_VAL1"}, - }, - }, - CreateRuntime: []oci.Hook{ - { - Path: "/usr/local/bin/cr-vendor-hook", - Args: []string{"--debug"}, - Env: []string{"HOOK_ENV1=CREATE_RUNTIME_VAL1"}, - }, - }, - }, - Linux: &oci.Linux{ - Devices: []oci.LinuxDevice{ - { - Path: "/dev/null", - }, - { - Path: "/dev/zero", - }, - { - Path: "/dev/vendor1-dev1", - Type: "b", - Major: 10, - Minor: 1, - }, - { - Path: "/dev/vendor1-dev2", - Type: "b", - Major: 10, - Minor: 2, - }, - { - Path: "/dev/vendor1-dev3", - Type: "b", - Major: 10, - Minor: 3, - }, - }, - Resources: &oci.LinuxResources{ - Devices: []oci.LinuxDeviceCgroup{ - { - Allow: true, - Type: "b", - Major: int64ptr(10), - Minor: int64ptr(1), - Access: "rwm", - }, - { - Allow: true, - Type: "b", - Major: int64ptr(10), - Minor: int64ptr(2), - Access: "rwm", - }, - { - Allow: true, - Type: "b", - Major: int64ptr(10), - Minor: int64ptr(3), - Access: "rwm", - }, - }, - }, - }, - }, - }, - { - name: "empty OCI Spec, non-existent device", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: - env: - - VENDOR1_SPEC_VAR1=VAL1 -devices: - - name: "dev1" - containerEdits: - env: - - "VENDOR1_VAR1=VAL1" - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 -`, - }, - }, - ociSpec: &oci.Spec{}, - devices: []string{ - "vendor1.com/device=dev2", - }, - result: &oci.Spec{}, - unresolved: []string{ - "vendor1.com/device=dev2", - }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - var ( - dir string - err error - reg Registry - ) - dir, err = createSpecDirs(t, tc.cdiSpecs.etc, tc.cdiSpecs.run) - if err != nil { - t.Errorf("failed to create test directory: %v", err) - return - } - reg = GetRegistry( - WithSpecDirs( - filepath.Join(dir, "etc"), - filepath.Join(dir, "run"), - ), - ) - require.Nil(t, err) - require.NotNil(t, reg) - - unresolved, err := reg.InjectDevices(tc.ociSpec, tc.devices...) - if len(tc.unresolved) != 0 { - require.NotNil(t, err) - require.Equal(t, tc.unresolved, unresolved) - return - } - - require.Nil(t, err) - require.Equal(t, tc.result, tc.ociSpec) - }) - } -} - -func TestRegistrySpecDB(t *testing.T) { - type specDirs struct { - etc map[string]string - run map[string]string - } - type testCase struct { - name string - cdiSpecs specDirs - vendors []string - classes []string - } - for _, tc := range []*testCase{ - { - name: "no vendors, no classes", - }, - { - name: "one vendor, one class", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: - env: - - VENDOR1_SPEC_VAR1=VAL1 -devices: - - name: "dev1" - containerEdits: - env: - - "VENDOR1_VAR1=VAL1" - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 -`, - }, - }, - vendors: []string{ - "vendor1.com", - }, - classes: []string{ - "device", - }, - }, - { - name: "one vendor, multiple classes", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 - - name: "dev2" - containerEdits: - env: - - "VENDOR1_DEV2=VAL2" - deviceNodes: - - path: "/dev/vendor1-dev2" - type: b - major: 10 - minor: 2 -`, - "vendor1-other.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/other-device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor1-other-dev1" - type: b - major: 12 - minor: 1 - - name: "dev2" - containerEdits: - env: - - "VENDOR1_DEV2=VAL2" - deviceNodes: - - path: "/dev/vendor1-other-dev2" - type: b - major: 11 - minor: 2 -`, - }, - }, - vendors: []string{ - "vendor1.com", - }, - classes: []string{ - "device", - "other-device", - }, - }, - { - name: "multiple vendor, multiple classes", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 - - name: "dev2" - containerEdits: - env: - - "VENDOR1_DEV2=VAL2" - deviceNodes: - - path: "/dev/vendor1-dev2" - type: b - major: 10 - minor: 2 -`, - "vendor2.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor2.com/other-device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor2-dev1" - - name: "dev2" - containerEdits: - deviceNodes: - - path: "/dev/vendor2-dev2" -`, - "vendor2-other.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor2.com/another-device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor2-another-dev1" - - name: "dev2" - containerEdits: - deviceNodes: - - path: "/dev/vendor2-another-dev2" -`, - "vendor3.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor3.com/yet-another-device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor3-dev1" - - name: "dev2" - containerEdits: - deviceNodes: - - path: "/dev/vendor3-dev2" -`, - }, - }, - vendors: []string{ - "vendor1.com", - "vendor2.com", - "vendor3.com", - }, - classes: []string{ - "another-device", - "device", - "other-device", - "yet-another-device", - }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - var ( - dir string - err error - reg Registry - ) - dir, err = createSpecDirs(t, tc.cdiSpecs.etc, tc.cdiSpecs.run) - if err != nil { - t.Errorf("failed to create test directory: %v", err) - return - } - reg = GetRegistry( - WithSpecDirs( - filepath.Join(dir, "etc"), - filepath.Join(dir, "run"), - ), - ) - require.Nil(t, err) - require.NotNil(t, reg) - - vendors := reg.SpecDB().ListVendors() - require.Equal(t, tc.vendors, vendors) - classes := reg.SpecDB().ListClasses() - require.Equal(t, tc.classes, classes) - }) - } -} - -func TestRegistryDeviceDB(t *testing.T) { - type specDirs struct { - etc map[string]string - run map[string]string - } - type testCase struct { - name string - cdiSpecs specDirs - devices []string - } - for _, tc := range []*testCase{ - { - name: "no vendors, no classes", - }, - { - name: "one vendor, one class", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: - env: - - VENDOR1_SPEC_VAR1=VAL1 -devices: - - name: "dev1" - containerEdits: - env: - - "VENDOR1_VAR1=VAL1" - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 -`, - }, - }, - devices: []string{ - "vendor1.com/device=dev1", - }, - }, - { - name: "one vendor, multiple classes", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 - - name: "dev2" - containerEdits: - env: - - "VENDOR1_DEV2=VAL2" - deviceNodes: - - path: "/dev/vendor1-dev2" - type: b - major: 10 - minor: 2 -`, - "vendor1-other.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/other-device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor1-other-dev1" - type: b - major: 11 - minor: 1 - - name: "dev2" - containerEdits: - env: - - "VENDOR1_DEV2=VAL2" - deviceNodes: - - path: "/dev/vendor1-other-dev2" - type: b - major: 11 - minor: 2 -`, - }, - }, - devices: []string{ - "vendor1.com/device=dev1", - "vendor1.com/device=dev2", - "vendor1.com/other-device=dev1", - "vendor1.com/other-device=dev2", - }, - }, - { - name: "multiple vendor, multiple classes", - cdiSpecs: specDirs{ - etc: map[string]string{ - "vendor1.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor1.com/device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor1-dev1" - type: b - major: 10 - minor: 1 - - name: "dev2" - containerEdits: - env: - - "VENDOR1_DEV2=VAL2" - deviceNodes: - - path: "/dev/vendor1-dev2" - type: b - major: 10 - minor: 2 -`, - "vendor2.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor2.com/other-device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor2-dev1" - - name: "dev2" - containerEdits: - deviceNodes: - - path: "/dev/vendor2-dev2" -`, - "vendor2-other.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor2.com/another-device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor2-another-dev1" - - name: "dev2" - containerEdits: - deviceNodes: - - path: "/dev/vendor2-another-dev2" -`, - "vendor3.yaml": ` -cdiVersion: "0.3.0" -kind: "vendor3.com/yet-another-device" -containerEdits: -devices: - - name: "dev1" - containerEdits: - deviceNodes: - - path: "/dev/vendor3-dev1" - - name: "dev2" - containerEdits: - deviceNodes: - - path: "/dev/vendor3-dev2" -`, - }, - }, - devices: []string{ - "vendor1.com/device=dev1", - "vendor1.com/device=dev2", - "vendor2.com/another-device=dev1", - "vendor2.com/another-device=dev2", - "vendor2.com/other-device=dev1", - "vendor2.com/other-device=dev2", - "vendor3.com/yet-another-device=dev1", - "vendor3.com/yet-another-device=dev2", - }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - var ( - dir string - err error - reg Registry - ) - dir, err = createSpecDirs(t, tc.cdiSpecs.etc, tc.cdiSpecs.run) - if err != nil { - t.Errorf("failed to create test directory: %v", err) - return - } - reg = GetRegistry( - WithSpecDirs( - filepath.Join(dir, "etc"), - filepath.Join(dir, "run"), - ), - ) - require.Nil(t, err) - require.NotNil(t, reg) - - devices := reg.DeviceDB().ListDevices() - require.Equal(t, tc.devices, devices) - }) - } -} diff --git a/pkg/cdi/regressions_test.go b/pkg/cdi/regressions_test.go index d3ce12ad..e080eb85 100644 --- a/pkg/cdi/regressions_test.go +++ b/pkg/cdi/regressions_test.go @@ -148,12 +148,18 @@ func withCDI(t *testing.T, annotations map[string]string, cdiSpecDirs []string) return nil } - registry := GetRegistry(WithSpecDirs(cdiSpecDirs...)) - if err = registry.Refresh(); err != nil { - t.Logf("CDI registry refresh failed: %v", err) + cache, err := NewCache( + WithSpecDirs(cdiSpecDirs...), + ) + if err != nil { + return fmt.Errorf("CDI cache creation failed: %w", err) + } + + if err = cache.Refresh(); err != nil { + t.Logf("CDI cache refresh failed: %v", err) } - if _, err := registry.InjectDevices(s, cdiDevices...); err != nil { + if _, err = cache.InjectDevices(s, cdiDevices...); err != nil { return fmt.Errorf("CDI device injection failed: %w", err) } diff --git a/pkg/cdi/spec-dirs.go b/pkg/cdi/spec-dirs.go index 09005d69..b192f962 100644 --- a/pkg/cdi/spec-dirs.go +++ b/pkg/cdi/spec-dirs.go @@ -35,8 +35,7 @@ var ( // 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. + // effective if it takes place before creating the cache instance. DefaultSpecDirs = []string{DefaultStaticDir, DefaultDynamicDir} // ErrStopScan can be returned from a ScanSpecFunc to stop the scan. ErrStopScan = errors.New("stop Spec scan") From 602c0935899495e1bf78080e883700ede46127e6 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 28 Aug 2024 11:17:48 +0200 Subject: [PATCH 2/2] Fix docstring whitespace Signed-off-by: Evan Lezar --- pkg/cdi/doc.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/cdi/doc.go b/pkg/cdi/doc.go index e5bdd845..d00e0d33 100644 --- a/pkg/cdi/doc.go +++ b/pkg/cdi/doc.go @@ -97,7 +97,7 @@ // ) // // func injectCDIDevices(spec *specs.Spec, devices []string) error { -// cache := cdi.GetDefaultCache() +// cache := cdi.GetDefaultCache() // // if err := cache.Refresh(); err != nil { // // Note: @@ -169,14 +169,14 @@ // Generating a Spec file for a vendor/device class can be done with a // code snippet similar to the following: // -// import ( +// import ( // // "fmt" // ... // "tags.cncf.io/container-device-interface/specs-go" // "tags.cncf.io/container-device-interface/pkg/cdi" // -// ) +// ) // // func generateDeviceSpecs() error { // cache := specs.GetDefaultCache() @@ -206,14 +206,14 @@ // They are typically created before the associated container is created // and removed once that container is removed. // -// import ( +// import ( // // "fmt" -// +// ... // "tags.cncf.io/container-device-interface/specs-go" // "tags.cncf.io/container-device-interface/pkg/cdi" // -// ) +// ) // // func generateTransientSpec(ctr Container) error { // cache := specs.GetDefaultCache()