mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
Merge pull request #82683 from davidz627/fix/translationStruct
Refactor CSI Translation Library into a struct that is injected into various components to simplify unit testing
This commit is contained in:
commit
14e5adfc85
@ -141,6 +141,7 @@ go_library(
|
||||
"//staging/src/k8s.io/component-base/cli/globalflag:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/version:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/version/verflag:go_default_library",
|
||||
"//staging/src/k8s.io/csi-translation-lib:go_default_library",
|
||||
"//staging/src/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/metrics/pkg/client/custom_metrics:go_default_library",
|
||||
"//staging/src/k8s.io/metrics/pkg/client/external_metrics:go_default_library",
|
||||
|
@ -36,6 +36,7 @@ import (
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/metadata"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
csitrans "k8s.io/csi-translation-lib"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
cloudcontroller "k8s.io/kubernetes/pkg/controller/cloud"
|
||||
endpointcontroller "k8s.io/kubernetes/pkg/controller/endpoint"
|
||||
@ -309,7 +310,8 @@ func startVolumeExpandController(ctx ControllerContext) (http.Handler, bool, err
|
||||
ctx.InformerFactory.Core().V1().PersistentVolumes(),
|
||||
ctx.InformerFactory.Storage().V1().StorageClasses(),
|
||||
ctx.Cloud,
|
||||
ProbeExpandableVolumePlugins(ctx.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration))
|
||||
ProbeExpandableVolumePlugins(ctx.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration),
|
||||
csitrans.New())
|
||||
|
||||
if expandControllerErr != nil {
|
||||
return nil, true, fmt.Errorf("failed to start volume expand controller : %v", expandControllerErr)
|
||||
|
@ -32,7 +32,6 @@ go_library(
|
||||
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/csi-translation-lib:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
@ -75,6 +74,7 @@ go_test(
|
||||
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
||||
"//staging/src/k8s.io/csi-translation-lib:go_default_library",
|
||||
"//staging/src/k8s.io/csi-translation-lib/plugins:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -41,7 +41,6 @@ import (
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
csitranslation "k8s.io/csi-translation-lib"
|
||||
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||
"k8s.io/kubernetes/pkg/controller/volume/events"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
@ -62,6 +61,11 @@ type ExpandController interface {
|
||||
Run(stopCh <-chan struct{})
|
||||
}
|
||||
|
||||
// CSINameTranslator can get the CSI Driver name based on the in-tree plugin name
|
||||
type CSINameTranslator interface {
|
||||
GetCSINameFromInTreeName(pluginName string) (string, error)
|
||||
}
|
||||
|
||||
type expandController struct {
|
||||
// kubeClient is the kube API client used by volumehost to communicate with
|
||||
// the API server.
|
||||
@ -92,6 +96,8 @@ type expandController struct {
|
||||
operationGenerator operationexecutor.OperationGenerator
|
||||
|
||||
queue workqueue.RateLimitingInterface
|
||||
|
||||
translator CSINameTranslator
|
||||
}
|
||||
|
||||
// NewExpandController expands the pvs
|
||||
@ -101,7 +107,8 @@ func NewExpandController(
|
||||
pvInformer coreinformers.PersistentVolumeInformer,
|
||||
scInformer storageclassinformer.StorageClassInformer,
|
||||
cloud cloudprovider.Interface,
|
||||
plugins []volume.VolumePlugin) (ExpandController, error) {
|
||||
plugins []volume.VolumePlugin,
|
||||
translator CSINameTranslator) (ExpandController, error) {
|
||||
|
||||
expc := &expandController{
|
||||
kubeClient: kubeClient,
|
||||
@ -113,6 +120,7 @@ func NewExpandController(
|
||||
classLister: scInformer.Lister(),
|
||||
classListerSynced: scInformer.Informer().HasSynced,
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "volume_expand"),
|
||||
translator: translator,
|
||||
}
|
||||
|
||||
if err := expc.volumePluginMgr.InitPlugins(plugins, nil, expc); err != nil {
|
||||
@ -255,7 +263,7 @@ func (expc *expandController) syncHandler(key string) error {
|
||||
if volumePlugin.IsMigratedToCSI() {
|
||||
msg := fmt.Sprintf("CSI migration enabled for %s; waiting for external resizer to expand the pvc", volumeResizerName)
|
||||
expc.recorder.Event(pvc, v1.EventTypeNormal, events.ExternalExpanding, msg)
|
||||
csiResizerName, err := csitranslation.GetCSINameFromInTreeName(class.Provisioner)
|
||||
csiResizerName, err := expc.translator.GetCSINameFromInTreeName(class.Provisioner)
|
||||
if err != nil {
|
||||
errorMsg := fmt.Sprintf("error getting CSI driver name for pvc %s, with error %v", util.ClaimToClaimKey(pvc), err)
|
||||
expc.recorder.Event(pvc, v1.EventTypeWarning, events.ExternalExpanding, errorMsg)
|
||||
|
@ -33,6 +33,7 @@ import (
|
||||
"k8s.io/client-go/informers"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
csitrans "k8s.io/csi-translation-lib"
|
||||
csitranslationplugins "k8s.io/csi-translation-lib/plugins"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
controllervolumetesting "k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing"
|
||||
@ -123,7 +124,7 @@ func TestSyncHandler(t *testing.T) {
|
||||
if tc.storageClass != nil {
|
||||
informerFactory.Storage().V1().StorageClasses().Informer().GetIndexer().Add(tc.storageClass)
|
||||
}
|
||||
expc, err := NewExpandController(fakeKubeClient, pvcInformer, pvInformer, storageClassInformer, nil, allPlugins)
|
||||
expc, err := NewExpandController(fakeKubeClient, pvcInformer, pvInformer, storageClassInformer, nil, allPlugins, csitrans.New())
|
||||
if err != nil {
|
||||
t.Fatalf("error creating expand controller : %v", err)
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ go_test(
|
||||
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/reference:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
||||
"//staging/src/k8s.io/csi-translation-lib:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -521,6 +521,12 @@ func wrapTestWithProvisionCalls(expectedProvisionCalls []provisionCall, toWrap t
|
||||
return wrapTestWithPluginCalls(nil, nil, expectedProvisionCalls, toWrap)
|
||||
}
|
||||
|
||||
type fakeCSINameTranslator struct{}
|
||||
|
||||
func (t fakeCSINameTranslator) GetCSINameFromInTreeName(pluginName string) (string, error) {
|
||||
return "vendor.com/MockCSIPlugin", nil
|
||||
}
|
||||
|
||||
// wrapTestWithCSIMigrationProvisionCalls returns a testCall that:
|
||||
// - configures controller with a volume plugin that emulates CSI migration
|
||||
// - calls given testCall
|
||||
@ -530,9 +536,7 @@ func wrapTestWithCSIMigrationProvisionCalls(toWrap testCall) testCall {
|
||||
isMigratedToCSI: true,
|
||||
}
|
||||
ctrl.volumePluginMgr.InitPlugins([]vol.VolumePlugin{plugin}, nil /* prober */, ctrl)
|
||||
ctrl.csiNameFromIntreeNameHook = func(string) (string, error) {
|
||||
return "vendor.com/MockCSIPlugin", nil
|
||||
}
|
||||
ctrl.translator = fakeCSINameTranslator{}
|
||||
return toWrap(ctrl, reactor, test)
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ import (
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
volerr "k8s.io/cloud-provider/volume/errors"
|
||||
csitranslation "k8s.io/csi-translation-lib"
|
||||
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||
"k8s.io/kubernetes/pkg/controller/volume/events"
|
||||
"k8s.io/kubernetes/pkg/controller/volume/persistentvolume/metrics"
|
||||
@ -134,6 +133,11 @@ const createProvisionedPVRetryCount = 5
|
||||
// Interval between retries when we create a PV object for a provisioned volume.
|
||||
const createProvisionedPVInterval = 10 * time.Second
|
||||
|
||||
// CSINameTranslator can get the CSI Driver name based on the in-tree plugin name
|
||||
type CSINameTranslator interface {
|
||||
GetCSINameFromInTreeName(pluginName string) (string, error)
|
||||
}
|
||||
|
||||
// PersistentVolumeController is a controller that synchronizes
|
||||
// PersistentVolumeClaims and PersistentVolumes. It starts two
|
||||
// cache.Controllers that watch PersistentVolume and PersistentVolumeClaim
|
||||
@ -200,10 +204,6 @@ type PersistentVolumeController struct {
|
||||
createProvisionedPVRetryCount int
|
||||
createProvisionedPVInterval time.Duration
|
||||
|
||||
// For testing only: hook to intercept CSI driver name <=> Intree plugin name mapping
|
||||
// Not used when set to nil
|
||||
csiNameFromIntreeNameHook func(pluginName string) (string, error)
|
||||
|
||||
// operationTimestamps caches start timestamp of operations
|
||||
// (currently provision + binding/deletion) for metric recording.
|
||||
// Detailed lifecyle/key for each operation
|
||||
@ -225,6 +225,8 @@ type PersistentVolumeController struct {
|
||||
// the corresponding timestamp entry will be deleted from cache
|
||||
// abort: N.A.
|
||||
operationTimestamps metrics.OperationStartTimeCache
|
||||
|
||||
translator CSINameTranslator
|
||||
}
|
||||
|
||||
// syncClaim is the main controller method to decide what to do with a claim.
|
||||
@ -1355,13 +1357,6 @@ func (ctrl *PersistentVolumeController) provisionClaim(claim *v1.PersistentVolum
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctrl *PersistentVolumeController) getCSINameFromIntreeName(pluginName string) (string, error) {
|
||||
if ctrl.csiNameFromIntreeNameHook != nil {
|
||||
return ctrl.csiNameFromIntreeNameHook(pluginName)
|
||||
}
|
||||
return csitranslation.GetCSINameFromInTreeName(pluginName)
|
||||
}
|
||||
|
||||
// provisionClaimOperation provisions a volume. This method is running in
|
||||
// standalone goroutine and already has all necessary locks.
|
||||
func (ctrl *PersistentVolumeController) provisionClaimOperation(
|
||||
@ -1571,7 +1566,7 @@ func (ctrl *PersistentVolumeController) provisionClaimOperationExternal(
|
||||
provisionerName := storageClass.Provisioner
|
||||
if plugin != nil {
|
||||
// update the provisioner name to use the CSI in-tree name
|
||||
provisionerName, err = ctrl.getCSINameFromIntreeName(storageClass.Provisioner)
|
||||
provisionerName, err = ctrl.translator.GetCSINameFromInTreeName(storageClass.Provisioner)
|
||||
if err != nil {
|
||||
strerr := fmt.Sprintf("error getting CSI name for In tree plugin %s: %v", storageClass.Provisioner, err)
|
||||
klog.V(2).Infof("%s", strerr)
|
||||
@ -1732,7 +1727,7 @@ func (ctrl *PersistentVolumeController) getProvisionerNameFromVolume(volume *v1.
|
||||
return "N/A"
|
||||
}
|
||||
if plugin != nil {
|
||||
provisionerName, err := ctrl.getCSINameFromIntreeName(class.Provisioner)
|
||||
provisionerName, err := ctrl.translator.GetCSINameFromInTreeName(class.Provisioner)
|
||||
if err == nil {
|
||||
return provisionerName
|
||||
}
|
||||
@ -1747,7 +1742,7 @@ func (ctrl *PersistentVolumeController) getProvisionerName(plugin vol.Provisiona
|
||||
return plugin.GetPluginName()
|
||||
} else if plugin != nil {
|
||||
// get the CSI in-tree name from storage class provisioner name
|
||||
provisionerName, err := ctrl.getCSINameFromIntreeName(storageClass.Provisioner)
|
||||
provisionerName, err := ctrl.translator.GetCSINameFromInTreeName(storageClass.Provisioner)
|
||||
if err != nil {
|
||||
return "N/A"
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import (
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
csitrans "k8s.io/csi-translation-lib"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/controller/volume/persistentvolume/metrics"
|
||||
pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
|
||||
@ -93,6 +94,7 @@ func NewController(p ControllerParameters) (*PersistentVolumeController, error)
|
||||
volumeQueue: workqueue.NewNamed("volumes"),
|
||||
resyncPeriod: p.SyncPeriod,
|
||||
operationTimestamps: metrics.NewOperationStartTimeCache(),
|
||||
translator: csitrans.New(),
|
||||
}
|
||||
|
||||
// Prober is nil because PV is not aware of Flexvolume.
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
storagelisters "k8s.io/client-go/listers/storage/v1"
|
||||
core "k8s.io/client-go/testing"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
csitrans "k8s.io/csi-translation-lib"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
pvtesting "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing"
|
||||
@ -438,6 +439,7 @@ func TestDelayBindingMode(t *testing.T) {
|
||||
classInformer := informerFactory.Storage().V1().StorageClasses()
|
||||
ctrl := &PersistentVolumeController{
|
||||
classLister: classInformer.Lister(),
|
||||
translator: csitrans.New(),
|
||||
}
|
||||
|
||||
for _, class := range classes {
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/util/rand"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
csilib "k8s.io/csi-translation-lib"
|
||||
csitrans "k8s.io/csi-translation-lib"
|
||||
"k8s.io/klog"
|
||||
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
@ -31,6 +31,16 @@ import (
|
||||
volumeutil "k8s.io/kubernetes/pkg/volume/util"
|
||||
)
|
||||
|
||||
// InTreeToCSITranslator contains methods required to check migratable status
|
||||
// and perform translations from InTree PV's to CSI
|
||||
type InTreeToCSITranslator interface {
|
||||
IsPVMigratable(pv *v1.PersistentVolume) bool
|
||||
IsMigratableIntreePluginByName(inTreePluginName string) bool
|
||||
GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error)
|
||||
GetCSINameFromInTreeName(pluginName string) (string, error)
|
||||
TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error)
|
||||
}
|
||||
|
||||
// CSIMaxVolumeLimitChecker defines predicate needed for counting CSI volumes
|
||||
type CSIMaxVolumeLimitChecker struct {
|
||||
csiNodeInfo CSINodeInfo
|
||||
@ -39,6 +49,8 @@ type CSIMaxVolumeLimitChecker struct {
|
||||
scInfo StorageClassInfo
|
||||
|
||||
randomVolumeIDPrefix string
|
||||
|
||||
translator InTreeToCSITranslator
|
||||
}
|
||||
|
||||
// NewCSIMaxVolumeLimitPredicate returns a predicate for counting CSI volumes
|
||||
@ -50,6 +62,7 @@ func NewCSIMaxVolumeLimitPredicate(
|
||||
pvcInfo: pvcInfo,
|
||||
scInfo: scInfo,
|
||||
randomVolumeIDPrefix: rand.String(32),
|
||||
translator: csitrans.New(),
|
||||
}
|
||||
return c.attachableLimitPredicate
|
||||
}
|
||||
@ -201,11 +214,11 @@ func (c *CSIMaxVolumeLimitChecker) getCSIDriverInfo(csiNode *storagev1beta1.CSIN
|
||||
csiSource := pv.Spec.PersistentVolumeSource.CSI
|
||||
if csiSource == nil {
|
||||
// We make a fast path for non-CSI volumes that aren't migratable
|
||||
if !csilib.IsPVMigratable(pv) {
|
||||
if !c.translator.IsPVMigratable(pv) {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
pluginName, err := csilib.GetInTreePluginNameFromSpec(pv, nil)
|
||||
pluginName, err := c.translator.GetInTreePluginNameFromSpec(pv, nil)
|
||||
if err != nil {
|
||||
klog.V(5).Infof("Unable to look up plugin name from PV spec: %v", err)
|
||||
return "", ""
|
||||
@ -216,7 +229,7 @@ func (c *CSIMaxVolumeLimitChecker) getCSIDriverInfo(csiNode *storagev1beta1.CSIN
|
||||
return "", ""
|
||||
}
|
||||
|
||||
csiPV, err := csilib.TranslateInTreePVToCSI(pv)
|
||||
csiPV, err := c.translator.TranslateInTreePVToCSI(pv)
|
||||
if err != nil {
|
||||
klog.V(5).Infof("Unable to translate in-tree volume to CSI: %v", err)
|
||||
return "", ""
|
||||
@ -258,13 +271,13 @@ func (c *CSIMaxVolumeLimitChecker) getCSIDriverInfoFromSC(csiNode *storagev1beta
|
||||
volumeHandle := fmt.Sprintf("%s-%s/%s", c.randomVolumeIDPrefix, namespace, pvcName)
|
||||
|
||||
provisioner := storageClass.Provisioner
|
||||
if csilib.IsMigratableIntreePluginByName(provisioner) {
|
||||
if c.translator.IsMigratableIntreePluginByName(provisioner) {
|
||||
if !isCSIMigrationOn(csiNode, provisioner) {
|
||||
klog.V(5).Infof("CSI Migration of plugin %s is not enabled", provisioner)
|
||||
return "", ""
|
||||
}
|
||||
|
||||
driverName, err := csilib.GetCSINameFromInTreeName(provisioner)
|
||||
driverName, err := c.translator.GetCSINameFromInTreeName(provisioner)
|
||||
if err != nil {
|
||||
klog.V(5).Infof("Unable to look up driver name from plugin name: %v", err)
|
||||
return "", ""
|
||||
|
@ -67,6 +67,7 @@ go_test(
|
||||
"//staging/src/k8s.io/component-base/featuregate:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/metrics/legacyregistry:go_default_library",
|
||||
"//staging/src/k8s.io/csi-translation-lib:go_default_library",
|
||||
"//staging/src/k8s.io/csi-translation-lib/plugins:go_default_library",
|
||||
"//vendor/github.com/prometheus/client_model/go:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
csitrans "k8s.io/csi-translation-lib"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/util/hostutil"
|
||||
volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
|
||||
@ -88,6 +89,10 @@ func (f *fakeOGCounter) GetVolumePluginMgr() *volume.VolumePluginMgr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeOGCounter) GetCSITranslator() InTreeToCSITranslator {
|
||||
return csitrans.New()
|
||||
}
|
||||
|
||||
func (f *fakeOGCounter) GenerateBulkVolumeVerifyFunc(
|
||||
map[types.NodeName][]*volume.Spec,
|
||||
string,
|
||||
|
@ -641,14 +641,14 @@ func (oe *operationExecutor) VerifyVolumesAreAttached(
|
||||
}
|
||||
|
||||
// Migration: Must also check the Node since Attach would have been done with in-tree if node is not using Migration
|
||||
nu, err := nodeUsingCSIPlugin(oe.operationGenerator, volumeAttached.VolumeSpec, node)
|
||||
nu, err := nodeUsingCSIPlugin(oe.operationGenerator.GetCSITranslator(), oe.operationGenerator.GetVolumePluginMgr(), volumeAttached.VolumeSpec, node)
|
||||
if err != nil {
|
||||
klog.Errorf(volumeAttached.GenerateErrorDetailed("VolumesAreAttached.NodeUsingCSIPlugin failed", err).Error())
|
||||
continue
|
||||
}
|
||||
|
||||
var volumePlugin volume.VolumePlugin
|
||||
if useCSIPlugin(oe.operationGenerator.GetVolumePluginMgr(), volumeAttached.VolumeSpec) && nu {
|
||||
if useCSIPlugin(oe.operationGenerator.GetCSITranslator(), oe.operationGenerator.GetVolumePluginMgr(), volumeAttached.VolumeSpec) && nu {
|
||||
// The volume represented by this spec is CSI and thus should be migrated
|
||||
volumePlugin, err = oe.operationGenerator.GetVolumePluginMgr().FindPluginByName(csi.CSIPluginName)
|
||||
if err != nil || volumePlugin == nil {
|
||||
@ -661,7 +661,7 @@ func (oe *operationExecutor) VerifyVolumesAreAttached(
|
||||
continue
|
||||
}
|
||||
|
||||
csiSpec, err := translateSpec(volumeAttached.VolumeSpec)
|
||||
csiSpec, err := translateSpec(oe.operationGenerator.GetCSITranslator(), volumeAttached.VolumeSpec)
|
||||
if err != nil {
|
||||
klog.Errorf(volumeAttached.GenerateErrorDetailed("VolumesAreAttached.TranslateSpec failed", err).Error())
|
||||
continue
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
csitrans "k8s.io/csi-translation-lib"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/util/hostutil"
|
||||
volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
|
||||
@ -520,6 +521,10 @@ func (fopg *fakeOperationGenerator) GetVolumePluginMgr() *volume.VolumePluginMgr
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fopg *fakeOperationGenerator) GetCSITranslator() InTreeToCSITranslator {
|
||||
return csitrans.New()
|
||||
}
|
||||
|
||||
func getTestPodWithSecret(podName, secretName string) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -32,7 +32,7 @@ import (
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/record"
|
||||
volerr "k8s.io/cloud-provider/volume/errors"
|
||||
csilib "k8s.io/csi-translation-lib"
|
||||
csitrans "k8s.io/csi-translation-lib"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kevents "k8s.io/kubernetes/pkg/kubelet/events"
|
||||
@ -49,6 +49,18 @@ const (
|
||||
unknownAttachableVolumePlugin string = "UnknownAttachableVolumePlugin"
|
||||
)
|
||||
|
||||
// InTreeToCSITranslator contains methods required to check migratable status
|
||||
// and perform translations from InTree PVs and Inline to CSI
|
||||
type InTreeToCSITranslator interface {
|
||||
IsPVMigratable(pv *v1.PersistentVolume) bool
|
||||
IsInlineMigratable(vol *v1.Volume) bool
|
||||
IsMigratableIntreePluginByName(inTreePluginName string) bool
|
||||
GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error)
|
||||
GetCSINameFromInTreeName(pluginName string) (string, error)
|
||||
TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error)
|
||||
TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error)
|
||||
}
|
||||
|
||||
var _ OperationGenerator = &operationGenerator{}
|
||||
|
||||
type operationGenerator struct {
|
||||
@ -70,6 +82,8 @@ type operationGenerator struct {
|
||||
|
||||
// blkUtil provides volume path related operations for block volume
|
||||
blkUtil volumepathhandler.BlockVolumePathHandler
|
||||
|
||||
translator InTreeToCSITranslator
|
||||
}
|
||||
|
||||
// NewOperationGenerator is returns instance of operationGenerator
|
||||
@ -85,6 +99,7 @@ func NewOperationGenerator(kubeClient clientset.Interface,
|
||||
recorder: recorder,
|
||||
checkNodeCapabilitiesBeforeMount: checkNodeCapabilitiesBeforeMount,
|
||||
blkUtil: blkUtil,
|
||||
translator: csitrans.New(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,6 +138,9 @@ type OperationGenerator interface {
|
||||
// GetVolumePluginMgr returns volume plugin manager
|
||||
GetVolumePluginMgr() *volume.VolumePluginMgr
|
||||
|
||||
// GetCSITranslator returns the CSI Translation Library
|
||||
GetCSITranslator() InTreeToCSITranslator
|
||||
|
||||
GenerateBulkVolumeVerifyFunc(
|
||||
map[types.NodeName][]*volume.Spec,
|
||||
string,
|
||||
@ -153,14 +171,14 @@ func (og *operationGenerator) GenerateVolumesAreAttachedFunc(
|
||||
}
|
||||
|
||||
// Migration: Must also check the Node since Attach would have been done with in-tree if node is not using Migration
|
||||
nu, err := nodeUsingCSIPlugin(og, volumeAttached.VolumeSpec, nodeName)
|
||||
nu, err := nodeUsingCSIPlugin(og.translator, og.volumePluginMgr, volumeAttached.VolumeSpec, nodeName)
|
||||
if err != nil {
|
||||
klog.Errorf(volumeAttached.GenerateErrorDetailed("VolumesAreAttached.NodeUsingCSIPlugin failed", err).Error())
|
||||
continue
|
||||
}
|
||||
|
||||
var volumePlugin volume.VolumePlugin
|
||||
if useCSIPlugin(og.volumePluginMgr, volumeAttached.VolumeSpec) && nu {
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, volumeAttached.VolumeSpec) && nu {
|
||||
// The volume represented by this spec is CSI and thus should be migrated
|
||||
volumePlugin, err = og.volumePluginMgr.FindPluginByName(csi.CSIPluginName)
|
||||
if err != nil || volumePlugin == nil {
|
||||
@ -168,7 +186,7 @@ func (og *operationGenerator) GenerateVolumesAreAttachedFunc(
|
||||
continue
|
||||
}
|
||||
|
||||
csiSpec, err := translateSpec(volumeAttached.VolumeSpec)
|
||||
csiSpec, err := translateSpec(og.translator, volumeAttached.VolumeSpec)
|
||||
if err != nil {
|
||||
klog.Errorf(volumeAttached.GenerateErrorDetailed("VolumesAreAttached.TranslateSpec failed", err).Error())
|
||||
continue
|
||||
@ -330,20 +348,20 @@ func (og *operationGenerator) GenerateAttachVolumeFunc(
|
||||
attachVolumeFunc := func() (error, error) {
|
||||
var attachableVolumePlugin volume.AttachableVolumePlugin
|
||||
|
||||
nu, err := nodeUsingCSIPlugin(og, volumeToAttach.VolumeSpec, volumeToAttach.NodeName)
|
||||
nu, err := nodeUsingCSIPlugin(og.translator, og.volumePluginMgr, volumeToAttach.VolumeSpec, volumeToAttach.NodeName)
|
||||
if err != nil {
|
||||
return volumeToAttach.GenerateError("AttachVolume.NodeUsingCSIPlugin failed", err)
|
||||
}
|
||||
|
||||
// useCSIPlugin will check both CSIMigration and the plugin specific feature gates
|
||||
if useCSIPlugin(og.volumePluginMgr, volumeToAttach.VolumeSpec) && nu {
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, volumeToAttach.VolumeSpec) && nu {
|
||||
// The volume represented by this spec is CSI and thus should be migrated
|
||||
attachableVolumePlugin, err = og.volumePluginMgr.FindAttachablePluginByName(csi.CSIPluginName)
|
||||
if err != nil || attachableVolumePlugin == nil {
|
||||
return volumeToAttach.GenerateError("AttachVolume.FindAttachablePluginByName failed", err)
|
||||
}
|
||||
|
||||
csiSpec, err := translateSpec(volumeToAttach.VolumeSpec)
|
||||
csiSpec, err := translateSpec(og.translator, volumeToAttach.VolumeSpec)
|
||||
if err != nil {
|
||||
return volumeToAttach.GenerateError("AttachVolume.TranslateSpec failed", err)
|
||||
}
|
||||
@ -416,15 +434,15 @@ func (og *operationGenerator) GenerateAttachVolumeFunc(
|
||||
// involves determining the plugin_name for the metric generating "CompleteFunc"
|
||||
// during the actual "OperationFunc" and not during this generation function
|
||||
|
||||
nu, err := nodeUsingCSIPlugin(og, volumeToAttach.VolumeSpec, volumeToAttach.NodeName)
|
||||
nu, err := nodeUsingCSIPlugin(og.translator, og.volumePluginMgr, volumeToAttach.VolumeSpec, volumeToAttach.NodeName)
|
||||
if err != nil {
|
||||
klog.Errorf("GenerateAttachVolumeFunc failed to check if node is using CSI Plugin, metric for this operation may be inaccurate: %v", err)
|
||||
}
|
||||
|
||||
// Need to translate the spec here if the plugin is migrated so that the metrics
|
||||
// emitted show the correct (migrated) plugin
|
||||
if useCSIPlugin(og.volumePluginMgr, volumeToAttach.VolumeSpec) && nu {
|
||||
csiSpec, err := translateSpec(volumeToAttach.VolumeSpec)
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, volumeToAttach.VolumeSpec) && nu {
|
||||
csiSpec, err := translateSpec(og.translator, volumeToAttach.VolumeSpec)
|
||||
if err == nil {
|
||||
volumeToAttach.VolumeSpec = csiSpec
|
||||
}
|
||||
@ -456,6 +474,10 @@ func (og *operationGenerator) GetVolumePluginMgr() *volume.VolumePluginMgr {
|
||||
return og.volumePluginMgr
|
||||
}
|
||||
|
||||
func (og *operationGenerator) GetCSITranslator() InTreeToCSITranslator {
|
||||
return og.translator
|
||||
}
|
||||
|
||||
func (og *operationGenerator) GenerateDetachVolumeFunc(
|
||||
volumeToDetach AttachedVolume,
|
||||
verifySafeToDetach bool,
|
||||
@ -467,20 +489,20 @@ func (og *operationGenerator) GenerateDetachVolumeFunc(
|
||||
|
||||
if volumeToDetach.VolumeSpec != nil {
|
||||
// Get attacher plugin
|
||||
nu, err := nodeUsingCSIPlugin(og, volumeToDetach.VolumeSpec, volumeToDetach.NodeName)
|
||||
nu, err := nodeUsingCSIPlugin(og.translator, og.volumePluginMgr, volumeToDetach.VolumeSpec, volumeToDetach.NodeName)
|
||||
if err != nil {
|
||||
return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.NodeUsingCSIPlugin failed", err)
|
||||
}
|
||||
|
||||
// useCSIPlugin will check both CSIMigration and the plugin specific feature gate
|
||||
if useCSIPlugin(og.volumePluginMgr, volumeToDetach.VolumeSpec) && nu {
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, volumeToDetach.VolumeSpec) && nu {
|
||||
// The volume represented by this spec is CSI and thus should be migrated
|
||||
attachableVolumePlugin, err = og.volumePluginMgr.FindAttachablePluginByName(csi.CSIPluginName)
|
||||
if err != nil || attachableVolumePlugin == nil {
|
||||
return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.FindAttachablePluginBySpec failed", err)
|
||||
}
|
||||
|
||||
csiSpec, err := translateSpec(volumeToDetach.VolumeSpec)
|
||||
csiSpec, err := translateSpec(og.translator, volumeToDetach.VolumeSpec)
|
||||
if err != nil {
|
||||
return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.TranslateSpec failed", err)
|
||||
}
|
||||
@ -511,7 +533,7 @@ func (og *operationGenerator) GenerateDetachVolumeFunc(
|
||||
// TODO(dyzz): This case can't distinguish between PV and In-line which is necessary because
|
||||
// if it was PV it may have been migrated, but the same plugin with in-line may not have been.
|
||||
// Suggestions welcome...
|
||||
if csilib.IsMigratableIntreePluginByName(pluginName) && utilfeature.DefaultFeatureGate.Enabled(features.CSIMigration) {
|
||||
if og.translator.IsMigratableIntreePluginByName(pluginName) && utilfeature.DefaultFeatureGate.Enabled(features.CSIMigration) {
|
||||
// The volume represented by this spec is CSI and thus should be migrated
|
||||
attachableVolumePlugin, err = og.volumePluginMgr.FindAttachablePluginByName(csi.CSIPluginName)
|
||||
if err != nil || attachableVolumePlugin == nil {
|
||||
@ -582,8 +604,8 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
||||
volumePluginName := unknownVolumePlugin
|
||||
// Need to translate the spec here if the plugin is migrated so that the metrics
|
||||
// emitted show the correct (migrated) plugin
|
||||
if useCSIPlugin(og.volumePluginMgr, volumeToMount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(volumeToMount.VolumeSpec)
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, volumeToMount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(og.translator, volumeToMount.VolumeSpec)
|
||||
if err == nil {
|
||||
volumeToMount.VolumeSpec = csiSpec
|
||||
}
|
||||
@ -601,8 +623,8 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
||||
mountVolumeFunc := func() (error, error) {
|
||||
|
||||
// Get mounter plugin
|
||||
if useCSIPlugin(og.volumePluginMgr, volumeToMount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(volumeToMount.VolumeSpec)
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, volumeToMount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(og.translator, volumeToMount.VolumeSpec)
|
||||
if err != nil {
|
||||
return volumeToMount.GenerateError("MountVolume.TranslateSpec failed", err)
|
||||
}
|
||||
@ -795,7 +817,7 @@ func (og *operationGenerator) GenerateUnmountVolumeFunc(
|
||||
podsDir string) (volumetypes.GeneratedOperations, error) {
|
||||
|
||||
var pluginName string
|
||||
if volumeToUnmount.VolumeSpec != nil && useCSIPlugin(og.volumePluginMgr, volumeToUnmount.VolumeSpec) {
|
||||
if volumeToUnmount.VolumeSpec != nil && useCSIPlugin(og.translator, og.volumePluginMgr, volumeToUnmount.VolumeSpec) {
|
||||
pluginName = csi.CSIPluginName
|
||||
} else {
|
||||
pluginName = volumeToUnmount.PluginName
|
||||
@ -863,9 +885,9 @@ func (og *operationGenerator) GenerateUnmountDeviceFunc(
|
||||
hostutil hostutil.HostUtils) (volumetypes.GeneratedOperations, error) {
|
||||
|
||||
var pluginName string
|
||||
if useCSIPlugin(og.volumePluginMgr, deviceToDetach.VolumeSpec) {
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, deviceToDetach.VolumeSpec) {
|
||||
pluginName = csi.CSIPluginName
|
||||
csiSpec, err := translateSpec(deviceToDetach.VolumeSpec)
|
||||
csiSpec, err := translateSpec(og.translator, deviceToDetach.VolumeSpec)
|
||||
if err != nil {
|
||||
return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.TranslateSpec failed", err)
|
||||
}
|
||||
@ -965,8 +987,8 @@ func (og *operationGenerator) GenerateMapVolumeFunc(
|
||||
|
||||
originalSpec := volumeToMount.VolumeSpec
|
||||
// Translate to CSI spec if migration enabled
|
||||
if useCSIPlugin(og.volumePluginMgr, originalSpec) {
|
||||
csiSpec, err := translateSpec(originalSpec)
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, originalSpec) {
|
||||
csiSpec, err := translateSpec(og.translator, originalSpec)
|
||||
if err != nil {
|
||||
return volumetypes.GeneratedOperations{}, volumeToMount.GenerateErrorDetailed("MapVolume.TranslateSpec failed", err)
|
||||
}
|
||||
@ -1153,8 +1175,8 @@ func (og *operationGenerator) GenerateUnmapVolumeFunc(
|
||||
var err error
|
||||
// Translate to CSI spec if migration enabled
|
||||
// And get block volume unmapper plugin
|
||||
if volumeToUnmount.VolumeSpec != nil && useCSIPlugin(og.volumePluginMgr, volumeToUnmount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(volumeToUnmount.VolumeSpec)
|
||||
if volumeToUnmount.VolumeSpec != nil && useCSIPlugin(og.translator, og.volumePluginMgr, volumeToUnmount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(og.translator, volumeToUnmount.VolumeSpec)
|
||||
if err != nil {
|
||||
return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmapVolume.TranslateSpec failed", err)
|
||||
}
|
||||
@ -1249,8 +1271,8 @@ func (og *operationGenerator) GenerateUnmapDeviceFunc(
|
||||
var blockVolumePlugin volume.BlockVolumePlugin
|
||||
var err error
|
||||
// Translate to CSI spec if migration enabled
|
||||
if useCSIPlugin(og.volumePluginMgr, deviceToDetach.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(deviceToDetach.VolumeSpec)
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, deviceToDetach.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(og.translator, deviceToDetach.VolumeSpec)
|
||||
if err != nil {
|
||||
return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmapDevice.TranslateSpec failed", err)
|
||||
}
|
||||
@ -1564,8 +1586,8 @@ func (og *operationGenerator) GenerateExpandInUseVolumeFunc(
|
||||
fsResizeFunc := func() (error, error) {
|
||||
// Need to translate the spec here if the plugin is migrated so that the metrics
|
||||
// emitted show the correct (migrated) plugin
|
||||
if useCSIPlugin(og.volumePluginMgr, volumeToMount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(volumeToMount.VolumeSpec)
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, volumeToMount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(og.translator, volumeToMount.VolumeSpec)
|
||||
if err != nil {
|
||||
return volumeToMount.GenerateError("NodeExpandVolume.translateSpec failed", err)
|
||||
}
|
||||
@ -1636,8 +1658,8 @@ func (og *operationGenerator) GenerateExpandInUseVolumeFunc(
|
||||
|
||||
// Need to translate the spec here if the plugin is migrated so that the metrics
|
||||
// emitted show the correct (migrated) plugin
|
||||
if useCSIPlugin(og.volumePluginMgr, volumeToMount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(volumeToMount.VolumeSpec)
|
||||
if useCSIPlugin(og.translator, og.volumePluginMgr, volumeToMount.VolumeSpec) {
|
||||
csiSpec, err := translateSpec(og.translator, volumeToMount.VolumeSpec)
|
||||
if err == nil {
|
||||
volumeToMount.VolumeSpec = csiSpec
|
||||
}
|
||||
@ -1796,7 +1818,7 @@ func isDeviceOpened(deviceToDetach AttachedVolume, hostUtil hostutil.HostUtils)
|
||||
return deviceOpened, nil
|
||||
}
|
||||
|
||||
func useCSIPlugin(vpm *volume.VolumePluginMgr, spec *volume.Spec) bool {
|
||||
func useCSIPlugin(tr InTreeToCSITranslator, vpm *volume.VolumePluginMgr, spec *volume.Spec) bool {
|
||||
// TODO(#75146) Check whether the driver is installed as well so that
|
||||
// we can throw a better error when the driver is not installed.
|
||||
// The error should be of the approximate form:
|
||||
@ -1804,7 +1826,7 @@ func useCSIPlugin(vpm *volume.VolumePluginMgr, spec *volume.Spec) bool {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIMigration) {
|
||||
return false
|
||||
}
|
||||
if csilib.IsPVMigratable(spec.PersistentVolume) || csilib.IsInlineMigratable(spec.Volume) {
|
||||
if tr.IsPVMigratable(spec.PersistentVolume) || tr.IsInlineMigratable(spec.Volume) {
|
||||
migratable, err := vpm.IsPluginMigratableBySpec(spec)
|
||||
if err == nil && migratable {
|
||||
return true
|
||||
@ -1813,9 +1835,7 @@ func useCSIPlugin(vpm *volume.VolumePluginMgr, spec *volume.Spec) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func nodeUsingCSIPlugin(og OperationGenerator, spec *volume.Spec, nodeName types.NodeName) (bool, error) {
|
||||
vpm := og.GetVolumePluginMgr()
|
||||
|
||||
func nodeUsingCSIPlugin(tr InTreeToCSITranslator, vpm *volume.VolumePluginMgr, spec *volume.Spec, nodeName types.NodeName) (bool, error) {
|
||||
migratable, err := vpm.IsPluginMigratableBySpec(spec)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -1869,7 +1889,7 @@ func nodeUsingCSIPlugin(og OperationGenerator, spec *volume.Spec, nodeName types
|
||||
mpaSet = sets.NewString(tok...)
|
||||
}
|
||||
|
||||
pluginName, err := csilib.GetInTreePluginNameFromSpec(spec.PersistentVolume, spec.Volume)
|
||||
pluginName, err := tr.GetInTreePluginNameFromSpec(spec.PersistentVolume, spec.Volume)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -1883,7 +1903,7 @@ func nodeUsingCSIPlugin(og OperationGenerator, spec *volume.Spec, nodeName types
|
||||
|
||||
if isMigratedOnNode {
|
||||
installed := false
|
||||
driverName, err := csilib.GetCSINameFromInTreeName(pluginName)
|
||||
driverName, err := tr.GetCSINameFromInTreeName(pluginName)
|
||||
if err != nil {
|
||||
return isMigratedOnNode, err
|
||||
}
|
||||
@ -1902,19 +1922,19 @@ func nodeUsingCSIPlugin(og OperationGenerator, spec *volume.Spec, nodeName types
|
||||
|
||||
}
|
||||
|
||||
func translateSpec(spec *volume.Spec) (*volume.Spec, error) {
|
||||
func translateSpec(tr InTreeToCSITranslator, spec *volume.Spec) (*volume.Spec, error) {
|
||||
var csiPV *v1.PersistentVolume
|
||||
var err error
|
||||
inlineVolume := false
|
||||
if spec.PersistentVolume != nil {
|
||||
// TranslateInTreePVToCSI will create a new PV
|
||||
csiPV, err = csilib.TranslateInTreePVToCSI(spec.PersistentVolume)
|
||||
csiPV, err = tr.TranslateInTreePVToCSI(spec.PersistentVolume)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to translate in tree pv to CSI: %v", err)
|
||||
}
|
||||
} else if spec.Volume != nil {
|
||||
// TranslateInTreeInlineVolumeToCSI will create a new PV
|
||||
csiPV, err = csilib.TranslateInTreeInlineVolumeToCSI(spec.Volume)
|
||||
csiPV, err = tr.TranslateInTreeInlineVolumeToCSI(spec.Volume)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to translate in tree inline volume to CSI: %v", err)
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ func TestOperationGenerator_GenerateUnmapVolumeFunc_PluginName(t *testing.T) {
|
||||
// csi plugin looks a file that contains some information about the volume,
|
||||
// and GenerateUnmapVolumeFuncfails if csi plugin can't find that file.
|
||||
// So the reason for calling plugin.NewBlockVolumeMapper for csi enabled case is creating that file.
|
||||
csiSpec, err := translateSpec(volumeToUnmount.VolumeSpec)
|
||||
csiSpec, err := translateSpec(operationGenerator.GetCSITranslator(), volumeToUnmount.VolumeSpec)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't translate volume to CSI")
|
||||
}
|
||||
|
@ -35,9 +35,20 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// CSITranslator translates in-tree storage API objects to their equivalent CSI
|
||||
// API objects. It also provides many helper functions to determine whether
|
||||
// translation logic exists and the mappings between "in-tree plugin <-> csi driver"
|
||||
type CSITranslator struct{}
|
||||
|
||||
// New creates a new CSITranslator which does real translation
|
||||
// for "in-tree plugins <-> csi drivers"
|
||||
func New() CSITranslator {
|
||||
return CSITranslator{}
|
||||
}
|
||||
|
||||
// TranslateInTreeStorageClassToCSI takes in-tree Storage Class
|
||||
// and translates it to a set of parameters consumable by CSI plugin
|
||||
func TranslateInTreeStorageClassToCSI(inTreePluginName string, sc *storage.StorageClass) (*storage.StorageClass, error) {
|
||||
func (ctl CSITranslator) TranslateInTreeStorageClassToCSI(inTreePluginName string, sc *storage.StorageClass) (*storage.StorageClass, error) {
|
||||
newSC := sc.DeepCopy()
|
||||
for _, curPlugin := range inTreePlugins {
|
||||
if inTreePluginName == curPlugin.GetInTreePluginName() {
|
||||
@ -50,7 +61,7 @@ func TranslateInTreeStorageClassToCSI(inTreePluginName string, sc *storage.Stora
|
||||
// TranslateInTreeInlineVolumeToCSI takes a inline volume and will translate
|
||||
// the in-tree volume source to a CSIPersistentVolumeSource (wrapped in a PV)
|
||||
// if the translation logic has been implemented.
|
||||
func TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error) {
|
||||
func (ctl CSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error) {
|
||||
if volume == nil {
|
||||
return nil, fmt.Errorf("persistent volume was nil")
|
||||
}
|
||||
@ -66,7 +77,7 @@ func TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume,
|
||||
// the in-tree source to a CSI Source if the translation logic
|
||||
// has been implemented. The input persistent volume will not
|
||||
// be modified
|
||||
func TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
|
||||
func (ctl CSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
|
||||
if pv == nil {
|
||||
return nil, errors.New("persistent volume was nil")
|
||||
}
|
||||
@ -82,7 +93,7 @@ func TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, erro
|
||||
// TranslateCSIPVToInTree takes a PV with a CSI PersistentVolume Source and will translate
|
||||
// it to a in-tree Persistent Volume Source for the specific in-tree volume specified
|
||||
// by the `Driver` field in the CSI Source. The input PV object will not be modified.
|
||||
func TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
|
||||
func (ctl CSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) {
|
||||
if pv == nil || pv.Spec.CSI == nil {
|
||||
return nil, errors.New("CSI persistent volume was nil")
|
||||
}
|
||||
@ -97,7 +108,7 @@ func TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, erro
|
||||
|
||||
// IsMigratableIntreePluginByName tests whether there is migration logic for the in-tree plugin
|
||||
// whose name matches the given name
|
||||
func IsMigratableIntreePluginByName(inTreePluginName string) bool {
|
||||
func (ctl CSITranslator) IsMigratableIntreePluginByName(inTreePluginName string) bool {
|
||||
for _, curPlugin := range inTreePlugins {
|
||||
if curPlugin.GetInTreePluginName() == inTreePluginName {
|
||||
return true
|
||||
@ -108,7 +119,7 @@ func IsMigratableIntreePluginByName(inTreePluginName string) bool {
|
||||
|
||||
// IsMigratedCSIDriverByName tests whether there exists an in-tree plugin with logic
|
||||
// to migrate to the CSI driver with given name
|
||||
func IsMigratedCSIDriverByName(csiPluginName string) bool {
|
||||
func (ctl CSITranslator) IsMigratedCSIDriverByName(csiPluginName string) bool {
|
||||
if _, ok := inTreePlugins[csiPluginName]; ok {
|
||||
return true
|
||||
}
|
||||
@ -116,7 +127,7 @@ func IsMigratedCSIDriverByName(csiPluginName string) bool {
|
||||
}
|
||||
|
||||
// GetInTreePluginNameFromSpec returns the plugin name
|
||||
func GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error) {
|
||||
func (ctl CSITranslator) GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error) {
|
||||
if pv != nil {
|
||||
for _, curPlugin := range inTreePlugins {
|
||||
if curPlugin.CanSupport(pv) {
|
||||
@ -138,7 +149,7 @@ func GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (strin
|
||||
|
||||
// GetCSINameFromInTreeName returns the name of a CSI driver that supersedes the
|
||||
// in-tree plugin with the given name
|
||||
func GetCSINameFromInTreeName(pluginName string) (string, error) {
|
||||
func (ctl CSITranslator) GetCSINameFromInTreeName(pluginName string) (string, error) {
|
||||
for csiDriverName, curPlugin := range inTreePlugins {
|
||||
if curPlugin.GetInTreePluginName() == pluginName {
|
||||
return csiDriverName, nil
|
||||
@ -149,7 +160,7 @@ func GetCSINameFromInTreeName(pluginName string) (string, error) {
|
||||
|
||||
// GetInTreeNameFromCSIName returns the name of the in-tree plugin superseded by
|
||||
// a CSI driver with the given name
|
||||
func GetInTreeNameFromCSIName(pluginName string) (string, error) {
|
||||
func (ctl CSITranslator) GetInTreeNameFromCSIName(pluginName string) (string, error) {
|
||||
if plugin, ok := inTreePlugins[pluginName]; ok {
|
||||
return plugin.GetInTreePluginName(), nil
|
||||
}
|
||||
@ -157,7 +168,7 @@ func GetInTreeNameFromCSIName(pluginName string) (string, error) {
|
||||
}
|
||||
|
||||
// IsPVMigratable tests whether there is migration logic for the given Persistent Volume
|
||||
func IsPVMigratable(pv *v1.PersistentVolume) bool {
|
||||
func (ctl CSITranslator) IsPVMigratable(pv *v1.PersistentVolume) bool {
|
||||
for _, curPlugin := range inTreePlugins {
|
||||
if curPlugin.CanSupport(pv) {
|
||||
return true
|
||||
@ -167,7 +178,7 @@ func IsPVMigratable(pv *v1.PersistentVolume) bool {
|
||||
}
|
||||
|
||||
// IsInlineMigratable tests whether there is Migration logic for the given Inline Volume
|
||||
func IsInlineMigratable(vol *v1.Volume) bool {
|
||||
func (ctl CSITranslator) IsInlineMigratable(vol *v1.Volume) bool {
|
||||
for _, curPlugin := range inTreePlugins {
|
||||
if curPlugin.CanSupportInline(vol) {
|
||||
return true
|
||||
|
@ -61,12 +61,13 @@ func TestTranslationStability(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
ctl := New()
|
||||
t.Logf("Testing %v", test.name)
|
||||
csiSource, err := TranslateInTreePVToCSI(test.pv)
|
||||
csiSource, err := ctl.TranslateInTreePVToCSI(test.pv)
|
||||
if err != nil {
|
||||
t.Errorf("Error when translating to CSI: %v", err)
|
||||
}
|
||||
newPV, err := TranslateCSIPVToInTree(csiSource)
|
||||
newPV, err := ctl.TranslateCSIPVToInTree(csiSource)
|
||||
if err != nil {
|
||||
t.Errorf("Error when translating CSI Source to in tree volume: %v", err)
|
||||
}
|
||||
@ -95,18 +96,19 @@ func TestPluginNameMappings(t *testing.T) {
|
||||
}
|
||||
for _, test := range testCases {
|
||||
t.Logf("Testing %v", test.name)
|
||||
csiPluginName, err := GetCSINameFromInTreeName(test.inTreePluginName)
|
||||
ctl := New()
|
||||
csiPluginName, err := ctl.GetCSINameFromInTreeName(test.inTreePluginName)
|
||||
if err != nil {
|
||||
t.Errorf("Error when mapping In-tree plugin name to CSI plugin name %s", err)
|
||||
}
|
||||
if !IsMigratedCSIDriverByName(csiPluginName) {
|
||||
if !ctl.IsMigratedCSIDriverByName(csiPluginName) {
|
||||
t.Errorf("%s expected to supersede an In-tree plugin", csiPluginName)
|
||||
}
|
||||
inTreePluginName, err := GetInTreeNameFromCSIName(csiPluginName)
|
||||
inTreePluginName, err := ctl.GetInTreeNameFromCSIName(csiPluginName)
|
||||
if err != nil {
|
||||
t.Errorf("Error when mapping CSI plugin name to In-tree plugin name %s", err)
|
||||
}
|
||||
if !IsMigratableIntreePluginByName(inTreePluginName) {
|
||||
if !ctl.IsMigratableIntreePluginByName(inTreePluginName) {
|
||||
t.Errorf("%s expected to be migratable to a CSI name", inTreePluginName)
|
||||
}
|
||||
if inTreePluginName != test.inTreePluginName || csiPluginName != test.csiPluginName {
|
||||
|
@ -34,7 +34,7 @@ import (
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
csilib "k8s.io/csi-translation-lib"
|
||||
csitrans "k8s.io/csi-translation-lib"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
"k8s.io/kubernetes/test/e2e/framework/metrics"
|
||||
"k8s.io/kubernetes/test/e2e/framework/podlogs"
|
||||
@ -558,7 +558,8 @@ func addOpCounts(o1 opCounts, o2 opCounts) opCounts {
|
||||
func getMigrationVolumeOpCounts(cs clientset.Interface, pluginName string) (opCounts, opCounts) {
|
||||
if len(pluginName) > 0 {
|
||||
var migratedOps opCounts
|
||||
csiName, err := csilib.GetCSINameFromInTreeName(pluginName)
|
||||
l := csitrans.New()
|
||||
csiName, err := l.GetCSINameFromInTreeName(pluginName)
|
||||
if err != nil {
|
||||
framework.Logf("Could not find CSI Name for in-tree plugin %v", pluginName)
|
||||
migratedOps = opCounts{}
|
||||
|
Loading…
Reference in New Issue
Block a user