k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/registry/core/persistentvolumeclaim/strategy.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package persistentvolumeclaim 18 19 import ( 20 "context" 21 "fmt" 22 23 "k8s.io/apimachinery/pkg/fields" 24 "k8s.io/apimachinery/pkg/labels" 25 "k8s.io/apimachinery/pkg/runtime" 26 "k8s.io/apimachinery/pkg/util/validation/field" 27 "k8s.io/apiserver/pkg/registry/generic" 28 "k8s.io/apiserver/pkg/storage" 29 "k8s.io/apiserver/pkg/storage/names" 30 "sigs.k8s.io/structured-merge-diff/v4/fieldpath" 31 32 "k8s.io/kubernetes/pkg/api/legacyscheme" 33 pvcutil "k8s.io/kubernetes/pkg/api/persistentvolumeclaim" 34 api "k8s.io/kubernetes/pkg/apis/core" 35 "k8s.io/kubernetes/pkg/apis/core/validation" 36 ) 37 38 // persistentvolumeclaimStrategy implements behavior for PersistentVolumeClaim objects 39 type persistentvolumeclaimStrategy struct { 40 runtime.ObjectTyper 41 names.NameGenerator 42 } 43 44 // Strategy is the default logic that applies when creating and updating PersistentVolumeClaim 45 // objects via the REST API. 46 var Strategy = persistentvolumeclaimStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} 47 48 func (persistentvolumeclaimStrategy) NamespaceScoped() bool { 49 return true 50 } 51 52 // GetResetFields returns the set of fields that get reset by the strategy 53 // and should not be modified by the user. 54 func (persistentvolumeclaimStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 55 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 56 "v1": fieldpath.NewSet( 57 fieldpath.MakePathOrDie("status"), 58 ), 59 } 60 61 return fields 62 } 63 64 // PrepareForCreate clears the Status field which is not allowed to be set by end users on creation. 65 func (persistentvolumeclaimStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { 66 pvc := obj.(*api.PersistentVolumeClaim) 67 pvc.Status = api.PersistentVolumeClaimStatus{} 68 pvcutil.DropDisabledFields(&pvc.Spec, nil) 69 70 // For data sources, we need to do 2 things to implement KEP 1495 71 72 // First drop invalid values from spec.dataSource (anything other than PVC or 73 // VolumeSnapshot) if certain conditions are met. 74 pvcutil.EnforceDataSourceBackwardsCompatibility(&pvc.Spec, nil) 75 76 // Second copy dataSource -> dataSourceRef or dataSourceRef -> dataSource if one of them 77 // is nil and the other is non-nil 78 pvcutil.NormalizeDataSources(&pvc.Spec) 79 } 80 81 func (persistentvolumeclaimStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { 82 pvc := obj.(*api.PersistentVolumeClaim) 83 opts := validation.ValidationOptionsForPersistentVolumeClaim(pvc, nil) 84 return validation.ValidatePersistentVolumeClaim(pvc, opts) 85 } 86 87 // WarningsOnCreate returns warnings for the creation of the given object. 88 func (persistentvolumeclaimStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { 89 return pvcutil.GetWarningsForPersistentVolumeClaim(obj.(*api.PersistentVolumeClaim)) 90 } 91 92 // Canonicalize normalizes the object after validation. 93 func (persistentvolumeclaimStrategy) Canonicalize(obj runtime.Object) { 94 } 95 96 func (persistentvolumeclaimStrategy) AllowCreateOnUpdate() bool { 97 return false 98 } 99 100 // PrepareForUpdate sets the Status field which is not allowed to be set by end users on update 101 func (persistentvolumeclaimStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 102 newPvc := obj.(*api.PersistentVolumeClaim) 103 oldPvc := old.(*api.PersistentVolumeClaim) 104 newPvc.Status = oldPvc.Status 105 106 pvcutil.DropDisabledFields(&newPvc.Spec, &oldPvc.Spec) 107 108 // We need to use similar logic to PrepareForCreate here both to preserve backwards 109 // compatibility with the old behavior (ignoring of garbage dataSources at both create 110 // and update time) and also for compatibility with older clients, that might omit 111 // the dataSourceRef field which we filled in automatically, so we have to fill it 112 // in again here. 113 pvcutil.EnforceDataSourceBackwardsCompatibility(&newPvc.Spec, &oldPvc.Spec) 114 pvcutil.NormalizeDataSources(&newPvc.Spec) 115 116 // We also normalize the data source fields of the old PVC, so that objects saved 117 // from an earlier version will pass validation. 118 pvcutil.NormalizeDataSources(&oldPvc.Spec) 119 } 120 121 func (persistentvolumeclaimStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 122 newPvc := obj.(*api.PersistentVolumeClaim) 123 oldPvc := old.(*api.PersistentVolumeClaim) 124 opts := validation.ValidationOptionsForPersistentVolumeClaim(newPvc, oldPvc) 125 errorList := validation.ValidatePersistentVolumeClaim(newPvc, opts) 126 return append(errorList, validation.ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc, opts)...) 127 } 128 129 // WarningsOnUpdate returns warnings for the given update. 130 func (persistentvolumeclaimStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 131 return pvcutil.GetWarningsForPersistentVolumeClaim(obj.(*api.PersistentVolumeClaim)) 132 } 133 134 func (persistentvolumeclaimStrategy) AllowUnconditionalUpdate() bool { 135 return true 136 } 137 138 type persistentvolumeclaimStatusStrategy struct { 139 persistentvolumeclaimStrategy 140 } 141 142 var StatusStrategy = persistentvolumeclaimStatusStrategy{Strategy} 143 144 // GetResetFields returns the set of fields that get reset by the strategy 145 // and should not be modified by the user. 146 func (persistentvolumeclaimStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 147 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 148 "v1": fieldpath.NewSet( 149 fieldpath.MakePathOrDie("spec"), 150 ), 151 } 152 153 return fields 154 } 155 156 // PrepareForUpdate sets the Spec field which is not allowed to be changed when updating a PV's Status 157 func (persistentvolumeclaimStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 158 newPVC := obj.(*api.PersistentVolumeClaim) 159 oldPVC := old.(*api.PersistentVolumeClaim) 160 newPVC.Spec = oldPVC.Spec 161 pvcutil.DropDisabledFieldsFromStatus(newPVC, oldPVC) 162 } 163 164 func (persistentvolumeclaimStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 165 newPvc := obj.(*api.PersistentVolumeClaim) 166 oldPvc := old.(*api.PersistentVolumeClaim) 167 opts := validation.ValidationOptionsForPersistentVolumeClaim(newPvc, oldPvc) 168 return validation.ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc, opts) 169 } 170 171 // WarningsOnUpdate returns warnings for the given update. 172 func (persistentvolumeclaimStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 173 return nil 174 } 175 176 // GetAttrs returns labels and fields of a given object for filtering purposes. 177 func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { 178 persistentvolumeclaimObj, ok := obj.(*api.PersistentVolumeClaim) 179 if !ok { 180 return nil, nil, fmt.Errorf("not a persistentvolumeclaim") 181 } 182 return labels.Set(persistentvolumeclaimObj.Labels), PersistentVolumeClaimToSelectableFields(persistentvolumeclaimObj), nil 183 } 184 185 // MatchPersistentVolumeClaim returns a generic matcher for a given label and field selector. 186 func MatchPersistentVolumeClaim(label labels.Selector, field fields.Selector) storage.SelectionPredicate { 187 return storage.SelectionPredicate{ 188 Label: label, 189 Field: field, 190 GetAttrs: GetAttrs, 191 } 192 } 193 194 // PersistentVolumeClaimToSelectableFields returns a field set that represents the object 195 func PersistentVolumeClaimToSelectableFields(persistentvolumeclaim *api.PersistentVolumeClaim) fields.Set { 196 objectMetaFieldsSet := generic.ObjectMetaFieldsSet(&persistentvolumeclaim.ObjectMeta, true) 197 specificFieldsSet := fields.Set{ 198 // This is a bug, but we need to support it for backward compatibility. 199 "name": persistentvolumeclaim.Name, 200 } 201 return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet) 202 }