Change:
Instantiating the interface causes the creation of pod local volume directory and json data file and not - This causes a problem where is failed (and as a result never gets called) then those pod local volume directories will never be cleaned up. /sig storage cc
Looks like is the PR that introduced this change and moved data file creation calls to .
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
/remove-lifecycle stale
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
Stale issues rot after 30d of inactivity. Mark the issue as fresh with . Rotten issues close after an additional 30d of inactivity. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle rotten
/remove-lifecycle stale
Rotten issues close after 30d of inactivity. Reopen the issue with . Mark the issue as fresh with . Send feedback to sig-testing, kubernetes/test-infra and/or . /close
Closing this issue. <detailsIn response to : Rotten issues close after 30d of inactivity. Reopen the issue with . Mark the issue as fresh with . /close Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/repen /remove-lifecycle stale
/reopen
Reopened this issue. <detailsIn response to : /reopen </details
/remove-lifecycle stale
Rotten issues close after 30d of inactivity. Reopen the issue with . Mark the issue as fresh with . Send feedback to sig-testing, kubernetes/test-infra and/or . /close
Closing this issue. <detailsIn response to : Rotten issues close after 30d of inactivity. Reopen the issue with . Mark the issue as fresh with . /close Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/reopen /remove-lifecycle rotten
Reopened this issue. <detailsIn response to : /reopen /remove-lifecycle rotten Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
Stale issues rot after 30d of inactivity. Mark the issue as fresh with . Rotten issues close after an additional 30d of inactivity. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle rotten
Rotten issues close after 30d of inactivity. Reopen the issue with . Mark the issue as fresh with . Send feedback to sig-contributor-experience at . /close
Closing this issue. <detailsIn response to : Rotten issues close after 30d of inactivity. Reopen the issue with . Mark the issue as fresh with . /close Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/reopen /lifecycle frozen
Reopened this issue. <detailsIn response to : /reopen /lifecycle frozen Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
This issue is currently awaiting triage. If a SIG or subproject determines this is a relevant issue, they will accept it by applying the label and provide further guidance. The label can be by org members by writing in a comment. <detailsInstructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details

Discussion:
} } <ins> // Save volume info in pod dir // persist volume info data for teardown nodeName := string(c.plugin.host.GetNodeName()) volData := map[string]string{ volDataKey.specVolID:           c.spec.Name(), volDataKey.volHandle:           volumeHandle, volDataKey.driverName:          string(c.driverName), volDataKey.nodeName:            nodeName, volDataKey.volumeLifecycleMode: string(c.volumeLifecycleMode), volDataKey.attachmentID:        getAttachmentName(volumeHandle, string(c.driverName), nodeName), } err = saveVolumeData(parentDir, volDataFileName, volData) defer func() { // Only if there was an error and volume operation was considered // finished, we should remove the directory. if err != nil && volumetypes.IsOperationFinishedError(err) { // attempt to cleanup volume mount dir if removeerr := removeMountDir(c.plugin, dir); removeerr != nil { klog.Error(log("mounter.SetUpAt failed to remove mount dir after error [%s]: %v", dir, removeerr)) } } }() if err != nil { errorMsg := log("mounter.SetUpAt failed to save volume info data: %v", err) klog.Error(errorMsg) return volumetypes.NewTransientOperationFailure(errorMsg) } </ins> err = csi.NodePublishVolume( ctx, volumeHandle,

testAccount = "test-service-account" ) <ins> func prepareVolumeInfoFile(mountPath string, plug *csiPlugin, specVolumeName, volumeID, driverName, lifecycleMode string) error { nodeName := string(plug.host.GetNodeName()) volData := map[string]string{ volDataKey.specVolID:           specVolumeName, volDataKey.volHandle:           volumeID, volDataKey.driverName:          driverName, volDataKey.nodeName:            nodeName, volDataKey.attachmentID:        getAttachmentName(volumeID, driverName, nodeName), volDataKey.volumeLifecycleMode: lifecycleMode, } if err := os.MkdirAll(mountPath, 0755); err != nil { return fmt.Errorf("failed to create dir for volume info file: %s", err) } if err := saveVolumeData(mountPath, volDataFileName, volData); err != nil { return fmt.Errorf("failed to save volume info file: %s", err) } return nil } </ins> func TestMounterGetPath(t *testing.T) { plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir)

