Fix VolumeAttachment garbage collection for migrated PVs

This commit is contained in:
Tim Ebert 2021-05-20 08:38:52 +02:00
parent ae1f28d7b0
commit cd3709232f
No known key found for this signature in database
GPG Key ID: 1D5C81A3991D0CC2
2 changed files with 66 additions and 43 deletions

View File

@ -715,33 +715,45 @@ func (adc *attachDetachController) processVolumeAttachments() error {
klog.Errorf("Unable to lookup pv object for: %q, err: %v", *pvName, err) klog.Errorf("Unable to lookup pv object for: %q, err: %v", *pvName, err)
continue continue
} }
var plugin volume.AttachableVolumePlugin
volumeSpec := volume.NewSpecFromPersistentVolume(pv, false) volumeSpec := volume.NewSpecFromPersistentVolume(pv, false)
plugin, err := adc.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec)
if err != nil || plugin == nil { // Consult csiMigratedPluginManager first before querying the plugins registered during runtime in volumePluginMgr.
// Currently VA objects are created for CSI volumes only. nil plugin is unexpected, generate a warning // In-tree plugins that provisioned PVs will not be registered anymore after migration to CSI, once the respective
klog.Warningf( // feature gate is enabled.
"Skipping processing the volume %q on nodeName: %q, no attacher interface found. err=%v", if inTreePluginName, err := adc.csiMigratedPluginManager.GetInTreePluginNameFromSpec(pv, nil); err == nil {
*pvName, if adc.csiMigratedPluginManager.IsMigrationEnabledForPlugin(inTreePluginName) {
nodeName, // PV is migrated and should be handled by the CSI plugin instead of the in-tree one
err) plugin, _ = adc.volumePluginMgr.FindAttachablePluginByName(csi.CSIPluginName)
continue // podNamespace is not needed here for Azurefile as the volumeName generated will be the same with or without podNamespace
volumeSpec, err = csimigration.TranslateInTreeSpecToCSI(volumeSpec, "" /* podNamespace */, adc.intreeToCSITranslator)
if err != nil {
klog.Errorf(
"Failed to translate intree volumeSpec to CSI volumeSpec for volume:%q, va.Name:%q, nodeName:%q: %s. Error: %v",
*pvName,
va.Name,
nodeName,
inTreePluginName,
err)
continue
}
}
} }
pluginName := plugin.GetPluginName()
if adc.csiMigratedPluginManager.IsMigrationEnabledForPlugin(pluginName) { if plugin == nil {
plugin, _ = adc.volumePluginMgr.FindAttachablePluginByName(csi.CSIPluginName) plugin, err = adc.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec)
// podNamespace is not needed here for Azurefile as the volumeName generated will be the same with or without podNamespace if err != nil || plugin == nil {
volumeSpec, err = csimigration.TranslateInTreeSpecToCSI(volumeSpec, "" /* podNamespace */, adc.intreeToCSITranslator) // Currently VA objects are created for CSI volumes only. nil plugin is unexpected, generate a warning
if err != nil { klog.Warningf(
klog.Errorf( "Skipping processing the volume %q on nodeName: %q, no attacher interface found. err=%v",
"Failed to translate intree volumeSpec to CSI volumeSpec for volume:%q, va.Name:%q, nodeName:%q: %v",
*pvName, *pvName,
va.Name,
nodeName, nodeName,
pluginName,
err) err)
continue continue
} }
} }
volumeName, err := volumeutil.GetUniqueVolumeNameFromSpec(plugin, volumeSpec) volumeName, err := volumeutil.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
if err != nil { if err != nil {
klog.Errorf( klog.Errorf(

View File

@ -36,7 +36,6 @@ import (
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/csi" "k8s.io/kubernetes/pkg/volume/csi"
"k8s.io/kubernetes/pkg/volume/gcepd"
"k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util"
) )
@ -351,17 +350,18 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2
} }
type vaTest struct { type vaTest struct {
testName string testName string
volName string volName string
podName string podName string
podNodeName string podNodeName string
pvName string pvName string
vaName string vaName string
vaNodeName string vaNodeName string
vaAttachStatus bool vaAttachStatus bool
csiMigration bool csiMigration bool
expected_attaches map[string][]string expected_attaches map[string][]string
expected_detaches map[string][]string expected_detaches map[string][]string
expectedASWAttachState cache.AttachState
} }
func Test_ADC_VolumeAttachmentRecovery(t *testing.T) { func Test_ADC_VolumeAttachmentRecovery(t *testing.T) {
@ -398,15 +398,26 @@ func Test_ADC_VolumeAttachmentRecovery(t *testing.T) {
expected_attaches: map[string][]string{}, expected_attaches: map[string][]string{},
expected_detaches: map[string][]string{"mynode-1": {"vol1"}}, expected_detaches: map[string][]string{"mynode-1": {"vol1"}},
}, },
{ { // pod is scheduled, volume is migrated, attach status:false, verify volume is marked as attached
testName: "CSI Migration", testName: "Scheduled Pod with migrated PV",
volName: "vol1", volName: "vol1",
podNodeName: "mynode-1", podNodeName: "mynode-1",
pvName: "pv1", pvName: "pv1",
vaName: "va1", vaName: "va1",
vaNodeName: "mynode-1", vaNodeName: "mynode-1",
vaAttachStatus: false, vaAttachStatus: false,
csiMigration: true, csiMigration: true,
expectedASWAttachState: cache.AttachStateAttached,
},
{ // pod is deleted, volume is migrated, attach status:false, verify volume is marked as uncertain
testName: "Deleted Pod with migrated PV",
volName: "vol1",
pvName: "pv1",
vaName: "va1",
vaNodeName: "mynode-1",
vaAttachStatus: false,
csiMigration: true,
expectedASWAttachState: cache.AttachStateUncertain,
}, },
} { } {
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
@ -424,7 +435,7 @@ func volumeAttachmentRecoveryTestCase(t *testing.T, tc vaTest) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIMigrationGCE, tc.csiMigration)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIMigrationGCE, tc.csiMigration)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InTreePluginGCEUnregister, tc.csiMigration)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InTreePluginGCEUnregister, tc.csiMigration)()
plugins = gcepd.ProbeVolumePlugins() // if InTreePluginGCEUnregister is enabled, only the CSI plugin is registered but not the in-tree one
plugins = append(plugins, csi.ProbeVolumePlugins()...) plugins = append(plugins, csi.ProbeVolumePlugins()...)
} else { } else {
plugins = controllervolumetesting.CreateTestPlugin() plugins = controllervolumetesting.CreateTestPlugin()
@ -569,8 +580,8 @@ func verifyExpectedVolumeState(t *testing.T, adc *attachDetachController, tc vaT
// Since csi migration is turned on, the attach state for the PV should be in CSI format. // Since csi migration is turned on, the attach state for the PV should be in CSI format.
attachedState := adc.actualStateOfWorld.GetAttachState( attachedState := adc.actualStateOfWorld.GetAttachState(
v1.UniqueVolumeName(csiPDUniqueNamePrefix+tc.volName), types.NodeName(tc.vaNodeName)) v1.UniqueVolumeName(csiPDUniqueNamePrefix+tc.volName), types.NodeName(tc.vaNodeName))
if attachedState != cache.AttachStateAttached { if attachedState != tc.expectedASWAttachState {
t.Fatalf("Expected attachedState %v, but it is %v", cache.AttachStateAttached, attachedState) t.Fatalf("Expected attachedState %v, but it is %v", tc.expectedASWAttachState, attachedState)
} }
// kubernetes.io/gce-pd/<volName> should not be marked when CSI Migration is on // kubernetes.io/gce-pd/<volName> should not be marked when CSI Migration is on