k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/plugin/pkg/admission/storage/storageobjectinuseprotection/admission.go (about) 1 /* 2 Copyright 2017 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 storageobjectinuseprotection 18 19 import ( 20 "context" 21 "io" 22 23 "k8s.io/apiserver/pkg/admission" 24 "k8s.io/klog/v2" 25 api "k8s.io/kubernetes/pkg/apis/core" 26 volumeutil "k8s.io/kubernetes/pkg/volume/util" 27 ) 28 29 const ( 30 // PluginName is the name of this admission controller plugin 31 PluginName = "StorageObjectInUseProtection" 32 ) 33 34 // Register registers a plugin 35 func Register(plugins *admission.Plugins) { 36 plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) { 37 plugin := newPlugin() 38 return plugin, nil 39 }) 40 } 41 42 // storageProtectionPlugin holds state for and implements the admission plugin. 43 type storageProtectionPlugin struct { 44 *admission.Handler 45 } 46 47 var _ admission.Interface = &storageProtectionPlugin{} 48 49 // newPlugin creates a new admission plugin. 50 func newPlugin() *storageProtectionPlugin { 51 return &storageProtectionPlugin{ 52 Handler: admission.NewHandler(admission.Create), 53 } 54 } 55 56 var ( 57 pvResource = api.Resource("persistentvolumes") 58 pvcResource = api.Resource("persistentvolumeclaims") 59 ) 60 61 // Admit sets finalizer on all PVCs(PVs). The finalizer is removed by 62 // PVCProtectionController(PVProtectionController) when it's not referenced. 63 // 64 // This prevents users from deleting a PVC that's used by a running pod. 65 // This also prevents admin from deleting a PV that's bound by a PVC 66 func (c *storageProtectionPlugin) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { 67 switch a.GetResource().GroupResource() { 68 case pvResource: 69 return c.admitPV(a) 70 case pvcResource: 71 return c.admitPVC(a) 72 73 default: 74 return nil 75 } 76 } 77 78 func (c *storageProtectionPlugin) admitPV(a admission.Attributes) error { 79 if len(a.GetSubresource()) != 0 { 80 return nil 81 } 82 83 pv, ok := a.GetObject().(*api.PersistentVolume) 84 // if we can't convert the obj to PV, just return 85 if !ok { 86 return nil 87 } 88 for _, f := range pv.Finalizers { 89 if f == volumeutil.PVProtectionFinalizer { 90 // Finalizer is already present, nothing to do 91 return nil 92 } 93 } 94 klog.V(4).Infof("adding PV protection finalizer to %s", pv.Name) 95 pv.Finalizers = append(pv.Finalizers, volumeutil.PVProtectionFinalizer) 96 97 return nil 98 } 99 100 func (c *storageProtectionPlugin) admitPVC(a admission.Attributes) error { 101 if len(a.GetSubresource()) != 0 { 102 return nil 103 } 104 105 pvc, ok := a.GetObject().(*api.PersistentVolumeClaim) 106 // if we can't convert the obj to PVC, just return 107 if !ok { 108 return nil 109 } 110 111 for _, f := range pvc.Finalizers { 112 if f == volumeutil.PVCProtectionFinalizer { 113 // Finalizer is already present, nothing to do 114 return nil 115 } 116 } 117 118 klog.V(4).Infof("adding PVC protection finalizer to %s/%s", pvc.Namespace, pvc.Name) 119 pvc.Finalizers = append(pvc.Finalizers, volumeutil.PVCProtectionFinalizer) 120 return nil 121 }