Address feedbacks

This commit is contained in:
Lalit Chauhan
2025-10-27 17:18:52 +00:00
parent 94101ba6e0
commit 37ba7bb454
14 changed files with 81 additions and 89 deletions

View File

@@ -33,6 +33,7 @@ import (
"k8s.io/apimachinery/pkg/api/operation"
apiresource "k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/api/validate"
"k8s.io/apimachinery/pkg/api/validate/content"
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/runtime"
@@ -1087,11 +1088,6 @@ func validateDeviceCounter(counter resource.Counter, fldPath *field.Path) field.
func validateQualifiedName(name resource.QualifiedName, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
if name == "" {
allErrs = append(allErrs, field.Required(fldPath, "name required"))
return allErrs
}
parts := strings.Split(string(name), "/")
switch len(parts) {
case 1:
@@ -1125,15 +1121,11 @@ func validateQualifiedName(name resource.QualifiedName, fldPath *field.Path) fie
func validateFullyQualifiedName(name resource.FullyQualifiedName, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
if name == "" {
allErrs = append(allErrs, field.Required(fldPath, "name required"))
return allErrs
}
allErrs = append(allErrs, validateQualifiedName(resource.QualifiedName(name), fldPath)...)
// validateQualifiedName checks that the name isn't empty and both parts are valid.
// validateQualifiedName checks that both parts are valid.
// What we need to enforce here is that there really is a domain.
if name != "" && !strings.Contains(string(name), "/") {
allErrs = append(allErrs, field.Invalid(fldPath, name, "must include a domain"))
if !strings.Contains(string(name), "/") {
allErrs = append(allErrs, field.Invalid(fldPath, name, "a fully qualified name must be a domain and a name separated by a slash"))
}
return allErrs.WithOrigin("format=k8s-resource-fully-qualified-name")
}
@@ -1143,7 +1135,7 @@ func validateCIdentifier(id string, fldPath *field.Path) field.ErrorList {
if len(id) > resource.DeviceMaxIDLength {
allErrs = append(allErrs, field.TooLong(fldPath, "" /*unused*/, resource.DeviceMaxIDLength))
}
for _, msg := range validation.IsCIdentifier(id) {
for _, msg := range content.IsCIdentifier(id) {
allErrs = append(allErrs, field.Invalid(fldPath, id, msg))
}
return allErrs

View File

@@ -263,8 +263,9 @@ func TestValidateClaim(t *testing.T) {
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("requests").Index(1), badName, "a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("requests").Index(1), badName, "must be the name of a request in the claim or the name of a request and a subrequest separated by '/'"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), "missing-domain", "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')").MarkCoveredByDeclarative(),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), resource.FullyQualifiedName("missing-domain"), "must include a domain").MarkCoveredByDeclarative(),
field.Required(field.NewPath("spec", "devices", "constraints").Index(1).Child("matchAttribute"), "name required").MarkCoveredByDeclarative(),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), resource.FullyQualifiedName("missing-domain"), "a fully qualified name must be a domain and a name separated by a slash").MarkCoveredByDeclarative(),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(1).Child("matchAttribute"), "", "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')").MarkCoveredByDeclarative(),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(1).Child("matchAttribute"), resource.FullyQualifiedName(""), "a fully qualified name must be a domain and a name separated by a slash").MarkCoveredByDeclarative(),
field.Required(field.NewPath("spec", "devices", "constraints").Index(2).Child("matchAttribute"), ""),
field.TooMany(field.NewPath("spec", "devices", "constraints"), resource.DeviceConstraintsMaxSize+1, resource.DeviceConstraintsMaxSize).MarkCoveredByDeclarative(),
field.Invalid(field.NewPath("spec", "devices", "config").Index(0).Child("requests").Index(1), badName, "a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')"),
@@ -322,8 +323,9 @@ func TestValidateClaim(t *testing.T) {
"invalid-distinct-constraint": {
wantFailures: field.ErrorList{
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("distinctAttribute"), "missing-domain", "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("distinctAttribute"), resource.FullyQualifiedName("missing-domain"), "must include a domain"),
field.Required(field.NewPath("spec", "devices", "constraints").Index(1).Child("distinctAttribute"), "name required"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("distinctAttribute"), resource.FullyQualifiedName("missing-domain"), "a fully qualified name must be a domain and a name separated by a slash"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(1).Child("distinctAttribute"), "", "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(1).Child("distinctAttribute"), resource.FullyQualifiedName(""), "a fully qualified name must be a domain and a name separated by a slash"),
field.Required(field.NewPath("spec", "devices", "constraints").Index(2), `exactly one of "matchAttribute" or "distinctAttribute" is required, but multiple fields are set`)},
claim: func() *resource.ResourceClaim {
claim := testClaim(goodName, goodNS, validClaimSpec)
@@ -375,8 +377,9 @@ func TestValidateClaim(t *testing.T) {
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("requests").Index(1), badName, "a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("requests").Index(1), badName, "must be the name of a request in the claim or the name of a request and a subrequest separated by '/'"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), "missing-domain", "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')").MarkCoveredByDeclarative(),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), resource.FullyQualifiedName("missing-domain"), "must include a domain").MarkCoveredByDeclarative(),
field.Required(field.NewPath("spec", "devices", "constraints").Index(1).Child("matchAttribute"), "name required").MarkCoveredByDeclarative(),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), resource.FullyQualifiedName("missing-domain"), "a fully qualified name must be a domain and a name separated by a slash").MarkCoveredByDeclarative(),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(1).Child("matchAttribute"), "", "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')").MarkCoveredByDeclarative(),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(1).Child("matchAttribute"), resource.FullyQualifiedName(""), "a fully qualified name must be a domain and a name separated by a slash").MarkCoveredByDeclarative(),
field.Required(field.NewPath("spec", "devices", "constraints").Index(2).Child("matchAttribute"), ""),
field.Invalid(field.NewPath("spec", "devices", "config").Index(0).Child("requests").Index(1), badName, "a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')"),
field.Invalid(field.NewPath("spec", "devices", "config").Index(0).Child("requests").Index(1), badName, "must be the name of a request in the claim or the name of a request and a subrequest separated by '/'"),

View File

@@ -406,7 +406,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
tweakMatchAttribute("nodomain"),
),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), "nodomain", "must include a domain").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), "nodomain", "a fully qualified name must be a domain and a name separated by a slash").WithOrigin("format=k8s-resource-fully-qualified-name"),
},
},
"match attribute empty": {
@@ -414,7 +414,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
tweakMatchAttribute(""),
),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), "name required"),
field.Invalid(field.NewPath("spec", "devices", "constraints").Index(0).Child("matchAttribute"), "", "").WithOrigin("format=k8s-resource-fully-qualified-name"),
},
},
"match attribute with empty domain": {

View File

@@ -568,6 +568,9 @@ const ResourceSliceMaxDeviceCountersPerSlice = 1024 // 64 * 16
type QualifiedName string
// FullyQualifiedName is a QualifiedName where the domain is set.
// Format validation cannot be added to this type because one of its usages,
// DistinctAttribute, is validated conditionally. This conditional validation
// cannot be expressed declaratively.
type FullyQualifiedName string
// DeviceMaxDomainLength is the maximum length of the domain prefix in a fully-qualified name.

View File

@@ -572,6 +572,9 @@ const ResourceSliceMaxDeviceCountersPerSlice = 1024 // 64 * 16
type QualifiedName string
// FullyQualifiedName is a QualifiedName where the domain is set.
// Format validation cannot be added to this type because one of its usages,
// DistinctAttribute, is validated conditionally. This conditional validation
// cannot be expressed declaratively.
type FullyQualifiedName string
// DeviceMaxDomainLength is the maximum length of the domain prefix in a fully-qualified name.

View File

@@ -568,6 +568,9 @@ const ResourceSliceMaxDeviceCountersPerSlice = 1024 // 64 * 16
type QualifiedName string
// FullyQualifiedName is a QualifiedName where the domain is set.
// Format validation cannot be added to this type because one of its usages,
// DistinctAttribute, is validated conditionally. This conditional validation
// cannot be expressed declaratively.
type FullyQualifiedName string
// DeviceMaxDomainLength is the maximum length of the domain prefix in a fully-qualified name.

View File

@@ -1,3 +1,19 @@
/*
Copyright 2025 The Kubernetes 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 content
import (

View File

@@ -1,3 +1,19 @@
/*
Copyright 2025 The Kubernetes 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 content
import (

View File

@@ -23,7 +23,6 @@ import (
"k8s.io/apimachinery/pkg/api/operation"
"k8s.io/apimachinery/pkg/api/validate/content"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
)
@@ -32,7 +31,7 @@ const (
defaultResourceRequestsPrefix = "requests."
// Default namespace prefix.
resourceDefaultNamespacePrefix = "kubernetes.io/"
cDeviceMaxLength = 32
resourceDeviceMaxLength = 32
)
// ShortName verifies that the specified value is a valid "short name"
@@ -234,15 +233,13 @@ func resourcesQualifiedName[T ~string](ctx context.Context, op operation.Operati
}
var allErrs field.ErrorList
s := string(*value)
if len(s) == 0 {
allErrs = append(allErrs, field.Required(fldPath, "name required"))
return allErrs
}
parts := strings.Split(s, "/")
// TODO: This validation and the corresponding handwritten validation validateQualifiedName in
// pkg/apis/resource/validation/validation.go are not validating whether there are more than 1
// slash. This should be fixed in both places.
switch len(parts) {
case 1:
allErrs = append(allErrs, validateCIdentifier(parts[0], fldPath)...)
allErrs = append(allErrs, validateCIdentifier(parts[0], resourceDeviceMaxLength, fldPath)...)
case 2:
if len(parts[0]) == 0 {
allErrs = append(allErrs, field.Invalid(fldPath, "", "prefix must not be empty"))
@@ -255,11 +252,8 @@ func resourcesQualifiedName[T ~string](ctx context.Context, op operation.Operati
if len(parts[1]) == 0 {
allErrs = append(allErrs, field.Invalid(fldPath, "", "name must not be empty"))
} else {
allErrs = append(allErrs, validateCIdentifier(parts[1], fldPath)...)
allErrs = append(allErrs, validateCIdentifier(parts[1], resourceDeviceMaxLength, fldPath)...)
}
// TODO: This validation and the corresponding handwritten validation validateQualifiedName in
// pkg/apis/resource/validation/validation.go are not validating whether there are more than 1
// slash. This should be fixed in both places.
}
return allErrs
}
@@ -276,25 +270,20 @@ func ResourceFullyQualifiedName[T ~string](ctx context.Context, op operation.Ope
return nil
}
var allErrs field.ErrorList
if len(*value) == 0 {
allErrs = append(allErrs, field.Required(fldPath, "name can't be empty"))
return allErrs
}
s := string(*value)
allErrs = append(allErrs, resourcesQualifiedName(ctx, op, fldPath, value, nil)...)
allErrs = append(allErrs, resourcesQualifiedName(ctx, op, fldPath, &s, nil)...)
if !strings.Contains(s, "/") {
allErrs = append(allErrs, field.Invalid(fldPath, s, "a fully qualified name must be a prefix and a name separated by a slash"))
allErrs = append(allErrs, field.Invalid(fldPath, s, "a fully qualified name must be a domain and a name separated by a slash"))
}
return allErrs.WithOrigin("format=k8s-resource-fully-qualified-name")
}
func validateCIdentifier(id string, fldPath *field.Path) field.ErrorList {
func validateCIdentifier(id string, length int, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
if len(id) > cDeviceMaxLength {
allErrs = append(allErrs, field.TooLong(fldPath, id, cDeviceMaxLength))
if len(id) > length {
allErrs = append(allErrs, field.TooLong(fldPath, id, length))
}
for _, msg := range validation.IsCIdentifier(id) {
for _, msg := range content.IsCIdentifier(id) {
allErrs = append(allErrs, field.Invalid(fldPath, id, msg))
}
return allErrs

View File

@@ -680,25 +680,26 @@ func TestResourceFullyQualifiedName(t *testing.T) {
name: "invalid name with dots",
input: "prefix.com/name.with.dots",
wantErrs: field.ErrorList{
field.Invalid(fldPath, "name.with.dots", "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Invalid(fldPath, "name.with.dots", "a valid C identifier must start with alphabetic character").WithOrigin("format=k8s-resource-fully-qualified-name"),
},
}, {
name: "invalid name with dashes",
input: "prefix.com/name-with-dashes",
wantErrs: field.ErrorList{
field.Invalid(fldPath, "name-with-dashes", "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_' (e.g. 'my_name', or 'MY_NAME', or 'MyName', regex used for validation is '[A-Za-z_][A-Za-z0-9_]*')").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Invalid(fldPath, "name-with-dashes", "a valid C identifier must start with alphabetic character").WithOrigin("format=k8s-resource-fully-qualified-name"),
},
}, {
name: "invalid: no prefix",
input: "name",
wantErrs: field.ErrorList{
field.Invalid(fldPath, "name", "a fully qualified name must be a prefix and a name separated by a slash").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Invalid(fldPath, "name", "a fully qualified name must be a domain and a name separated by a slash").WithOrigin("format=k8s-resource-fully-qualified-name"),
},
}, {
name: "invalid: empty",
input: "",
wantErrs: field.ErrorList{
field.Required(fldPath, "name can't be empty"),
field.Invalid(fldPath, "", "a fully qualified name must be a domain and a name separated by a slash").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Invalid(fldPath, "", "a valid C identifier must start with alphabetic character").WithOrigin("format=k8s-resource-fully-qualified-name"),
},
}, {
name: "invalid: prefix too long",
@@ -717,7 +718,7 @@ func TestResourceFullyQualifiedName(t *testing.T) {
name: "invalid: prefix is not a valid DNS subdomain",
input: "Prefix.com/name",
wantErrs: field.ErrorList{
field.Invalid(fldPath, "Prefix.com", "prefix: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Invalid(fldPath, "Prefix.com", "prefix: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters").WithOrigin("format=k8s-resource-fully-qualified-name"),
},
}, {
name: "invalid: name is not a valid RFC 1123 label",

View File

@@ -237,19 +237,10 @@ func IsWildcardDNS1123Subdomain(value string) []string {
return errs
}
const cIdentifierFmt string = "[A-Za-z_][A-Za-z0-9_]*"
const identifierErrMsg string = "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_'"
var cIdentifierRegexp = regexp.MustCompile("^" + cIdentifierFmt + "$")
// IsCIdentifier tests for a string that conforms the definition of an identifier
// in C. This checks the format, but not the length.
func IsCIdentifier(value string) []string {
if !cIdentifierRegexp.MatchString(value) {
return []string{RegexError(identifierErrMsg, cIdentifierFmt, "my_name", "MY_NAME", "MyName")}
}
return nil
}
// Deprecated: Use k8s.io/apimachinery/pkg/api/validate/content.IsCIdentifier instead.
var IsCIdentifier = content.IsCIdentifier
// IsValidPortNum tests that the argument is a valid, non-zero port number.
func IsValidPortNum(port int) []string {

View File

@@ -116,31 +116,6 @@ func TestIsDNS1035Label(t *testing.T) {
}
}
func TestIsCIdentifier(t *testing.T) {
goodValues := []string{
"a", "ab", "abc", "a1", "_a", "a_", "a_b", "a_1", "a__1__2__b", "__abc_123",
"A", "AB", "AbC", "A1", "_A", "A_", "A_B", "A_1", "A__1__2__B", "__123_ABC",
}
for _, val := range goodValues {
if msgs := IsCIdentifier(val); len(msgs) != 0 {
t.Errorf("expected true for '%s': %v", val, msgs)
}
}
badValues := []string{
"", "1", "123", "1a",
"-", "a-", "-a", "1-", "-1", "1_", "1_2",
".", "a.", ".a", "a.b", "1.", ".1", "1.2",
" ", "a ", " a", "a b", "1 ", " 1", "1 2",
"#a#",
}
for _, val := range badValues {
if msgs := IsCIdentifier(val); len(msgs) == 0 {
t.Errorf("expected false for '%s'", val)
}
}
}
func TestIsValidPortNum(t *testing.T) {
goodValues := []int{1, 2, 1000, 16384, 32768, 65535}
for _, val := range goodValues {

View File

@@ -38,9 +38,9 @@ func TestFullyQualifiedName(t *testing.T) {
FullyQualifiedNameTypedefField: "my-prefix/",
}
st.Value(invalidStruct).ExpectMatches(field.ErrorMatcher{}.ByType().ByOrigin().ByField(), field.ErrorList{
field.Invalid(field.NewPath("fullyQualifiedNameField"), "my_name", "").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Required(field.NewPath("fullyQualifiedNamePtrField"), ""),
field.Invalid(field.NewPath("fullyQualifiedNameTypedefField"), "my-prefix/", "").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Invalid(field.NewPath("fullyQualifiedNameField"), "my_name", "a fully qualified name must be a domain and a name separated by a slash").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Invalid(field.NewPath("fullyQualifiedNamePtrField"), "", "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_'").WithOrigin("format=k8s-resource-fully-qualified-name"),
field.Invalid(field.NewPath("fullyQualifiedNameTypedefField"), "my-prefix/", "name must not be empty").WithOrigin("format=k8s-resource-fully-qualified-name"),
})
// Test validation ratcheting
st.Value(invalidStruct).OldValue(invalidStruct).ExpectValid()

View File

@@ -143,7 +143,7 @@ func (ftv formatTagValidator) Docs() TagDoc {
Docs: "Deprecated: This field holds a case-insensitive Kubernetes \"long name\", aka a \"DNS subdomain\" value.",
}, {
Description: "k8s-resource-fully-qualified-name",
Docs: "This field holds a Kubernetes resource \"fully qualified name\" value.",
Docs: "This field holds a Kubernetes resource \"fully qualified name\" value. A fully qualified name must not be empty and must be composed of a prefix and a name, separated by a slash (e.g., \"prefix/name\"). The prefix must be a DNS subdomain, and the name part must be a C identifier with no more than 32 characters.",
}, {
Description: "k8s-resource-pool-name",
Docs: "This field holds value with one or more Kubernetes \"long name\" parts separated by `/` and no longer than 253 characters.",