...

Source file src/k8s.io/kubernetes/pkg/volume/csimigration/plugin_manager.go

Documentation: k8s.io/kubernetes/pkg/volume/csimigration

     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 true
    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  }
   170  

View as plain text