Update generated files

This commit is contained in:
Hemant Kumar
2026-07-20 20:46:50 -04:00
parent 119f0c8b37
commit dbd670abfd
12 changed files with 686 additions and 17 deletions

View File

@@ -13068,11 +13068,11 @@
"description": "VolumeHealthCondition represents an adverse health condition reported for a volume.",
"properties": {
"message": {
"description": "message is a human-readable description. Maximum permitted length of a message is 1024 characters.",
"description": "message is a human-readable description. Maximum permitted length of a message is 1024 bytes.",
"type": "string"
},
"reason": {
"description": "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 characters.a",
"description": "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 bytes.",
"type": "string"
},
"status": {

View File

@@ -8340,12 +8340,12 @@
"description": "VolumeHealthCondition represents an adverse health condition reported for a volume.",
"properties": {
"message": {
"description": "message is a human-readable description. Maximum permitted length of a message is 1024 characters.",
"description": "message is a human-readable description. Maximum permitted length of a message is 1024 bytes.",
"type": "string"
},
"reason": {
"default": "",
"description": "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 characters.a",
"description": "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 bytes.",
"type": "string"
},
"status": {

View File

@@ -5141,12 +5141,12 @@
"description": "VolumeHealthCondition represents an adverse health condition reported for a volume.",
"properties": {
"message": {
"description": "message is a human-readable description. Maximum permitted length of a message is 1024 characters.",
"description": "message is a human-readable description. Maximum permitted length of a message is 1024 bytes.",
"type": "string"
},
"reason": {
"default": "",
"description": "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 characters.a",
"description": "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 bytes.",
"type": "string"
},
"status": {

View File

@@ -33,6 +33,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
runtime "k8s.io/apimachinery/pkg/runtime"
sets "k8s.io/apimachinery/pkg/util/sets"
field "k8s.io/apimachinery/pkg/util/validation/field"
)
@@ -711,7 +712,77 @@ func Validate_PersistentVolumeClaim(
}
// field corev1.PersistentVolumeClaim.Spec has no validation
// field corev1.PersistentVolumeClaim.Status has no validation
{ // field corev1.PersistentVolumeClaim.Status
fn := func(
fldPath *field.Path,
obj, oldObj *corev1.PersistentVolumeClaimStatus,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
}
// call the type's validation function
errs = append(errs, Validate_PersistentVolumeClaimStatus(ctx, op, fldPath, obj, oldObj)...)
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.PersistentVolumeClaim) *corev1.PersistentVolumeClaimStatus {
return &oldObj.Status
})
errs = append(errs, fn(fldPath.Child("status"), &obj.Status, oldVal, oldObj != nil)...)
}
return errs
}
// Validate_PersistentVolumeClaimStatus validates an instance of PersistentVolumeClaimStatus according
// to declarative validation rules in the API schema.
func Validate_PersistentVolumeClaimStatus(
ctx context.Context, op operation.Operation, fldPath *field.Path,
obj, oldObj *corev1.PersistentVolumeClaimStatus) (errs field.ErrorList) {
// field corev1.PersistentVolumeClaimStatus.Phase has no validation
// field corev1.PersistentVolumeClaimStatus.AccessModes has no validation
// field corev1.PersistentVolumeClaimStatus.Capacity has no validation
// field corev1.PersistentVolumeClaimStatus.Conditions has no validation
// field corev1.PersistentVolumeClaimStatus.AllocatedResources has no validation
// field corev1.PersistentVolumeClaimStatus.AllocatedResourceStatuses has no validation
// field corev1.PersistentVolumeClaimStatus.CurrentVolumeAttributesClassName has no validation
// field corev1.PersistentVolumeClaimStatus.ModifyVolumeStatus has no validation
{ // field corev1.PersistentVolumeClaimStatus.HealthStatus
fn := func(
fldPath *field.Path,
obj, oldObj *corev1.VolumeHealthStatus,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
}
// call field-attached validations
earlyReturn := false
if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 {
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
// call the type's validation function
errs = append(errs, Validate_VolumeHealthStatus(ctx, op, fldPath, obj, oldObj)...)
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.PersistentVolumeClaimStatus) *corev1.VolumeHealthStatus {
return oldObj.HealthStatus
})
errs = append(errs, fn(fldPath.Child("healthStatus"), obj.HealthStatus, oldVal, oldObj != nil)...)
}
return errs
}
@@ -767,7 +838,28 @@ func Validate_Pod(
errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...)
}
// field corev1.Pod.Status has no validation
{ // field corev1.Pod.Status
fn := func(
fldPath *field.Path,
obj, oldObj *corev1.PodStatus,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
}
// call the type's validation function
errs = append(errs, Validate_PodStatus(ctx, op, fldPath, obj, oldObj)...)
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.Pod) *corev1.PodStatus {
return &oldObj.Status
})
errs = append(errs, fn(fldPath.Child("status"), &obj.Status, oldVal, oldObj != nil)...)
}
return errs
}
@@ -854,6 +946,75 @@ func Validate_PodSpec(
return errs
}
// Validate_PodStatus validates an instance of PodStatus according
// to declarative validation rules in the API schema.
func Validate_PodStatus(
ctx context.Context, op operation.Operation, fldPath *field.Path,
obj, oldObj *corev1.PodStatus) (errs field.ErrorList) {
// field corev1.PodStatus.ObservedGeneration has no validation
// field corev1.PodStatus.Phase has no validation
// field corev1.PodStatus.Conditions has no validation
// field corev1.PodStatus.Message has no validation
// field corev1.PodStatus.Reason has no validation
// field corev1.PodStatus.NominatedNodeName has no validation
// field corev1.PodStatus.HostIP has no validation
// field corev1.PodStatus.HostIPs has no validation
// field corev1.PodStatus.PodIP has no validation
// field corev1.PodStatus.PodIPs has no validation
// field corev1.PodStatus.StartTime has no validation
// field corev1.PodStatus.InitContainerStatuses has no validation
// field corev1.PodStatus.ContainerStatuses has no validation
// field corev1.PodStatus.QOSClass has no validation
// field corev1.PodStatus.EphemeralContainerStatuses has no validation
// field corev1.PodStatus.Resize has no validation
// field corev1.PodStatus.ResourceClaimStatuses has no validation
// field corev1.PodStatus.ExtendedResourceClaimStatus has no validation
// field corev1.PodStatus.AllocatedResources has no validation
// field corev1.PodStatus.Resources has no validation
// field corev1.PodStatus.NodeAllocatableResourceClaimStatuses has no validation
{ // field corev1.PodStatus.VolumeHealth
fn := func(
fldPath *field.Path,
obj, oldObj []corev1.PodVolumeHealth,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
}
// call field-attached validations
earlyReturn := false
if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 {
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
// lists with map semantics require unique keys
if e := validate.ValSliceUnique(ctx, op, fldPath, obj, oldObj,
func(a *corev1.PodVolumeHealth, b *corev1.PodVolumeHealth) bool { return a.Name == b.Name }); len(e) != 0 {
errs = append(errs, e...)
}
// iterate the list and call the type's validation function
if e := validate.EachValSliceVal(ctx, op, fldPath, obj, oldObj,
func(a *corev1.PodVolumeHealth, b *corev1.PodVolumeHealth) bool { return a.Name == b.Name }, validate.SemanticDeepEqual, Validate_PodVolumeHealth); len(e) != 0 {
errs = append(errs, e...)
}
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.PodStatus) []corev1.PodVolumeHealth {
return oldObj.VolumeHealth
})
errs = append(errs, fn(fldPath.Child("volumeHealth"), obj.VolumeHealth, oldVal, oldObj != nil)...)
}
return errs
}
// Validate_PodTemplate validates an instance of PodTemplate according
// to declarative validation rules in the API schema.
func Validate_PodTemplate(
@@ -942,6 +1103,91 @@ func Validate_PodTemplateSpec(
return errs
}
// Validate_PodVolumeHealth validates an instance of PodVolumeHealth according
// to declarative validation rules in the API schema.
func Validate_PodVolumeHealth(
ctx context.Context, op operation.Operation, fldPath *field.Path,
obj, oldObj *corev1.PodVolumeHealth) (errs field.ErrorList) {
{ // field corev1.PodVolumeHealth.Name
fn := func(
fldPath *field.Path,
obj, oldObj *string,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) {
return nil
}
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.PodVolumeHealth) *string {
return &oldObj.Name
})
errs = append(errs, fn(fldPath.Child("name"), &obj.Name, oldVal, oldObj != nil)...)
}
{ // field corev1.PodVolumeHealth.HealthConditions
fn := func(
fldPath *field.Path,
obj, oldObj []corev1.VolumeHealthCondition,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
}
// call field-attached validations
earlyReturn := false
if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 16).MarkShortCircuit(); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 {
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
// lists with map semantics require unique keys
if e := validate.ValSliceUnique(ctx, op, fldPath, obj, oldObj,
func(a *corev1.VolumeHealthCondition, b *corev1.VolumeHealthCondition) bool {
return a.Status == b.Status && a.Reason == b.Reason
}); len(e) != 0 {
errs = append(errs, e...)
}
// iterate the list and call the type's validation function
if e := validate.EachValSliceVal(ctx, op, fldPath, obj, oldObj,
func(a *corev1.VolumeHealthCondition, b *corev1.VolumeHealthCondition) bool {
return a.Status == b.Status && a.Reason == b.Reason
}, validate.DirectEqual, Validate_VolumeHealthCondition); len(e) != 0 {
errs = append(errs, e...)
}
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.PodVolumeHealth) []corev1.VolumeHealthCondition {
return oldObj.HealthConditions
})
errs = append(errs, fn(fldPath.Child("healthConditions"), obj.HealthConditions, oldVal, oldObj != nil)...)
}
// field corev1.PodVolumeHealth.LastTransitionTime has no validation
return errs
}
// Validate_ReplicationController validates an instance of ReplicationController according
// to declarative validation rules in the API schema.
func Validate_ReplicationController(
@@ -1330,3 +1576,177 @@ func Validate_Toleration(
// field corev1.Toleration.TolerationSeconds has no validation
return errs
}
// Validate_VolumeHealthCondition validates an instance of VolumeHealthCondition according
// to declarative validation rules in the API schema.
func Validate_VolumeHealthCondition(
ctx context.Context, op operation.Operation, fldPath *field.Path,
obj, oldObj *corev1.VolumeHealthCondition) (errs field.ErrorList) {
{ // field corev1.VolumeHealthCondition.Status
fn := func(
fldPath *field.Path,
obj, oldObj *corev1.VolumeHealthStatusType,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) {
return nil
}
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
// call the type's validation function
errs = append(errs, Validate_VolumeHealthStatusType(ctx, op, fldPath, obj, oldObj)...)
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.VolumeHealthCondition) *corev1.VolumeHealthStatusType {
return &oldObj.Status
})
errs = append(errs, fn(fldPath.Child("status"), &obj.Status, oldVal, oldObj != nil)...)
}
{ // field corev1.VolumeHealthCondition.Reason
fn := func(
fldPath *field.Path,
obj, oldObj *string,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) {
return nil
}
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
if e := validate.MaxBytes(ctx, op, fldPath, obj, oldObj, 256); len(e) != 0 {
errs = append(errs, e...)
}
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.VolumeHealthCondition) *string {
return &oldObj.Reason
})
errs = append(errs, fn(fldPath.Child("reason"), &obj.Reason, oldVal, oldObj != nil)...)
}
{ // field corev1.VolumeHealthCondition.Message
fn := func(
fldPath *field.Path,
obj, oldObj *string,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) {
return nil
}
}
// call field-attached validations
earlyReturn := false
if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 {
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
if e := validate.MaxBytes(ctx, op, fldPath, obj, oldObj, 1024); len(e) != 0 {
errs = append(errs, e...)
}
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.VolumeHealthCondition) *string {
return &oldObj.Message
})
errs = append(errs, fn(fldPath.Child("message"), &obj.Message, oldVal, oldObj != nil)...)
}
return errs
}
// Validate_VolumeHealthStatus validates an instance of VolumeHealthStatus according
// to declarative validation rules in the API schema.
func Validate_VolumeHealthStatus(
ctx context.Context, op operation.Operation, fldPath *field.Path,
obj, oldObj *corev1.VolumeHealthStatus) (errs field.ErrorList) {
{ // field corev1.VolumeHealthStatus.HealthConditions
fn := func(
fldPath *field.Path,
obj, oldObj []corev1.VolumeHealthCondition,
oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update {
if equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
}
// call field-attached validations
earlyReturn := false
if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 16).MarkShortCircuit(); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 {
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
// lists with map semantics require unique keys
if e := validate.ValSliceUnique(ctx, op, fldPath, obj, oldObj,
func(a *corev1.VolumeHealthCondition, b *corev1.VolumeHealthCondition) bool {
return a.Status == b.Status && a.Reason == b.Reason
}); len(e) != 0 {
errs = append(errs, e...)
}
// iterate the list and call the type's validation function
if e := validate.EachValSliceVal(ctx, op, fldPath, obj, oldObj,
func(a *corev1.VolumeHealthCondition, b *corev1.VolumeHealthCondition) bool {
return a.Status == b.Status && a.Reason == b.Reason
}, validate.DirectEqual, Validate_VolumeHealthCondition); len(e) != 0 {
errs = append(errs, e...)
}
return
}
oldVal := safe.Field(oldObj,
func(oldObj *corev1.VolumeHealthStatus) []corev1.VolumeHealthCondition {
return oldObj.HealthConditions
})
errs = append(errs, fn(fldPath.Child("healthConditions"), obj.HealthConditions, oldVal, oldObj != nil)...)
}
// field corev1.VolumeHealthStatus.LastTransitionTime has no validation
return errs
}
var symbolsForVolumeHealthStatusType = sets.New(corev1.VolumeHealthDataLoss, corev1.VolumeHealthDegraded, corev1.VolumeHealthInaccessible)
// Validate_VolumeHealthStatusType validates an instance of VolumeHealthStatusType according
// to declarative validation rules in the API schema.
func Validate_VolumeHealthStatusType(
ctx context.Context, op operation.Operation, fldPath *field.Path,
obj, oldObj *corev1.VolumeHealthStatusType) (errs field.ErrorList) {
if e := validate.Enum(ctx, op, fldPath, obj, oldObj, symbolsForVolumeHealthStatusType, nil); len(e) != 0 {
errs = append(errs, e...)
}
return errs
}

