diff --git a/pkg/apis/resource/types.go b/pkg/apis/resource/types.go index 65fb34f9a14..ab58317d914 100644 --- a/pkg/apis/resource/types.go +++ b/pkg/apis/resource/types.go @@ -988,6 +988,14 @@ type ResourceClaimTemplateList struct { Items []ResourceClaimTemplate } +const ( + AllocatedDeviceStatusMaxConditions int = 8 + AllocatedDeviceStatusDataMaxLength int = OpaqueParametersMaxLength + NetworkDeviceDataMaxIPs int = 16 + NetworkDeviceDataInterfaceNameMaxLength int = 256 + NetworkDeviceDataHardwareAddressMaxLength int = 128 +) + // AllocatedDeviceStatus contains the status of an allocated device, if the // driver chooses to report it. This may include driver-specific information. type AllocatedDeviceStatus struct { diff --git a/pkg/apis/resource/validation/validation.go b/pkg/apis/resource/validation/validation.go index 2f58721ddc1..9a357c9bc07 100644 --- a/pkg/apis/resource/validation/validation.go +++ b/pkg/apis/resource/validation/validation.go @@ -256,7 +256,7 @@ func validateDeviceConfiguration(config resource.DeviceConfiguration, fldPath *f func validateOpaqueConfiguration(config resource.OpaqueDeviceConfiguration, fldPath *field.Path, stored bool) field.ErrorList { var allErrs field.ErrorList allErrs = append(allErrs, validateDriverName(config.Driver, fldPath.Child("driver"))...) - allErrs = append(allErrs, validateRawExtension(config.Parameters, fldPath.Child("parameters"), stored)...) + allErrs = append(allErrs, validateRawExtension(config.Parameters, fldPath.Child("parameters"), stored, resource.OpaqueParametersMaxLength)...) return allErrs } @@ -748,29 +748,29 @@ func validateDeviceStatus(device resource.AllocatedDeviceStatus, fldPath *field. if !allocatedDevices.Has(deviceID) { allErrs = append(allErrs, field.Invalid(fldPath, deviceID, "must be an allocated device in the claim")) } - if len(device.Conditions) > maxConditions { - allErrs = append(allErrs, field.TooMany(fldPath.Child("conditions"), len(device.Conditions), maxConditions)) + if len(device.Conditions) > resource.AllocatedDeviceStatusMaxConditions { + allErrs = append(allErrs, field.TooMany(fldPath.Child("conditions"), len(device.Conditions), resource.AllocatedDeviceStatusMaxConditions)) } allErrs = append(allErrs, metav1validation.ValidateConditions(device.Conditions, fldPath.Child("conditions"))...) if len(device.Data.Raw) > 0 { // Data is an optional field. - allErrs = append(allErrs, validateRawExtension(device.Data, fldPath.Child("data"), false)...) + allErrs = append(allErrs, validateRawExtension(device.Data, fldPath.Child("data"), false, resource.AllocatedDeviceStatusDataMaxLength)...) } allErrs = append(allErrs, validateNetworkDeviceData(device.NetworkData, fldPath.Child("networkData"))...) return allErrs } // validateRawExtension validates RawExtension as in https://github.com/kubernetes/kubernetes/pull/125549/ -func validateRawExtension(rawExtension runtime.RawExtension, fldPath *field.Path, stored bool) field.ErrorList { +func validateRawExtension(rawExtension runtime.RawExtension, fldPath *field.Path, stored bool, rawExtensionMaxLength int) field.ErrorList { var allErrs field.ErrorList var v any if len(rawExtension.Raw) == 0 { allErrs = append(allErrs, field.Required(fldPath, "")) - } else if !stored && len(rawExtension.Raw) > resource.OpaqueParametersMaxLength { + } else if !stored && len(rawExtension.Raw) > rawExtensionMaxLength { // Don't even bother with parsing when too large. // Only applies on create. Existing parameters are grand-fathered in // because the limit was introduced in 1.32. This also means that it // can be changed in the future. - allErrs = append(allErrs, field.TooLong(fldPath, "" /* unused */, resource.OpaqueParametersMaxLength)) + allErrs = append(allErrs, field.TooLong(fldPath, "" /* unused */, rawExtensionMaxLength)) } else if err := json.Unmarshal(rawExtension.Raw, &v); err != nil { allErrs = append(allErrs, field.Invalid(fldPath, "", fmt.Sprintf("error parsing data as JSON: %v", err.Error()))) } else if v == nil { @@ -781,26 +781,21 @@ func validateRawExtension(rawExtension runtime.RawExtension, fldPath *field.Path return allErrs } -const maxConditions int = 8 -const maxIPs int = 16 -const interfaceNameMaxLength int = 256 -const hardwareAddressMaxLength int = 128 - func validateNetworkDeviceData(networkDeviceData *resource.NetworkDeviceData, fldPath *field.Path) field.ErrorList { var allErrs field.ErrorList if networkDeviceData == nil { return allErrs } - if len(networkDeviceData.InterfaceName) > interfaceNameMaxLength { - allErrs = append(allErrs, field.TooLong(fldPath.Child("interfaceName"), "" /* unused */, interfaceNameMaxLength)) + if len(networkDeviceData.InterfaceName) > resource.NetworkDeviceDataInterfaceNameMaxLength { + allErrs = append(allErrs, field.TooLong(fldPath.Child("interfaceName"), "" /* unused */, resource.NetworkDeviceDataInterfaceNameMaxLength)) } - if len(networkDeviceData.HardwareAddress) > hardwareAddressMaxLength { - allErrs = append(allErrs, field.TooLong(fldPath.Child("hardwareAddress"), "" /* unused */, hardwareAddressMaxLength)) + if len(networkDeviceData.HardwareAddress) > resource.NetworkDeviceDataHardwareAddressMaxLength { + allErrs = append(allErrs, field.TooLong(fldPath.Child("hardwareAddress"), "" /* unused */, resource.NetworkDeviceDataHardwareAddressMaxLength)) } - allErrs = append(allErrs, validateSet(networkDeviceData.IPs, maxIPs, + allErrs = append(allErrs, validateSet(networkDeviceData.IPs, resource.NetworkDeviceDataMaxIPs, func(address string, fldPath *field.Path) field.ErrorList { return validation.IsValidCIDR(fldPath, address) }, diff --git a/pkg/apis/resource/validation/validation_resourceclaim_test.go b/pkg/apis/resource/validation/validation_resourceclaim_test.go index c48a5bd3079..78d30c5ac00 100644 --- a/pkg/apis/resource/validation/validation_resourceclaim_test.go +++ b/pkg/apis/resource/validation/validation_resourceclaim_test.go @@ -1055,8 +1055,8 @@ func TestValidateClaimStatusUpdate(t *testing.T) { }, "invalid-network-device-status": { wantFailures: field.ErrorList{ - field.TooLong(field.NewPath("status", "devices").Index(0).Child("networkData", "interfaceName"), "", interfaceNameMaxLength), - field.TooLong(field.NewPath("status", "devices").Index(0).Child("networkData", "hardwareAddress"), "", hardwareAddressMaxLength), + field.TooLong(field.NewPath("status", "devices").Index(0).Child("networkData", "interfaceName"), "", resource.NetworkDeviceDataInterfaceNameMaxLength), + field.TooLong(field.NewPath("status", "devices").Index(0).Child("networkData", "hardwareAddress"), "", resource.NetworkDeviceDataHardwareAddressMaxLength), field.Invalid(field.NewPath("status", "devices").Index(0).Child("networkData", "ips").Index(0), "300.9.8.0/24", "must be a valid CIDR value, (e.g. 10.9.8.0/24 or 2001:db8::/64)"), }, oldClaim: func() *resource.ResourceClaim { return validAllocatedClaim }(), @@ -1067,8 +1067,8 @@ func TestValidateClaimStatusUpdate(t *testing.T) { Pool: goodName, Device: goodName, NetworkData: &resource.NetworkDeviceData{ - InterfaceName: strings.Repeat("x", interfaceNameMaxLength+1), - HardwareAddress: strings.Repeat("x", hardwareAddressMaxLength+1), + InterfaceName: strings.Repeat("x", resource.NetworkDeviceDataInterfaceNameMaxLength+1), + HardwareAddress: strings.Repeat("x", resource.NetworkDeviceDataHardwareAddressMaxLength+1), IPs: []string{ "300.9.8.0/24", }, @@ -1101,9 +1101,9 @@ func TestValidateClaimStatusUpdate(t *testing.T) { }, "invalid-data-device-status-limits": { wantFailures: field.ErrorList{ - field.TooMany(field.NewPath("status", "devices").Index(0).Child("conditions"), maxConditions+1, maxConditions), - field.TooLong(field.NewPath("status", "devices").Index(0).Child("data"), "" /* unused */, resource.OpaqueParametersMaxLength), - field.TooMany(field.NewPath("status", "devices").Index(0).Child("networkData", "ips"), maxIPs+1, maxIPs), + field.TooMany(field.NewPath("status", "devices").Index(0).Child("conditions"), resource.AllocatedDeviceStatusMaxConditions+1, resource.AllocatedDeviceStatusMaxConditions), + field.TooLong(field.NewPath("status", "devices").Index(0).Child("data"), "" /* unused */, resource.AllocatedDeviceStatusDataMaxLength), + field.TooMany(field.NewPath("status", "devices").Index(0).Child("networkData", "ips"), resource.NetworkDeviceDataMaxIPs+1, resource.NetworkDeviceDataMaxIPs), }, oldClaim: func() *resource.ResourceClaim { return validAllocatedClaim }(), update: func(claim *resource.ResourceClaim) *resource.ResourceClaim { @@ -1112,7 +1112,7 @@ func TestValidateClaimStatusUpdate(t *testing.T) { Driver: goodName, Pool: goodName, Device: goodName, - Data: runtime.RawExtension{Raw: []byte(`{"str": "` + strings.Repeat("x", resource.OpaqueParametersMaxLength-9-2+1 /* too large by one */) + `"}`)}, + Data: runtime.RawExtension{Raw: []byte(`{"str": "` + strings.Repeat("x", resource.AllocatedDeviceStatusDataMaxLength-9-2+1 /* too large by one */) + `"}`)}, Conditions: []metav1.Condition{ {Type: "test-0", Status: metav1.ConditionTrue, Reason: "test_reason", LastTransitionTime: metav1.Now(), ObservedGeneration: 0}, {Type: "test-1", Status: metav1.ConditionTrue, Reason: "test_reason", LastTransitionTime: metav1.Now(), ObservedGeneration: 0}, @@ -1184,8 +1184,8 @@ func TestValidateClaimStatusUpdate(t *testing.T) { }, "invalid-network-device-status-disabled-feature-gate": { wantFailures: field.ErrorList{ - field.TooLong(field.NewPath("status", "devices").Index(0).Child("networkData", "interfaceName"), "", interfaceNameMaxLength), - field.TooLong(field.NewPath("status", "devices").Index(0).Child("networkData", "hardwareAddress"), "", hardwareAddressMaxLength), + field.TooLong(field.NewPath("status", "devices").Index(0).Child("networkData", "interfaceName"), "", resource.NetworkDeviceDataInterfaceNameMaxLength), + field.TooLong(field.NewPath("status", "devices").Index(0).Child("networkData", "hardwareAddress"), "", resource.NetworkDeviceDataHardwareAddressMaxLength), field.Invalid(field.NewPath("status", "devices").Index(0).Child("networkData", "ips").Index(0), "300.9.8.0/24", "must be a valid CIDR value, (e.g. 10.9.8.0/24 or 2001:db8::/64)"), }, oldClaim: func() *resource.ResourceClaim { return validAllocatedClaim }(), @@ -1196,8 +1196,8 @@ func TestValidateClaimStatusUpdate(t *testing.T) { Pool: goodName, Device: goodName, NetworkData: &resource.NetworkDeviceData{ - InterfaceName: strings.Repeat("x", interfaceNameMaxLength+1), - HardwareAddress: strings.Repeat("x", hardwareAddressMaxLength+1), + InterfaceName: strings.Repeat("x", resource.NetworkDeviceDataInterfaceNameMaxLength+1), + HardwareAddress: strings.Repeat("x", resource.NetworkDeviceDataHardwareAddressMaxLength+1), IPs: []string{ "300.9.8.0/24", }, @@ -1230,9 +1230,9 @@ func TestValidateClaimStatusUpdate(t *testing.T) { }, "invalid-data-device-status-limits-feature-gate": { wantFailures: field.ErrorList{ - field.TooMany(field.NewPath("status", "devices").Index(0).Child("conditions"), maxConditions+1, maxConditions), - field.TooLong(field.NewPath("status", "devices").Index(0).Child("data"), "" /* unused */, resource.OpaqueParametersMaxLength), - field.TooMany(field.NewPath("status", "devices").Index(0).Child("networkData", "ips"), maxIPs+1, maxIPs), + field.TooMany(field.NewPath("status", "devices").Index(0).Child("conditions"), resource.AllocatedDeviceStatusMaxConditions+1, resource.AllocatedDeviceStatusMaxConditions), + field.TooLong(field.NewPath("status", "devices").Index(0).Child("data"), "" /* unused */, resource.AllocatedDeviceStatusDataMaxLength), + field.TooMany(field.NewPath("status", "devices").Index(0).Child("networkData", "ips"), resource.NetworkDeviceDataMaxIPs+1, resource.NetworkDeviceDataMaxIPs), }, oldClaim: func() *resource.ResourceClaim { return validAllocatedClaim }(), update: func(claim *resource.ResourceClaim) *resource.ResourceClaim { @@ -1241,7 +1241,7 @@ func TestValidateClaimStatusUpdate(t *testing.T) { Driver: goodName, Pool: goodName, Device: goodName, - Data: runtime.RawExtension{Raw: []byte(`{"str": "` + strings.Repeat("x", resource.OpaqueParametersMaxLength-9-2+1 /* too large by one */) + `"}`)}, + Data: runtime.RawExtension{Raw: []byte(`{"str": "` + strings.Repeat("x", resource.AllocatedDeviceStatusDataMaxLength-9-2+1 /* too large by one */) + `"}`)}, Conditions: []metav1.Condition{ {Type: "test-0", Status: metav1.ConditionTrue, Reason: "test_reason", LastTransitionTime: metav1.Now(), ObservedGeneration: 0}, {Type: "test-1", Status: metav1.ConditionTrue, Reason: "test_reason", LastTransitionTime: metav1.Now(), ObservedGeneration: 0}, diff --git a/staging/src/k8s.io/api/resource/v1alpha3/types.go b/staging/src/k8s.io/api/resource/v1alpha3/types.go index e3d7fd8945b..b023d792c1a 100644 --- a/staging/src/k8s.io/api/resource/v1alpha3/types.go +++ b/staging/src/k8s.io/api/resource/v1alpha3/types.go @@ -999,6 +999,14 @@ type ResourceClaimTemplateList struct { Items []ResourceClaimTemplate `json:"items" protobuf:"bytes,2,rep,name=items"` } +const ( + AllocatedDeviceStatusMaxConditions int = 8 + AllocatedDeviceStatusDataMaxLength int = OpaqueParametersMaxLength + NetworkDeviceDataMaxIPs int = 16 + NetworkDeviceDataInterfaceNameMaxLength int = 256 + NetworkDeviceDataHardwareAddressMaxLength int = 128 +) + // AllocatedDeviceStatus contains the status of an allocated device, if the // driver chooses to report it. This may include driver-specific information. type AllocatedDeviceStatus struct { @@ -1031,6 +1039,8 @@ type AllocatedDeviceStatus struct { // If the device has been configured according to the class and claim // config references, the `Ready` condition should be True. // + // Must not contain more than 8 entries. + // // +optional // +listType=map // +listMapKey=type @@ -1068,6 +1078,8 @@ type NetworkDeviceData struct { // associated subnet mask. // e.g.: "192.0.2.5/24" for IPv4 and "2001:db8::5/64" for IPv6. // + // Must not contain more than 16 entries. + // // +optional // +listType=atomic IPs []string `json:"ips,omitempty" protobuf:"bytes,2,opt,name=ips"` diff --git a/staging/src/k8s.io/api/resource/v1beta1/types.go b/staging/src/k8s.io/api/resource/v1beta1/types.go index a7f1ee7b54f..d5a238f90f1 100644 --- a/staging/src/k8s.io/api/resource/v1beta1/types.go +++ b/staging/src/k8s.io/api/resource/v1beta1/types.go @@ -1002,6 +1002,14 @@ type ResourceClaimTemplateList struct { Items []ResourceClaimTemplate `json:"items" protobuf:"bytes,2,rep,name=items"` } +const ( + AllocatedDeviceStatusMaxConditions int = 8 + AllocatedDeviceStatusDataMaxLength int = OpaqueParametersMaxLength + NetworkDeviceDataMaxIPs int = 16 + NetworkDeviceDataInterfaceNameMaxLength int = 256 + NetworkDeviceDataHardwareAddressMaxLength int = 128 +) + // AllocatedDeviceStatus contains the status of an allocated device, if the // driver chooses to report it. This may include driver-specific information. type AllocatedDeviceStatus struct { @@ -1034,6 +1042,8 @@ type AllocatedDeviceStatus struct { // If the device has been configured according to the class and claim // config references, the `Ready` condition should be True. // + // Must not contain more than 8 entries. + // // +optional // +listType=map // +listMapKey=type @@ -1071,6 +1081,8 @@ type NetworkDeviceData struct { // associated subnet mask. // e.g.: "192.0.2.5/24" for IPv4 and "2001:db8::5/64" for IPv6. // + // Must not contain more than 16 entries. + // // +optional // +listType=atomic IPs []string `json:"ips,omitempty" protobuf:"bytes,2,opt,name=ips"`