mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			161 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2019 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package csimigration
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 
 | |
| 	"k8s.io/api/core/v1"
 | |
| 	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | |
| 	"k8s.io/component-base/featuregate"
 | |
| 	csilibplugins "k8s.io/csi-translation-lib/plugins"
 | |
| 	"k8s.io/kubernetes/pkg/features"
 | |
| 	"k8s.io/kubernetes/pkg/volume"
 | |
| )
 | |
| 
 | |
| // PluginNameMapper contains utility methods to retrieve names of plugins
 | |
| // that support a spec, map intree <=> migrated CSI plugin names, etc
 | |
| type PluginNameMapper interface {
 | |
| 	GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error)
 | |
| 	GetCSINameFromInTreeName(pluginName string) (string, error)
 | |
| }
 | |
| 
 | |
| // PluginManager keeps track of migrated state of in-tree plugins
 | |
| type PluginManager struct {
 | |
| 	PluginNameMapper
 | |
| }
 | |
| 
 | |
| // NewPluginManager returns a new PluginManager instance
 | |
| func NewPluginManager(m PluginNameMapper) PluginManager {
 | |
| 	return PluginManager{
 | |
| 		PluginNameMapper: m,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // IsMigrationCompleteForPlugin indicates whether CSI migration has been completed
 | |
| // for a particular storage plugin
 | |
| func (pm PluginManager) IsMigrationCompleteForPlugin(pluginName string) bool {
 | |
| 	// CSIMigration feature and plugin specific migration feature flags should
 | |
| 	// be enabled for plugin specific migration completion feature flags to be
 | |
| 	// take effect
 | |
| 	if !pm.IsMigrationEnabledForPlugin(pluginName) {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	switch pluginName {
 | |
| 	case csilibplugins.AWSEBSInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAWSComplete)
 | |
| 	case csilibplugins.GCEPDInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationGCEComplete)
 | |
| 	case csilibplugins.AzureFileInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureFileComplete)
 | |
| 	case csilibplugins.AzureDiskInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureDiskComplete)
 | |
| 	case csilibplugins.CinderInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationOpenStackComplete)
 | |
| 	case csilibplugins.VSphereInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationvSphereComplete)
 | |
| 	default:
 | |
| 		return false
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // IsMigrationEnabledForPlugin indicates whether CSI migration has been enabled
 | |
| // for a particular storage plugin
 | |
| func (pm PluginManager) IsMigrationEnabledForPlugin(pluginName string) bool {
 | |
| 	// CSIMigration feature should be enabled along with the plugin-specific one
 | |
| 	if !utilfeature.DefaultFeatureGate.Enabled(features.CSIMigration) {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	switch pluginName {
 | |
| 	case csilibplugins.AWSEBSInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAWS)
 | |
| 	case csilibplugins.GCEPDInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationGCE)
 | |
| 	case csilibplugins.AzureFileInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureFile)
 | |
| 	case csilibplugins.AzureDiskInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureDisk)
 | |
| 	case csilibplugins.CinderInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationOpenStack)
 | |
| 	case csilibplugins.VSphereInTreePluginName:
 | |
| 		return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationvSphere)
 | |
| 	default:
 | |
| 		return false
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // IsMigratable indicates whether CSI migration has been enabled for a volume
 | |
| // plugin that the spec refers to
 | |
| func (pm PluginManager) IsMigratable(spec *volume.Spec) (bool, error) {
 | |
| 	if spec == nil {
 | |
| 		return false, fmt.Errorf("could not find if plugin is migratable because volume spec is nil")
 | |
| 	}
 | |
| 
 | |
| 	pluginName, _ := pm.GetInTreePluginNameFromSpec(spec.PersistentVolume, spec.Volume)
 | |
| 	if pluginName == "" {
 | |
| 		return false, nil
 | |
| 	}
 | |
| 	// found an in-tree plugin that supports the spec
 | |
| 	return pm.IsMigrationEnabledForPlugin(pluginName), nil
 | |
| }
 | |
| 
 | |
| // InTreeToCSITranslator performs translation of Volume sources for PV and Volume objects
 | |
| // from references to in-tree plugins to migrated CSI plugins
 | |
| type InTreeToCSITranslator interface {
 | |
| 	TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error)
 | |
| 	TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error)
 | |
| }
 | |
| 
 | |
| // TranslateInTreeSpecToCSI translates a volume spec (either PV or inline volume)
 | |
| // supported by an in-tree plugin to CSI
 | |
| func TranslateInTreeSpecToCSI(spec *volume.Spec, translator InTreeToCSITranslator) (*volume.Spec, error) {
 | |
| 	var csiPV *v1.PersistentVolume
 | |
| 	var err error
 | |
| 	inlineVolume := false
 | |
| 	if spec.PersistentVolume != nil {
 | |
| 		csiPV, err = translator.TranslateInTreePVToCSI(spec.PersistentVolume)
 | |
| 	} else if spec.Volume != nil {
 | |
| 		csiPV, err = translator.TranslateInTreeInlineVolumeToCSI(spec.Volume)
 | |
| 		inlineVolume = true
 | |
| 	} else {
 | |
| 		err = errors.New("not a valid volume spec")
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("failed to translate in-tree pv to CSI: %v", err)
 | |
| 	}
 | |
| 	return &volume.Spec{
 | |
| 		PersistentVolume:                csiPV,
 | |
| 		ReadOnly:                        spec.ReadOnly,
 | |
| 		InlineVolumeSpecForCSIMigration: inlineVolume,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // CheckMigrationFeatureFlags checks the configuration of feature flags related
 | |
| // to CSI Migration is valid
 | |
| func CheckMigrationFeatureFlags(f featuregate.FeatureGate, pluginMigration, pluginMigrationComplete featuregate.Feature) error {
 | |
| 	if f.Enabled(pluginMigration) && !f.Enabled(features.CSIMigration) {
 | |
| 		return fmt.Errorf("enabling %q requires CSIMigration to be enabled", pluginMigration)
 | |
| 	}
 | |
| 	if f.Enabled(pluginMigrationComplete) && !f.Enabled(pluginMigration) {
 | |
| 		return fmt.Errorf("enabling %q requires %q to be enabled", pluginMigrationComplete, pluginMigration)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 |