Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support dots in Kind name segment #137

Merged
merged 2 commits into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Released versions of the spec are available as Git tags.
| v0.4.0 | | Added `type` field to Mount specification |
| v0.5.0 | | Add `HostPath` to `DeviceNodes` |
| v0.6.0 | | Add `Annotations` field to `Spec` and `Device` specifications |
| | | Allow dots (`.`) in name segment of `Kind` field |

*Note*: The initial release of a **spec** with version `v0.x.0` will be tagged as
`v0.x.0` with subsequent changes to the API applicable to this version tagged as `v0.x.y`.
Expand Down
8 changes: 2 additions & 6 deletions pkg/cdi/qualified-device.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,10 @@ import (
//
// "<vendor>/<class>=<name>".
//
// A valid vendor name may contain the following runes:
// A valid vendor and class name may contain the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '.', '-', '_'.
//
// A valid class name may contain the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_'.
//
// A valid device name may containe the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_', '.', ':'
Expand Down Expand Up @@ -98,7 +94,7 @@ func ValidateVendorName(vendor string) error {
// A class name may contain the following ASCII characters:
// - upper- and lowercase letters ('A'-'Z', 'a'-'z')
// - digits ('0'-'9')
// - underscore and dash ('_', '-')
// - underscore, dash, and dot ('_', '-', and '.')
//
// Deprecated: use parser.ValidateClassName instead
func ValidateClassName(class string) error {
Expand Down
7 changes: 7 additions & 0 deletions pkg/cdi/qualified-device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ func TestQualifiedName(t *testing.T) {
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",
Expand Down
7 changes: 7 additions & 0 deletions pkg/cdi/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,13 @@ func TestRequiredVersion(t *testing.T) {
},
expectedVersion: "0.6.0",
},
{
description: "dotted name (class) label require v0.6.0",
spec: &cdi.Spec{
Kind: "vendor.com/class.sub",
},
expectedVersion: "0.6.0",
},
}

for _, tc := range testCases {
Expand Down
8 changes: 8 additions & 0 deletions pkg/cdi/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ func requiresV060(spec *cdi.Spec) bool {
}
}

// The v0.6.0 spec allows dots "." in Kind name label (class)
vendor, class := parser.ParseQualifier(spec.Kind)
if vendor != "" {
if strings.ContainsRune(class, '.') {
return true
}
}

return false
}

Expand Down
65 changes: 30 additions & 35 deletions pkg/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,10 @@ import (
//
// "<vendor>/<class>=<name>".
//
// A valid vendor name may contain the following runes:
// A valid vendor and class name may contain the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '.', '-', '_'.
//
// A valid class name may contain the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_'.
//
// A valid device name may containe the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_', '.', ':'
Expand Down Expand Up @@ -122,52 +118,51 @@ func ParseQualifier(kind string) (string, string) {
// - digits ('0'-'9')
// - underscore, dash, and dot ('_', '-', and '.')
func ValidateVendorName(vendor string) error {
if vendor == "" {
return fmt.Errorf("invalid (empty) vendor name")
}
if !IsLetter(rune(vendor[0])) {
return fmt.Errorf("invalid vendor %q, should start with letter", vendor)
}
for _, c := range string(vendor[1 : len(vendor)-1]) {
switch {
case IsAlphaNumeric(c):
case c == '_' || c == '-' || c == '.':
default:
return fmt.Errorf("invalid character '%c' in vendor name %q",
c, vendor)
}
}
if !IsAlphaNumeric(rune(vendor[len(vendor)-1])) {
return fmt.Errorf("invalid vendor %q, should end with a letter or digit", vendor)
err := validateVendorOrClassName(vendor)
if err != nil {
err = fmt.Errorf("invalid vendor. %w", err)
}

return nil
return err
}

// 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 and dash ('_', '-')
// - underscore, dash, and dot ('_', '-', and '.')
func ValidateClassName(class string) error {
if class == "" {
return fmt.Errorf("invalid (empty) device class")
err := validateVendorOrClassName(class)
if err != nil {
err = fmt.Errorf("invalid class. %w", err)
}
if !IsLetter(rune(class[0])) {
return fmt.Errorf("invalid class %q, should start with letter", class)
return err
}

// validateVendorOrClassName checks the validity of vendor or class name.
// A name may contain the following ASCII characters:
// - upper- and lowercase letters ('A'-'Z', 'a'-'z')
// - digits ('0'-'9')
// - underscore, dash, and dot ('_', '-', and '.')
func validateVendorOrClassName(name string) error {
if name == "" {
return fmt.Errorf("empty name")
}
for _, c := range string(class[1 : len(class)-1]) {
if !IsLetter(rune(name[0])) {
return fmt.Errorf("%q, should start with letter", name)
}
for _, c := range string(name[1 : len(name)-1]) {
switch {
case IsAlphaNumeric(c):
case c == '_' || c == '-':
case c == '_' || c == '-' || c == '.':
default:
return fmt.Errorf("invalid character '%c' in device class %q",
c, class)
return fmt.Errorf("invalid character '%c' in name %q",
c, name)
}
}
if !IsAlphaNumeric(rune(class[len(class)-1])) {
return fmt.Errorf("invalid class %q, should end with a letter or digit", class)
if !IsAlphaNumeric(rune(name[len(name)-1])) {
return fmt.Errorf("%q, should end with a letter or digit", name)
}

return nil
}

Expand Down
7 changes: 7 additions & 0 deletions pkg/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ func TestQualifiedName(t *testing.T) {
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",
Expand Down