k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 default: 78 return false 79 } 80 } 81 82 // IsMigrationEnabledForPlugin indicates whether CSI migration has been enabled 83 // for a particular storage plugin 84 func (pm PluginManager) IsMigrationEnabledForPlugin(pluginName string) bool { 85 // CSIMigration feature should be enabled along with the plugin-specific one 86 // CSIMigration has been GA. It will be enabled by default. 87 88 switch pluginName { 89 case csilibplugins.AWSEBSInTreePluginName: 90 return true 91 case csilibplugins.GCEPDInTreePluginName: 92 return true 93 case csilibplugins.AzureFileInTreePluginName: 94 return true 95 case csilibplugins.AzureDiskInTreePluginName: 96 return true 97 case csilibplugins.CinderInTreePluginName: 98 return true 99 case csilibplugins.VSphereInTreePluginName: 100 return true 101 case csilibplugins.PortworxVolumePluginName: 102 return pm.featureGate.Enabled(features.CSIMigrationPortworx) 103 default: 104 return false 105 } 106 } 107 108 // IsMigratable indicates whether CSI migration has been enabled for a volume 109 // plugin that the spec refers to 110 func (pm PluginManager) IsMigratable(spec *volume.Spec) (bool, error) { 111 if spec == nil { 112 return false, fmt.Errorf("could not find if plugin is migratable because volume spec is nil") 113 } 114 115 pluginName, _ := pm.GetInTreePluginNameFromSpec(spec.PersistentVolume, spec.Volume) 116 if pluginName == "" { 117 return false, nil 118 } 119 // found an in-tree plugin that supports the spec 120 return pm.IsMigrationEnabledForPlugin(pluginName), nil 121 } 122 123 // InTreeToCSITranslator performs translation of Volume sources for PV and Volume objects 124 // from references to in-tree plugins to migrated CSI plugins 125 type InTreeToCSITranslator interface { 126 TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) 127 TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) 128 } 129 130 // TranslateInTreeSpecToCSI translates a volume spec (either PV or inline volume) 131 // supported by an in-tree plugin to CSI 132 func TranslateInTreeSpecToCSI(spec *volume.Spec, podNamespace string, translator InTreeToCSITranslator) (*volume.Spec, error) { 133 var csiPV *v1.PersistentVolume 134 var err error 135 inlineVolume := false 136 if spec.PersistentVolume != nil { 137 csiPV, err = translator.TranslateInTreePVToCSI(spec.PersistentVolume) 138 } else if spec.Volume != nil { 139 csiPV, err = translator.TranslateInTreeInlineVolumeToCSI(spec.Volume, podNamespace) 140 inlineVolume = true 141 } else { 142 err = errors.New("not a valid volume spec") 143 } 144 if err != nil { 145 return nil, fmt.Errorf("failed to translate in-tree pv to CSI: %v", err) 146 } 147 return &volume.Spec{ 148 Migrated: true, 149 PersistentVolume: csiPV, 150 ReadOnly: spec.ReadOnly, 151 InlineVolumeSpecForCSIMigration: inlineVolume, 152 }, nil 153 } 154 155 // CheckMigrationFeatureFlags checks the configuration of feature flags related 156 // to CSI Migration is valid. It will return whether the migration is complete 157 // by looking up the pluginUnregister flag 158 func CheckMigrationFeatureFlags(f featuregate.FeatureGate, pluginMigration, 159 pluginUnregister featuregate.Feature) (migrationComplete bool, err error) { 160 // This is for in-tree plugin that get migration finished 161 if f.Enabled(pluginMigration) && f.Enabled(pluginUnregister) { 162 return true, nil 163 } 164 return false, nil 165 }