View File

@@ -33251,7 +33251,7 @@ func schema_k8sio_api_core_v1_VolumeHealthCondition(ref common.ReferenceCallback
},
"reason": {
SchemaProps: spec.SchemaProps{
Description: "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 characters.a",
Description: "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 bytes.",
Default: "",
Type: []string{"string"},
Format: "",
@@ -33259,7 +33259,7 @@ func schema_k8sio_api_core_v1_VolumeHealthCondition(ref common.ReferenceCallback
},
"message": {
SchemaProps: spec.SchemaProps{
Description: "message is a human-readable description. Maximum permitted length of a message is 1024 characters.",
Description: "message is a human-readable description. Maximum permitted length of a message is 1024 bytes.",
Type: []string{"string"},
Format: "",
},

View File

@@ -3482,6 +3482,7 @@ message PersistentVolumeClaimStatus {
// for the volume bound to this claim.
// +featureGate=CSIVolumeHealth
// +optional
// +k8s:optional
optional VolumeHealthStatus healthStatus = 10;
}
@@ -5092,6 +5093,9 @@ message PodStatus {
// +optional
// +listType=map
// +listMapKey=name
// +k8s:optional
// +k8s:listType=map
// +k8s:listMapKey=name
repeated PodVolumeHealth volumeHealth = 22;
}
@@ -5137,6 +5141,8 @@ message PodTemplateSpec {
// reported by the CSI node plugin via the kubelet.
message PodVolumeHealth {
// name matches an entry in pod.spec.volumes.
// +required
// +k8s:required
optional string name = 1;
// conditions is the set of adverse conditions reported by
@@ -5148,6 +5154,11 @@ message PodVolumeHealth {
// +patchMergeKey=status
// +patchStrategy=merge
// +listMapKey=reason
// +k8s:optional
// +k8s:listType=map
// +k8s:listMapKey=status
// +k8s:listMapKey=reason
// +k8s:maxItems=16
repeated VolumeHealthCondition healthConditions = 2;
// lastTransitionTime is when the current set of conditions first appeared.
@@ -7030,17 +7041,23 @@ message VolumeDevice {
message VolumeHealthCondition {
// status is the machine-parseable health category.
// One of "Inaccessible", "DataLoss", "Degraded".
// +required
// +k8s:required
optional string status = 1;
// reason is a brief CamelCase machine-parseable reason.
// Together with status it forms the unique identity of a condition entry.
// Maximum permitted length of a reason is 256 characters.a
// Maximum permitted length of a reason is 256 bytes.
// +required
// +k8s:required
// +k8s:maxBytes=256
optional string reason = 2;
// message is a human-readable description.
// Maximum permitted length of a message is 1024 bytes.
// +optional
// Maximum permitted length of a message is 1024 characters.
// +k8s:optional
// +k8s:maxBytes=1024
optional string message = 3;
}
@@ -7056,6 +7073,11 @@ message VolumeHealthStatus {
// +patchMergeKey=status
// +patchStrategy=merge
// +listMapKey=reason
// +k8s:optional
// +k8s:listType=map
// +k8s:listMapKey=status
// +k8s:listMapKey=reason
// +k8s:maxItems=16
repeated VolumeHealthCondition healthConditions = 1;
// lastTransitionTime is when the current set of conditions first appeared.

View File

@@ -2818,8 +2818,8 @@ func (VolumeDevice) SwaggerDoc() map[string]string {
var map_VolumeHealthCondition = map[string]string{
"": "VolumeHealthCondition represents an adverse health condition reported for a volume.",
"status": "status is the machine-parseable health category. One of \"Inaccessible\", \"DataLoss\", \"Degraded\".",
"reason": "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 characters.a",
"message": "message is a human-readable description. Maximum permitted length of a message is 1024 characters.",
"reason": "reason is a brief CamelCase machine-parseable reason. Together with status it forms the unique identity of a condition entry. Maximum permitted length of a reason is 256 bytes.",
"message": "message is a human-readable description. Maximum permitted length of a message is 1024 bytes.",
}
func (VolumeHealthCondition) SwaggerDoc() map[string]string {

View File

@@ -32,10 +32,10 @@ type VolumeHealthConditionApplyConfiguration struct {
Status *corev1.VolumeHealthStatusType `json:"status,omitempty"`
// reason is a brief CamelCase machine-parseable reason.
// Together with status it forms the unique identity of a condition entry.
// Maximum permitted length of a reason is 256 characters.a
// Maximum permitted length of a reason is 256 bytes.
Reason *string `json:"reason,omitempty"`
// message is a human-readable description.
// Maximum permitted length of a message is 1024 characters.
// Maximum permitted length of a message is 1024 bytes.
Message *string `json:"message,omitempty"`
}

View File

@@ -17,12 +17,14 @@ limitations under the License.
package persistentvolumeclaim
import (
"strings"
"testing"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
apitesting "k8s.io/kubernetes/pkg/api/testing"
core "k8s.io/kubernetes/pkg/apis/core"
registry "k8s.io/kubernetes/pkg/registry/core/persistentvolumeclaim"
"k8s.io/kubernetes/test/declarative_validation/meta"
@@ -73,6 +75,82 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) {
meta.RunObjectMetaUpdateTestCases(t, ctx, &updateObj, registry.Strategy, meta.WithStringentFinalizerValidation())
}
func TestDeclarativeValidateStatusUpdate(t *testing.T) {
for _, apiVersion := range apiVersions {
ctx := genericapirequest.WithNamespace(genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{
APIPrefix: "api",
APIGroup: "",
APIVersion: apiVersion,
Resource: "persistentvolumeclaims",
Subresource: "status",
Name: "valid-obj",
IsResourceRequest: true,
Verb: "update",
}), metav1.NamespaceDefault)
tests := map[string]struct {
conditions []core.VolumeHealthCondition
expectedErrs field.ErrorList
}{
"valid": {
conditions: []core.VolumeHealthCondition{{Status: core.VolumeHealthDegraded, Reason: "DiskSlow"}},
},
"status required": {
conditions: []core.VolumeHealthCondition{{Reason: "DiskSlow"}},
expectedErrs: field.ErrorList{field.Required(field.NewPath("status", "healthStatus", "healthConditions").Index(0).Child("status"), "")},
},
"status enum": {
conditions: []core.VolumeHealthCondition{{Status: "Invalid", Reason: "DiskSlow"}},
expectedErrs: field.ErrorList{field.NotSupported(field.NewPath("status", "healthStatus", "healthConditions").Index(0).Child("status"), core.VolumeHealthStatusType("Invalid"), []core.VolumeHealthStatusType(nil))},
},
"reason required": {
conditions: []core.VolumeHealthCondition{{Status: core.VolumeHealthDegraded}},
expectedErrs: field.ErrorList{field.Required(field.NewPath("status", "healthStatus", "healthConditions").Index(0).Child("reason"), "")},
},
"reason max bytes": {
conditions: []core.VolumeHealthCondition{{Status: core.VolumeHealthDegraded, Reason: strings.Repeat("𝄞", 65)}},
expectedErrs: field.ErrorList{field.TooLong(field.NewPath("status", "healthStatus", "healthConditions").Index(0).Child("reason"), "", 256).WithOrigin("maxBytes")},
},
"message max bytes": {
conditions: []core.VolumeHealthCondition{{Status: core.VolumeHealthDegraded, Reason: "DiskSlow", Message: strings.Repeat("𝄞", 257)}},
expectedErrs: field.ErrorList{field.TooLong(field.NewPath("status", "healthStatus", "healthConditions").Index(0).Child("message"), "", 1024).WithOrigin("maxBytes")},
},
"duplicate conditions": {
conditions: []core.VolumeHealthCondition{
{Status: core.VolumeHealthDegraded, Reason: "DiskSlow"},
{Status: core.VolumeHealthDegraded, Reason: "DiskSlow"},
},
expectedErrs: field.ErrorList{field.Duplicate(field.NewPath("status", "healthStatus", "healthConditions").Index(1), nil)},
},
"too many conditions": {
conditions: makeVolumeHealthConditions(17),
expectedErrs: field.ErrorList{field.TooMany(field.NewPath("status", "healthStatus", "healthConditions"), 17, 16).WithOrigin("maxItems")},
},
}
for name, tc := range tests {
t.Run(apiVersion+"/"+name, func(t *testing.T) {
oldObj := mkValidPersistentVolumeClaim()
oldObj.ResourceVersion = "1"
updateObj := oldObj.DeepCopy()
updateObj.Status.HealthStatus = &core.VolumeHealthStatus{HealthConditions: tc.conditions}
apitesting.VerifyUpdateValidationEquivalence(t, ctx, updateObj, &oldObj, registry.StatusStrategy, tc.expectedErrs, apitesting.WithSubResources("status"))
})
}
}
}
func makeVolumeHealthConditions(count int) []core.VolumeHealthCondition {
conditions := make([]core.VolumeHealthCondition, count)
for i := range conditions {
conditions[i] = core.VolumeHealthCondition{
Status: core.VolumeHealthDegraded,
Reason: "Reason" + string(rune('A'+i)),
}
}
return conditions
}
func mkValidPersistentVolumeClaim() core.PersistentVolumeClaim {
return core.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{

View File

@@ -61,6 +61,23 @@ func init() {
"metadata.uid": {
{ErrorType: "FieldValueInvalid", Origin: "immutable"},
},
"status.healthStatus.healthConditions": {
{ErrorType: "FieldValueTooMany", Origin: "maxItems"},
},
"status.healthStatus.healthConditions[*]": {
{ErrorType: "FieldValueDuplicate"},
},
"status.healthStatus.healthConditions[*].message": {
{ErrorType: "FieldValueTooLong", Origin: "maxBytes"},
},
"status.healthStatus.healthConditions[*].reason": {
{ErrorType: "FieldValueRequired"},
{ErrorType: "FieldValueTooLong", Origin: "maxBytes"},
},
"status.healthStatus.healthConditions[*].status": {
{ErrorType: "FieldValueNotSupported"},
{ErrorType: "FieldValueRequired"},
},
},
)
}

View File

@@ -17,6 +17,7 @@ limitations under the License.
package pod
import (
"strings"
"testing"
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -92,3 +93,111 @@ func TestDeclarativeValidateUpdate(t *testing.T) {
meta.RunObjectMetaUpdateTestCases(t, ctx, &updateObj, registry.Strategy, meta.WithStringentFinalizerValidation())
}
}
func TestDeclarativeValidateStatusUpdate(t *testing.T) {
for _, apiVersion := range apiVersions {
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{
APIPrefix: "api",
APIGroup: "",
APIVersion: apiVersion,
Resource: "pods",
Subresource: "status",
Name: "foo",
IsResourceRequest: true,
Verb: "update",
})
conditionPath := field.NewPath("status", "volumeHealth").Index(0).Child("healthConditions")
tests := map[string]struct {
volumeHealth []api.PodVolumeHealth
expectedErrs field.ErrorList
}{
"valid": {
volumeHealth: []api.PodVolumeHealth{{
Name: "vol",
HealthConditions: []api.VolumeHealthCondition{{Status: api.VolumeHealthDegraded, Reason: "DiskSlow"}},
}},
},
"name required": {
volumeHealth: []api.PodVolumeHealth{{}},
expectedErrs: field.ErrorList{
field.Required(field.NewPath("status", "volumeHealth").Index(0).Child("name"), ""),
},
},
"duplicate volumes": {
volumeHealth: []api.PodVolumeHealth{{Name: "vol"}, {Name: "vol"}},
expectedErrs: field.ErrorList{
field.Duplicate(field.NewPath("status", "volumeHealth").Index(1), nil),
},
},
"status required": {
volumeHealth: []api.PodVolumeHealth{{Name: "vol", HealthConditions: []api.VolumeHealthCondition{{Reason: "DiskSlow"}}}},
expectedErrs: field.ErrorList{
field.Required(conditionPath.Index(0).Child("status"), ""),
},
},
"status enum": {
volumeHealth: []api.PodVolumeHealth{{Name: "vol", HealthConditions: []api.VolumeHealthCondition{{Status: "Invalid", Reason: "DiskSlow"}}}},
expectedErrs: field.ErrorList{
field.NotSupported(conditionPath.Index(0).Child("status"), api.VolumeHealthStatusType("Invalid"), []api.VolumeHealthStatusType(nil)),
},
},
"reason required": {
volumeHealth: []api.PodVolumeHealth{{Name: "vol", HealthConditions: []api.VolumeHealthCondition{{Status: api.VolumeHealthDegraded}}}},
expectedErrs: field.ErrorList{
field.Required(conditionPath.Index(0).Child("reason"), ""),
},
},
"reason max bytes": {
volumeHealth: []api.PodVolumeHealth{{Name: "vol", HealthConditions: []api.VolumeHealthCondition{{Status: api.VolumeHealthDegraded, Reason: strings.Repeat("𝄞", 65)}}}},
expectedErrs: field.ErrorList{
field.TooLong(conditionPath.Index(0).Child("reason"), "", 256).WithOrigin("maxBytes"),
},
},
"message max bytes": {
volumeHealth: []api.PodVolumeHealth{{Name: "vol", HealthConditions: []api.VolumeHealthCondition{{Status: api.VolumeHealthDegraded, Reason: "DiskSlow", Message: strings.Repeat("𝄞", 257)}}}},
expectedErrs: field.ErrorList{
field.TooLong(conditionPath.Index(0).Child("message"), "", 1024).WithOrigin("maxBytes"),
},
},
"duplicate conditions": {
volumeHealth: []api.PodVolumeHealth{{
Name: "vol",
HealthConditions: []api.VolumeHealthCondition{
{Status: api.VolumeHealthDegraded, Reason: "DiskSlow"},
{Status: api.VolumeHealthDegraded, Reason: "DiskSlow"},
},
}},
expectedErrs: field.ErrorList{
field.Duplicate(conditionPath.Index(1), nil),
},
},
"too many conditions": {
volumeHealth: []api.PodVolumeHealth{{Name: "vol", HealthConditions: makePodVolumeHealthConditions(17)}},
expectedErrs: field.ErrorList{
field.TooMany(conditionPath, 17, 16).WithOrigin("maxItems"),
},
},
}
for name, tc := range tests {
t.Run(apiVersion+"/"+name, func(t *testing.T) {
oldObj := podtest.MakePod("foo", podtest.SetVolumes(api.Volume{Name: "vol"}))
oldObj.ResourceVersion = "1"
updateObj := oldObj.DeepCopy()
updateObj.Status.VolumeHealth = tc.volumeHealth
apitesting.VerifyUpdateValidationEquivalence(t, ctx, updateObj, oldObj, registry.StatusStrategy, tc.expectedErrs, apitesting.WithSubResources("status"))
})
}
}
}
func makePodVolumeHealthConditions(count int) []api.VolumeHealthCondition {
conditions := make([]api.VolumeHealthCondition, count)
for i := range conditions {
conditions[i] = api.VolumeHealthCondition{
Status: api.VolumeHealthDegraded,
Reason: "Reason" + string(rune('A'+i)),
}
}
return conditions
}

View File

@@ -64,6 +64,29 @@ func init() {
"spec.tolerations[*].key": {
{ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"},
},
"status.volumeHealth[*]": {
{ErrorType: "FieldValueDuplicate"},
},
"status.volumeHealth[*].healthConditions": {
{ErrorType: "FieldValueTooMany", Origin: "maxItems"},
},
"status.volumeHealth[*].healthConditions[*]": {
{ErrorType: "FieldValueDuplicate"},
},
"status.volumeHealth[*].healthConditions[*].message": {
{ErrorType: "FieldValueTooLong", Origin: "maxBytes"},
},
"status.volumeHealth[*].healthConditions[*].reason": {
{ErrorType: "FieldValueRequired"},
{ErrorType: "FieldValueTooLong", Origin: "maxBytes"},
},
"status.volumeHealth[*].healthConditions[*].status": {
{ErrorType: "FieldValueNotSupported"},
{ErrorType: "FieldValueRequired"},
},
"status.volumeHealth[*].name": {
{ErrorType: "FieldValueRequired"},
},
},
)
}