diff --git a/cmd/cdi/cmd/cdi-api.go b/cmd/cdi/cmd/cdi-api.go index 7f42350..ed89d52 100644 --- a/cmd/cdi/cmd/cdi-api.go +++ b/cmd/cdi/cmd/cdi-api.go @@ -25,6 +25,7 @@ import ( oci "github.com/opencontainers/runtime-spec/specs-go" gen "github.com/opencontainers/runtime-tools/generate" "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/pkg/parser" ) func cdiListVendors() { @@ -230,7 +231,7 @@ func collectCDIDevicesFromOCISpec(spec *oci.Spec) []string { g.ClearLinuxDevices() for _, d := range devices { - if !cdi.IsQualifiedName(d.Path) { + if !parser.IsQualifiedName(d.Path) { g.AddDevice(d) continue } diff --git a/pkg/cdi/annotations.go b/pkg/cdi/annotations.go index a38b0f1..a596c61 100644 --- a/pkg/cdi/annotations.go +++ b/pkg/cdi/annotations.go @@ -71,7 +71,7 @@ func ParseAnnotations(annotations map[string]string) ([]string, []string, error) continue } for _, d := range strings.Split(value, ",") { - if !IsQualifiedName(d) { + if !parser.IsQualifiedName(d) { return nil, nil, fmt.Errorf("invalid CDI device name %q", d) } devices = append(devices, d) @@ -130,7 +130,7 @@ func AnnotationKey(pluginName, deviceID string) (string, error) { func AnnotationValue(devices []string) (string, error) { value, sep := "", "" for _, d := range devices { - if _, _, _, err := ParseQualifiedName(d); err != nil { + if _, _, _, err := parser.ParseQualifiedName(d); err != nil { return "", err } value += sep + d diff --git a/pkg/cdi/device.go b/pkg/cdi/device.go index 00be48d..2e5fa57 100644 --- a/pkg/cdi/device.go +++ b/pkg/cdi/device.go @@ -67,7 +67,7 @@ func (d *Device) edits() *ContainerEdits { // Validate the device. func (d *Device) validate() error { - if err := ValidateDeviceName(d.Name); err != nil { + if err := parser.ValidateDeviceName(d.Name); err != nil { return err } name := d.Name diff --git a/pkg/cdi/qualified-device.go b/pkg/cdi/qualified-device.go deleted file mode 100644 index 0bdfdc1..0000000 --- a/pkg/cdi/qualified-device.go +++ /dev/null @@ -1,113 +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 ( - "tags.cncf.io/container-device-interface/pkg/parser" -) - -// QualifiedName returns the qualified name for a device. -// The syntax for a qualified device names is -// -// "/=". -// -// 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 QualifiedName(vendor, class, name string) string { - return parser.QualifiedName(vendor, class, name) -} - -// IsQualifiedName tests if a device name is qualified. -// -// Deprecated: use parser.IsQualifiedName instead -func IsQualifiedName(device string) bool { - return parser.IsQualifiedName(device) -} - -// 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 ParseQualifiedName(device string) (string, string, string, error) { - return parser.ParseQualifiedName(device) -} - -// 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 ParseDevice(device string) (string, string, string) { - return parser.ParseDevice(device) -} - -// ParseQualifier splits a device qualifier into vendor and class. -// The syntax for a device qualifier is -// -// "/" -// -// If parsing fails, an empty vendor and the class set to the -// verbatim input is returned. -// -// Deprecated: use parser.ParseQualifier instead -func ParseQualifier(kind string) (string, string) { - return parser.ParseQualifier(kind) -} - -// 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 -func ValidateVendorName(vendor string) error { - return parser.ValidateVendorName(vendor) -} - -// 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 ValidateClassName(class string) error { - return parser.ValidateClassName(class) -} - -// 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 ValidateDeviceName(name string) error { - return parser.ValidateDeviceName(name) -} diff --git a/pkg/cdi/qualified-device_test.go b/pkg/cdi/qualified-device_test.go deleted file mode 100644 index c4f3f2f..0000000 --- a/pkg/cdi/qualified-device_test.go +++ /dev/null @@ -1,153 +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 ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestQualifiedName(t *testing.T) { - type testCase = struct { - device string - vendor string - class string - name string - isQualified bool - isParsable bool - } - - for _, tc := range []*testCase{ - { - device: "vendor.com/class=dev", - vendor: "vendor.com", - class: "class", - name: "dev", - isQualified: true, - }, - { - device: "vendor.com/class=0", - vendor: "vendor.com", - class: "class", - name: "0", - isQualified: true, - }, - { - device: "vendor1.com/class1=dev1", - vendor: "vendor1.com", - class: "class1", - name: "dev1", - isQualified: true, - }, - { - device: "vendor1.com/class.subclass=dev1", - vendor: "vendor1.com", - class: "class.subclass", - name: "dev1", - isQualified: true, - }, - { - device: "other-vendor1.com/class_1=dev_1", - vendor: "other-vendor1.com", - class: "class_1", - name: "dev_1", - isQualified: true, - }, - { - device: "yet_another-vendor2.com/c-lass_2=dev_1:2.3", - vendor: "yet_another-vendor2.com", - class: "c-lass_2", - name: "dev_1:2.3", - isQualified: true, - }, - { - device: "_invalid.com/class=dev", - vendor: "_invalid.com", - class: "class", - name: "dev", - isParsable: true, - }, - { - device: "invalid2.com-/class=dev", - vendor: "invalid2.com-", - class: "class", - name: "dev", - isParsable: true, - }, - { - device: "invalid3.com/_class=dev", - vendor: "invalid3.com", - class: "_class", - name: "dev", - isParsable: true, - }, - { - device: "invalid4.com/class_=dev", - vendor: "invalid4.com", - class: "class_", - name: "dev", - isParsable: true, - }, - { - device: "invalid5.com/class=-dev", - vendor: "invalid5.com", - class: "class", - name: "-dev", - isParsable: true, - }, - { - device: "invalid6.com/class=dev:", - vendor: "invalid6.com", - class: "class", - name: "dev:", - isParsable: true, - }, - { - device: "*.com/*dev=*gpu*", - vendor: "*.com", - class: "*dev", - name: "*gpu*", - isParsable: true, - }, - } { - t.Run(tc.name, func(t *testing.T) { - vendor, class, name, err := ParseQualifiedName(tc.device) - if tc.isQualified { - require.True(t, IsQualifiedName(tc.device), "qualified name %q", tc.device) - require.NoError(t, err) - require.Equal(t, tc.vendor, vendor, "qualified name %q", tc.device) - require.Equal(t, tc.class, class, "qualified name %q", tc.device) - require.Equal(t, tc.name, name, "qualified name %q", tc.device) - - vendor, class, name = ParseDevice(tc.device) - require.Equal(t, tc.vendor, vendor, "parsed name %q", tc.device) - require.Equal(t, tc.class, class, "parse name %q", tc.device) - require.Equal(t, tc.name, name, "parsed name %q", tc.device) - - device := QualifiedName(vendor, class, name) - require.Equal(t, tc.device, device, "constructed device %q", tc.device) - } else if tc.isParsable { - require.False(t, IsQualifiedName(tc.device), "parsed name %q", tc.device) - vendor, class, name = ParseDevice(tc.device) - require.Equal(t, tc.vendor, vendor, "parsed name %q", tc.device) - require.Equal(t, tc.class, class, "parse name %q", tc.device) - require.Equal(t, tc.name, name, "parsed name %q", tc.device) - } - }) - } -} diff --git a/pkg/cdi/spec.go b/pkg/cdi/spec.go index 6ee986e..f0231d8 100644 --- a/pkg/cdi/spec.go +++ b/pkg/cdi/spec.go @@ -28,6 +28,7 @@ import ( "sigs.k8s.io/yaml" "tags.cncf.io/container-device-interface/internal/validation" + "tags.cncf.io/container-device-interface/pkg/parser" cdi "tags.cncf.io/container-device-interface/specs-go" ) @@ -105,7 +106,7 @@ func newSpec(raw *cdi.Spec, path string, priority int) (*Spec, error) { spec.path += defaultSpecExt } - spec.vendor, spec.class = ParseQualifier(spec.Kind) + spec.vendor, spec.class = parser.ParseQualifier(spec.Kind) if spec.devices, err = spec.validate(); err != nil { return nil, fmt.Errorf("invalid CDI Spec: %w", err) @@ -211,10 +212,10 @@ func (s *Spec) validate() (map[string]*Device, error) { if err := cdi.ValidateVersion(s.Spec); err != nil { return nil, err } - if err := ValidateVendorName(s.vendor); err != nil { + if err := parser.ValidateVendorName(s.vendor); err != nil { return nil, err } - if err := ValidateClassName(s.class); err != nil { + if err := parser.ValidateClassName(s.class); err != nil { return nil, err } if err := validation.ValidateSpecAnnotations(s.Kind, s.Annotations); err != nil { @@ -316,7 +317,7 @@ func GenerateTransientSpecName(vendor, class, transientID string) string { // the Spec does not contain a valid vendor or class, it returns // an empty name and a non-nil error. func GenerateNameForSpec(raw *cdi.Spec) (string, error) { - vendor, class := ParseQualifier(raw.Kind) + vendor, class := parser.ParseQualifier(raw.Kind) if vendor == "" { return "", fmt.Errorf("invalid vendor/class %q in Spec", raw.Kind) } @@ -330,7 +331,7 @@ func GenerateNameForSpec(raw *cdi.Spec) (string, error) { // If the Spec does not contain a valid vendor or class, it returns an // an empty name and a non-nil error. func GenerateNameForTransientSpec(raw *cdi.Spec, transientID string) (string, error) { - vendor, class := ParseQualifier(raw.Kind) + vendor, class := parser.ParseQualifier(raw.Kind) if vendor == "" { return "", fmt.Errorf("invalid vendor/class %q in Spec", raw.Kind) }