k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/plugin/pkg/admission/storage/storageclass/setdefault/admission.go (about) 1 /* 2 Copyright 2016 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 setdefault 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 "k8s.io/kubernetes/pkg/volume/util" 24 25 "k8s.io/klog/v2" 26 27 "k8s.io/apiserver/pkg/admission" 28 genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer" 29 "k8s.io/client-go/informers" 30 storagev1listers "k8s.io/client-go/listers/storage/v1" 31 api "k8s.io/kubernetes/pkg/apis/core" 32 "k8s.io/kubernetes/pkg/apis/core/helper" 33 ) 34 35 const ( 36 // PluginName is the name of this admission controller plugin 37 PluginName = "DefaultStorageClass" 38 ) 39 40 // Register registers a plugin 41 func Register(plugins *admission.Plugins) { 42 plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) { 43 plugin := newPlugin() 44 return plugin, nil 45 }) 46 } 47 48 // claimDefaulterPlugin holds state for and implements the admission plugin. 49 type claimDefaulterPlugin struct { 50 *admission.Handler 51 52 lister storagev1listers.StorageClassLister 53 } 54 55 var _ admission.Interface = &claimDefaulterPlugin{} 56 var _ admission.MutationInterface = &claimDefaulterPlugin{} 57 var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&claimDefaulterPlugin{}) 58 59 // newPlugin creates a new admission plugin. 60 func newPlugin() *claimDefaulterPlugin { 61 return &claimDefaulterPlugin{ 62 Handler: admission.NewHandler(admission.Create), 63 } 64 } 65 66 func (a *claimDefaulterPlugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) { 67 informer := f.Storage().V1().StorageClasses() 68 a.lister = informer.Lister() 69 a.SetReadyFunc(informer.Informer().HasSynced) 70 } 71 72 // ValidateInitialization ensures lister is set. 73 func (a *claimDefaulterPlugin) ValidateInitialization() error { 74 if a.lister == nil { 75 return fmt.Errorf("missing lister") 76 } 77 return nil 78 } 79 80 // Admit sets the default value of a PersistentVolumeClaim's storage class, in case the user did 81 // not provide a value. 82 // 83 // 1. Find available StorageClasses. 84 // 2. Figure which is the default 85 // 3. Write to the PVClaim 86 func (a *claimDefaulterPlugin) Admit(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) error { 87 if attr.GetResource().GroupResource() != api.Resource("persistentvolumeclaims") { 88 return nil 89 } 90 91 if len(attr.GetSubresource()) != 0 { 92 return nil 93 } 94 95 pvc, ok := attr.GetObject().(*api.PersistentVolumeClaim) 96 // if we can't convert then we don't handle this object so just return 97 if !ok { 98 return nil 99 } 100 101 if helper.PersistentVolumeClaimHasClass(pvc) { 102 // The user asked for a class. 103 return nil 104 } 105 106 klog.V(4).Infof("no storage class for claim %s (generate: %s)", pvc.Name, pvc.GenerateName) 107 108 def, err := util.GetDefaultClass(a.lister) 109 if err != nil { 110 return admission.NewForbidden(attr, err) 111 } 112 if def == nil { 113 // No default class selected, do nothing about the PVC. 114 return nil 115 } 116 117 klog.V(4).Infof("defaulting storage class for claim %s (generate: %s) to %s", pvc.Name, pvc.GenerateName, def.Name) 118 pvc.Spec.StorageClassName = &def.Name 119 return nil 120 }