123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- /*
- 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)
- 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)
- 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
- }
|