if !reflect.DeepEqual(vol.VolumeContext, test.expectedVolumeContext) { t.Errorf("csi server expected volumeContext %+v, got %+v", test.expectedVolumeContext, vol.VolumeContext) } <ins> // ensure data file is created dataDir := filepath.Dir(mounter.GetPath()) dataFile := filepath.Join(dataDir, volDataFileName) if _, err := os.Stat(dataFile); err != nil { if os.IsNotExist(err) { t.Errorf("data file not created %s", dataFile) } else { t.Fatal(err) } } data, err := loadVolumeData(dataDir, volDataFileName) if err != nil { t.Fatal(err) } if data[volDataKey.specVolID] != csiMounter.spec.Name() { t.Error("volume data file unexpected specVolID:", data[volDataKey.specVolID]) } if data[volDataKey.volHandle] != csiMounter.volumeID { t.Error("volume data file unexpected volHandle:", data[volDataKey.volHandle]) } if data[volDataKey.driverName] != string(csiMounter.driverName) { t.Error("volume data file unexpected driverName:", data[volDataKey.driverName]) } if data[volDataKey.nodeName] != string(csiMounter.plugin.host.GetNodeName()) { t.Error("volume data file unexpected nodeName:", data[volDataKey.nodeName]) } if data[volDataKey.volumeLifecycleMode] != string(csiMounter.volumeLifecycleMode) { t.Error("volume data file unexpected volumeLifecycleMode:", data[volDataKey.volumeLifecycleMode]) } </ins> }) } }

if vol.Path != csiMounter.GetPath() { t.Error("csi server may not have received NodePublishVolume call") } <ins> // ensure data file is created dataDir := filepath.Dir(mounter.GetPath()) dataFile := filepath.Join(dataDir, volDataFileName) if _, err := os.Stat(dataFile); err != nil { if os.IsNotExist(err) { t.Errorf("data file not created %s", dataFile) } else { t.Fatal(err) } } data, err := loadVolumeData(dataDir, volDataFileName) if err != nil { t.Fatal(err) } if data[volDataKey.specVolID] != csiMounter.spec.Name() { t.Error("volume data file unexpected specVolID:", data[volDataKey.specVolID]) } if data[volDataKey.volHandle] != csiMounter.volumeID { t.Error("volume data file unexpected volHandle:", data[volDataKey.volHandle]) } if data[volDataKey.driverName] != string(csiMounter.driverName) { t.Error("volume data file unexpected driverName:", data[volDataKey.driverName]) } if data[volDataKey.nodeName] != string(csiMounter.plugin.host.GetNodeName()) { t.Error("volume data file unexpected nodeName:", data[volDataKey.nodeName]) } if data[volDataKey.volumeLifecycleMode] != string(tc.mode) { t.Error("volume data file unexpected volumeLifecycleMode:", data[volDataKey.volumeLifecycleMode]) } </ins> }) } }

} mounter.csiClientGetter.driverName = csiDriverName(driverName) <del> // Save volume info in pod dir </del> dir := mounter.GetPath() <del> dataDir := filepath.Dir(dir) // dropoff /mount at end if err := os.MkdirAll(dataDir, 0750); err != nil { return nil, errors.New(log("failed to create dir %#v:  %v", dataDir, err)) } klog.V(4).Info(log("created path successfully [%s]", dataDir)) </del> mounter.MetricsProvider = NewMetricsCsi(volumeHandle, dir, csiDriverName(driverName)) <del> // persist volume info data for teardown node := string(p.host.GetNodeName()) volData := map[string]string{ volDataKey.specVolID:           spec.Name(), volDataKey.volHandle:           volumeHandle, volDataKey.driverName:          driverName, volDataKey.nodeName:            node, volDataKey.volumeLifecycleMode: string(volumeLifecycleMode), } attachID := getAttachmentName(volumeHandle, driverName, node) volData[volDataKey.attachmentID] = attachID err = saveVolumeData(dataDir, volDataFileName, volData) defer func() { // Only if there was an error and volume operation was considered // finished, we should remove the directory. if err != nil && volumetypes.IsOperationFinishedError(err) { // attempt to cleanup volume mount dir. if err = removeMountDir(p, dir); err != nil { klog.Error(log("attacher.MountDevice failed to remove mount dir after error [%s]: %v", dir, err)) } } }() if err != nil { errorMsg := log("csi.NewMounter failed to save volume info data: %v", err) klog.Error(errorMsg) return nil, errors.New(errorMsg) } </del> klog.V(4).Info(log("mounter created successfully")) return mounter, nil }

