k8s.io/kubernetes@v1.29.3/pkg/volume/csimigration/plugin_manager.go (about) 1 /* 2 Copyright 2019 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 csimigration 18 19 import ( 20 "errors" 21 "fmt" 22 23 v1 "k8s.io/api/core/v1" 24 "k8s.io/component-base/featuregate" 25 csilibplugins "k8s.io/csi-translation-lib/plugins" 26 "k8s.io/kubernetes/pkg/features" 27 "k8s.io/kubernetes/pkg/volume" 28 ) 29 30 // PluginNameMapper contains utility methods to retrieve names of plugins 31 // that support a spec, map intree <=> migrated CSI plugin names, etc 32 type PluginNameMapper interface { 33 GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error) 34 GetCSINameFromInTreeName(pluginName string) (string, error) 35 } 36 37 // PluginManager keeps track of migrated state of in-tree plugins 38 type PluginManager struct { 39 PluginNameMapper 40 featureGate featuregate.FeatureGate 41 } 42 43 // NewPluginManager returns a new PluginManager instance 44 func NewPluginManager(m PluginNameMapper, featureGate featuregate.FeatureGate) PluginManager { 45 return PluginManager{ 46 PluginNameMapper: m, 47 featureGate: featureGate, 48 } 49 } 50 51 // IsMigrationCompleteForPlugin indicates whether CSI migration has been completed 52 // for a particular storage plugin. A complete migration will need to: 53 // 1. Enable CSIMigrationXX for the plugin 54 // 2. Unregister the in-tree plugin by setting the InTreePluginXXUnregister feature gate 55 func (pm PluginManager) IsMigrationCompleteForPlugin(pluginName string) bool { 56 // CSIMigration feature and plugin specific InTreePluginUnregister feature flags should 57 // be enabled for plugin specific migration completion to be take effect 58 if !pm.IsMigrationEnabledForPlugin(pluginName) { 59 return false 60 } 61 62 switch pluginName { 63 case csilibplugins.AWSEBSInTreePluginName: 64 return pm.featureGate.Enabled(features.InTreePluginAWSUnregister) 65 case csilibplugins.GCEPDInTreePluginName: 66 return pm.featureGate.Enabled(features.InTreePluginGCEUnregister) 67 case csilibplugins.AzureFileInTreePluginName: 68 return pm.featureGate.Enabled(features.InTreePluginAzureFileUnregister) 69 case csilibplugins.AzureDiskInTreePluginName: 70 return pm.featureGate.Enabled(features.InTreePluginAzureDiskUnregister) 71 case csilibplugins.CinderInTreePluginName: 72 return pm.featureGate.Enabled(features.InTreePluginOpenStackUnregister) 73 case csilibplugins.VSphereInTreePluginName: 74 return pm.featureGate.Enabled(features.InTreePluginvSphereUnregister) 75 case csilibplugins.PortworxVolumePluginName: 76 return pm.featureGate.Enabled(features.InTreePluginPortworxUnregister) 77 case csilibplugins.RBDVolumePluginName: 78 return pm.featureGate.Enabled(features.InTreePluginRBDUnregister) 79 default: 80 return false 81 } 82 } 83 84 // IsMigrationEnabledForPlugin indicates whether CSI migration has been enabled 85 // for a particular storage plugin 86 func (pm PluginManager) IsMigrationEnabledForPlugin(pluginName string) bool { 87 // CSIMigration feature should be enabled along with the plugin-specific one 88 // CSIMigration has been GA. It will be enabled by default. 89 90 switch pluginName { 91 case csilibplugins.AWSEBSInTreePluginName: 92 return true 93 case csilibplugins.GCEPDInTreePluginName: 94 return true 95 case csilibplugins.AzureFileInTreePluginName: 96 return pm.featureGate.Enabled(features.CSIMigrationAzureFile) 97 case csilibplugins.AzureDiskInTreePluginName: 98 return true 99 case csilibplugins.CinderInTreePluginName: 100 return true 101 case csilibplugins.VSphereInTreePluginName: 102 return true 103 case csilibplugins.PortworxVolumePluginName: 104 return pm.featureGate.Enabled(features.CSIMigrationPortworx) 105 case csilibplugins.RBDVolumePluginName: 106 return pm.featureGate.Enabled(features.CSIMigrationRBD) 107 default: 108 return false 109 } 110 } 111 112 // IsMigratable indicates whether CSI migration has been enabled for a volume 113 // plugin that the spec refers to 114 func (pm PluginManager) IsMigratable(spec *volume.Spec) (bool, error) { 115 if spec == nil { 116 return false, fmt.Errorf("could not find if plugin is migratable because volume spec is nil") 117 } 118 119 pluginName, _ := pm.GetInTreePluginNameFromSpec(spec.PersistentVolume, spec.Volume) 120 if pluginName == "" { 121 return false, nil 122 } 123 // found an in-tree plugin that supports the spec 124 return pm.IsMigrationEnabledForPlugin(pluginName), nil 125 } 126 127 // InTreeToCSITranslator performs translation of Volume sources for PV and Volume objects 128 // from references to in-tree plugins to migrated CSI plugins 129 type InTreeToCSITranslator interface { 130 TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) 131 TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) 132 } 133 134 // TranslateInTreeSpecToCSI translates a volume spec (either PV or inline volume) 135 // supported by an in-tree plugin to CSI 136 func TranslateInTreeSpecToCSI(spec *volume.Spec, podNamespace string, translator InTreeToCSITranslator) (*volume.Spec, error) { 137 var csiPV *v1.PersistentVolume 138 var err error 139 inlineVolume := false 140 if spec.PersistentVolume != nil { 141 csiPV, err = translator.TranslateInTreePVToCSI(spec.PersistentVolume) 142 } else if spec.Volume != nil { 143 csiPV, err = translator.TranslateInTreeInlineVolumeToCSI(spec.Volume, podNamespace) 144 inlineVolume = true 145 } else { 146 err = errors.New("not a valid volume spec") 147 } 148 if err != nil { 149 return nil, fmt.Errorf("failed to translate in-tree pv to CSI: %v", err) 150 } 151 return &volume.Spec{ 152 Migrated: true, 153 PersistentVolume: csiPV, 154 ReadOnly: spec.ReadOnly, 155 InlineVolumeSpecForCSIMigration: inlineVolume, 156 }, nil 157 } 158 159 // CheckMigrationFeatureFlags checks the configuration of feature flags related 160 // to CSI Migration is valid. It will return whether the migration is complete 161 // by looking up the pluginUnregister flag 162 func CheckMigrationFeatureFlags(f featuregate.FeatureGate, pluginMigration, 163 pluginUnregister featuregate.Feature) (migrationComplete bool, err error) { 164 // This is for in-tree plugin that get migration finished 165 if f.Enabled(pluginMigration) && f.Enabled(pluginUnregister) { 166 return true, nil 167 } 168 return false, nil 169 }