DRA API: add maximum length of opaque parameters

This had been left out unintentionally earlier. Because theoretically there
might now be existing objects with parameters that are larger than whatever
limit gets enforced now, the limit only gets checked when parameters get
created or modified.

This is similar to the validation of CEL expressions and for consistency, the
same 10 Ki limit as for those is chosen.

Because the limit is not enforced for stored parameters, it can be increased in
the future, with the caveat that users who need larger parameters then depend
on the newer Kubernetes release with a higher limit. Lowering the limit is
harder because creating deployments that worked in older Kubernetes will not
work anymore with newer Kubernetes.
This commit is contained in:
Patrick Ohly
2024-11-06 09:42:47 +01:00
parent e273349f3a
commit 446f20aa3e
14 changed files with 209 additions and 26 deletions

View File

@@ -17,6 +17,7 @@ limitations under the License.
package validation
import (
"strings"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -227,6 +228,7 @@ func TestValidateClass(t *testing.T) {
field.Invalid(field.NewPath("spec", "config").Index(3).Child("opaque", "parameters"), "<value omitted>", "parameters must be a valid JSON object"),
field.Required(field.NewPath("spec", "config").Index(4).Child("opaque", "parameters"), ""),
field.Required(field.NewPath("spec", "config").Index(5).Child("opaque"), ""),
field.TooLong(field.NewPath("spec", "config").Index(7).Child("opaque", "parameters"), "" /* unused */, resource.OpaqueParametersMaxLength),
},
class: func() *resource.DeviceClass {
class := testClass(goodName)
@@ -272,6 +274,22 @@ func TestValidateClass(t *testing.T) {
{
DeviceConfiguration: resource.DeviceConfiguration{ /* Bad, empty. */ },
},
{
DeviceConfiguration: resource.DeviceConfiguration{
Opaque: &resource.OpaqueDeviceConfiguration{
Driver: goodName,
Parameters: runtime.RawExtension{Raw: []byte(`{"str": "` + strings.Repeat("x", resource.OpaqueParametersMaxLength-9-2) + `"}`)},
},
},
},
{
DeviceConfiguration: resource.DeviceConfiguration{
Opaque: &resource.OpaqueDeviceConfiguration{
Driver: goodName,
Parameters: runtime.RawExtension{Raw: []byte(`{"str": "` + strings.Repeat("x", resource.OpaqueParametersMaxLength-9-2+1 /* too large by one */) + `"}`)},
},
},
},
}
for i := len(class.Spec.Config); i < resource.DeviceConfigMaxSize; i++ {
class.Spec.Config = append(class.Spec.Config, validConfig)
@@ -321,6 +339,55 @@ func TestValidateClassUpdate(t *testing.T) {
oldClass: validClass,
update: func(class *resource.DeviceClass) *resource.DeviceClass { return class },
},
"valid-config-large": {
oldClass: validClass,
update: func(class *resource.DeviceClass) *resource.DeviceClass {
class.Spec.Config = []resource.DeviceClassConfiguration{{
DeviceConfiguration: resource.DeviceConfiguration{
Opaque: &resource.OpaqueDeviceConfiguration{
Driver: goodName,
Parameters: runtime.RawExtension{Raw: []byte(`{"str": "` + strings.Repeat("x", resource.OpaqueParametersMaxLength-9-2) + `"}`)},
},
},
}}
return class
},
},
"invalid-config-too-large": {
wantFailures: field.ErrorList{
field.TooLong(field.NewPath("spec", "config").Index(0).Child("opaque", "parameters"), "" /* unused */, resource.OpaqueParametersMaxLength),
},
oldClass: validClass,
update: func(class *resource.DeviceClass) *resource.DeviceClass {
class.Spec.Config = []resource.DeviceClassConfiguration{{
DeviceConfiguration: resource.DeviceConfiguration{
Opaque: &resource.OpaqueDeviceConfiguration{
Driver: goodName,
Parameters: runtime.RawExtension{Raw: []byte(`{"str": "` + strings.Repeat("x", resource.OpaqueParametersMaxLength-9-2+1 /* too large by one */) + `"}`)},
},
},
}}
return class
},
},
"too-large-config-valid-if-stored": {
oldClass: func() *resource.DeviceClass {
class := validClass.DeepCopy()
class.Spec.Config = []resource.DeviceClassConfiguration{{
DeviceConfiguration: resource.DeviceConfiguration{
Opaque: &resource.OpaqueDeviceConfiguration{
Driver: goodName,
Parameters: runtime.RawExtension{Raw: []byte(`{"str": "` + strings.Repeat("x", resource.OpaqueParametersMaxLength-9-2+1 /* too large by one */) + `"}`)},
},
},
}}
return class
}(),
update: func(class *resource.DeviceClass) *resource.DeviceClass {
// No changes -> remains valid.
return class
},
},
}
for name, scenario := range scenarios {