if spec.Name() != tc.specVolID { t.Errorf("Unexpected spec name constructed %s", spec.Name()) } }) } }

} csiMounter := mounter.(*csiMountMgr) <ins> mountPath := filepath.Dir(csiMounter.GetPath()) err = prepareVolumeInfoFile(mountPath, plug, tc.originSpec.Name(), csiMounter.volumeID, testDriver, string(csiMounter.volumeLifecycleMode)) if err != nil { t.Fatalf("failed to save fake volume info file: %s", err) } </ins> // rebuild spec spec, err := plug.ConstructVolumeSpec("test-pv", filepath.Dir(csiMounter.GetPath())) if err != nil {

if csiMounter.volumeLifecycleMode != test.volumeLifecycleMode { t.Error("unexpected driver mode:", csiMounter.volumeLifecycleMode) } <del> // ensure data file is created dataDir := filepath.Dir(mounter.GetPath()) dataFile := filepath.Join(dataDir, volDataFileName) if _, err := os.Stat(dataFile); err != nil { if os.IsNotExist(err) { t.Errorf("data file not created %s", dataFile) } else { t.Fatal(err) } } data, err := loadVolumeData(dataDir, volDataFileName) if err != nil { t.Fatal(err) } if data[volDataKey.specVolID] != csiMounter.spec.Name() { t.Error("volume data file unexpected specVolID:", data[volDataKey.specVolID]) } if data[volDataKey.volHandle] != csiMounter.volumeID { t.Error("volume data file unexpected volHandle:", data[volDataKey.volHandle]) } if data[volDataKey.driverName] != string(csiMounter.driverName) { t.Error("volume data file unexpected driverName:", data[volDataKey.driverName]) } if data[volDataKey.nodeName] != string(csiMounter.plugin.host.GetNodeName()) { t.Error("volume data file unexpected nodeName:", data[volDataKey.nodeName]) } if data[volDataKey.volumeLifecycleMode] != string(test.volumeLifecycleMode) { t.Error("volume data file unexpected volumeLifecycleMode:", data[volDataKey.volumeLifecycleMode]) } </del> }) } }

if csiMounter.volumeLifecycleMode != test.volumeLifecycleMode { t.Error("unexpected driver mode:", csiMounter.volumeLifecycleMode) } <del> // ensure data file is created dataDir := filepath.Dir(mounter.GetPath()) dataFile := filepath.Join(dataDir, volDataFileName) if _, err := os.Stat(dataFile); err != nil { if os.IsNotExist(err) { t.Errorf("data file not created %s", dataFile) } else { t.Fatal(err) } } data, err := loadVolumeData(dataDir, volDataFileName) if err != nil { t.Fatal(err) } if data[volDataKey.specVolID] != csiMounter.spec.Name() { t.Error("volume data file unexpected specVolID:", data[volDataKey.specVolID]) } if data[volDataKey.volHandle] != csiMounter.volumeID { t.Error("volume data file unexpected volHandle:", data[volDataKey.volHandle]) } if data[volDataKey.driverName] != string(csiMounter.driverName) { t.Error("volume data file unexpected driverName:", data[volDataKey.driverName]) } if data[volDataKey.nodeName] != string(csiMounter.plugin.host.GetNodeName()) { t.Error("volume data file unexpected nodeName:", data[volDataKey.nodeName]) } if data[volDataKey.volumeLifecycleMode] != string(csiMounter.volumeLifecycleMode) { t.Error("volume data file unexpected volumeLifecycleMode:", data[volDataKey.volumeLifecycleMode]) } </del> }) } }