k8s.io/kubernetes@v1.29.3/pkg/registry/core/persistentvolume/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 persistentvolume 18 19 import ( 20 "context" 21 "fmt" 22 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 utilfeature "k8s.io/apiserver/pkg/util/feature" 25 "k8s.io/kubernetes/pkg/features" 26 27 "k8s.io/apimachinery/pkg/fields" 28 "k8s.io/apimachinery/pkg/labels" 29 "k8s.io/apimachinery/pkg/runtime" 30 "k8s.io/apimachinery/pkg/util/validation/field" 31 "k8s.io/apiserver/pkg/registry/generic" 32 "k8s.io/apiserver/pkg/storage" 33 "k8s.io/apiserver/pkg/storage/names" 34 "k8s.io/kubernetes/pkg/api/legacyscheme" 35 pvutil "k8s.io/kubernetes/pkg/api/persistentvolume" 36 api "k8s.io/kubernetes/pkg/apis/core" 37 "k8s.io/kubernetes/pkg/apis/core/validation" 38 volumevalidation "k8s.io/kubernetes/pkg/volume/validation" 39 "sigs.k8s.io/structured-merge-diff/v4/fieldpath" 40 ) 41 42 // persistentvolumeStrategy implements behavior for PersistentVolume objects 43 type persistentvolumeStrategy struct { 44 runtime.ObjectTyper 45 names.NameGenerator 46 } 47 48 // Strategy is the default logic that applies when creating and updating PersistentVolume 49 // objects via the REST API. 50 var Strategy = persistentvolumeStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} 51 52 func (persistentvolumeStrategy) NamespaceScoped() bool { 53 return false 54 } 55 56 // GetResetFields returns the set of fields that get reset by the strategy 57 // and should not be modified by the user. 58 func (persistentvolumeStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 59 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 60 "v1": fieldpath.NewSet( 61 fieldpath.MakePathOrDie("status"), 62 ), 63 } 64 65 return fields 66 } 67 68 // ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation. 69 func (persistentvolumeStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { 70 pv := obj.(*api.PersistentVolume) 71 pv.Status = api.PersistentVolumeStatus{} 72 73 if utilfeature.DefaultFeatureGate.Enabled(features.PersistentVolumeLastPhaseTransitionTime) { 74 pv.Status.Phase = api.VolumePending 75 now := NowFunc() 76 pv.Status.LastPhaseTransitionTime = &now 77 } 78 } 79 80 func (persistentvolumeStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { 81 persistentvolume := obj.(*api.PersistentVolume) 82 opts := validation.ValidationOptionsForPersistentVolume(persistentvolume, nil) 83 errorList := validation.ValidatePersistentVolume(persistentvolume, opts) 84 return append(errorList, volumevalidation.ValidatePersistentVolume(persistentvolume)...) 85 } 86 87 // WarningsOnCreate returns warnings for the creation of the given object. 88 func (persistentvolumeStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { 89 return pvutil.GetWarningsForPersistentVolume(obj.(*api.PersistentVolume)) 90 } 91 92 // Canonicalize normalizes the object after validation. 93 func (persistentvolumeStrategy) Canonicalize(obj runtime.Object) { 94 } 95 96 func (persistentvolumeStrategy) AllowCreateOnUpdate() bool { 97 return false 98 } 99 100 // PrepareForUpdate sets the Status fields which is not allowed to be set by an end user updating a PV 101 func (persistentvolumeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 102 newPv := obj.(*api.PersistentVolume) 103 oldPv := old.(*api.PersistentVolume) 104 newPv.Status = oldPv.Status 105 } 106 107 func (persistentvolumeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 108 newPv := obj.(*api.PersistentVolume) 109 oldPv := old.(*api.PersistentVolume) 110 opts := validation.ValidationOptionsForPersistentVolume(newPv, oldPv) 111 errorList := validation.ValidatePersistentVolume(newPv, opts) 112 errorList = append(errorList, volumevalidation.ValidatePersistentVolume(newPv)...) 113 return append(errorList, validation.ValidatePersistentVolumeUpdate(newPv, oldPv, opts)...) 114 } 115 116 // WarningsOnUpdate returns warnings for the given update. 117 func (persistentvolumeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 118 return pvutil.GetWarningsForPersistentVolume(obj.(*api.PersistentVolume)) 119 } 120 121 func (persistentvolumeStrategy) AllowUnconditionalUpdate() bool { 122 return true 123 } 124 125 type persistentvolumeStatusStrategy struct { 126 persistentvolumeStrategy 127 } 128 129 var StatusStrategy = persistentvolumeStatusStrategy{Strategy} 130 131 // GetResetFields returns the set of fields that get reset by the strategy 132 // and should not be modified by the user. 133 func (persistentvolumeStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 134 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 135 "v1": fieldpath.NewSet( 136 fieldpath.MakePathOrDie("spec"), 137 ), 138 } 139 140 return fields 141 } 142 143 var NowFunc = metav1.Now 144 145 // PrepareForUpdate sets the Spec field which is not allowed to be changed when updating a PV's Status 146 func (persistentvolumeStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 147 newPv := obj.(*api.PersistentVolume) 148 oldPv := old.(*api.PersistentVolume) 149 newPv.Spec = oldPv.Spec 150 151 if utilfeature.DefaultFeatureGate.Enabled(features.PersistentVolumeLastPhaseTransitionTime) { 152 switch { 153 case oldPv.Status.Phase == newPv.Status.Phase && newPv.Status.LastPhaseTransitionTime == nil: 154 // phase didn't change, preserve the existing transition time if set 155 newPv.Status.LastPhaseTransitionTime = oldPv.Status.LastPhaseTransitionTime 156 157 case oldPv.Status.Phase != newPv.Status.Phase && (newPv.Status.LastPhaseTransitionTime == nil || newPv.Status.LastPhaseTransitionTime.Equal(oldPv.Status.LastPhaseTransitionTime)): 158 // phase changed and client didn't set or didn't change the transition time 159 now := NowFunc() 160 newPv.Status.LastPhaseTransitionTime = &now 161 } 162 } 163 164 pvutil.DropDisabledStatusFields(&oldPv.Status, &newPv.Status) 165 } 166 167 func (persistentvolumeStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 168 return validation.ValidatePersistentVolumeStatusUpdate(obj.(*api.PersistentVolume), old.(*api.PersistentVolume)) 169 } 170 171 // WarningsOnUpdate returns warnings for the given update. 172 func (persistentvolumeStatusStrategy) 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 persistentvolumeObj, ok := obj.(*api.PersistentVolume) 179 if !ok { 180 return nil, nil, fmt.Errorf("not a persistentvolume") 181 } 182 return labels.Set(persistentvolumeObj.Labels), PersistentVolumeToSelectableFields(persistentvolumeObj), nil 183 } 184 185 // MatchPersistentVolume returns a generic matcher for a given label and field selector. 186 func MatchPersistentVolumes(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 // PersistentVolumeToSelectableFields returns a field set that represents the object 195 func PersistentVolumeToSelectableFields(persistentvolume *api.PersistentVolume) fields.Set { 196 objectMetaFieldsSet := generic.ObjectMetaFieldsSet(&persistentvolume.ObjectMeta, false) 197 specificFieldsSet := fields.Set{ 198 // This is a bug, but we need to support it for backward compatibility. 199 "name": persistentvolume.Name, 200 } 201 return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet) 202 }