Skip to content

Commit 8642bee

Browse files
Revert publish info field from rawDevicePath to devicePath and attempt to recover the missing devicePath
This change reverts publish info field from rawDevicePath to devicePath. It also makes a better effort to recover the devicePath field for Filesystem-based volumes (non-raw block) that may have been lost during pre-23.01 to 23.01/23.04 upgrades.
1 parent d9550d8 commit 8642bee

11 files changed

Lines changed: 463 additions & 29 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
**Fixes:**
88

99
- Fixed ONTAP ZAPI request to ensure LUN serial number is queried when getting LUN attributes.
10+
- Revert publish info field from `rawDevicePath` to `devicePath`; added logic to populate and recover (in some cases)
11+
`devicePath` field.
12+
13+
**Enhancements:**
14+
- Added additional logic to verify iSCSI multipath device serial number and size.
15+
- Additional verification for iSCSI volumes to ensure correct multipath device is unstaged.
1016

1117
## v23.04.0
1218

frontend/csi/node_helpers/kubernetes/plugin.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/netapp/trident/frontend/csi"
1818
nodehelpers "github.com/netapp/trident/frontend/csi/node_helpers"
1919
. "github.com/netapp/trident/logging"
20+
"github.com/netapp/trident/utils"
2021
)
2122

2223
var osFs = afero.NewOsFs()
@@ -109,13 +110,18 @@ func (h *helper) reconcileVolumePublishInfo(ctx context.Context) error {
109110
h.publishedPaths = publishedPaths
110111
}
111112

113+
pvToDeviceMappings, err := utils.PVMountpointMappings(ctx)
114+
if err != nil {
115+
Logc(ctx).Errorf("Unable to get devices for mounted PVs.")
116+
}
117+
112118
for _, file := range files {
113119
// On Windows, the staging path is a directory whose name is the volume ID (e.g. pvc-<uuid>). We don't want to
114120
// attempt to reconcile directories.
115121
if file.IsDir() {
116122
continue
117123
}
118-
err := h.reconcileVolumePublishInfoFile(ctx, file.Name())
124+
err := h.reconcileVolumePublishInfoFile(ctx, file.Name(), pvToDeviceMappings)
119125
if err != nil {
120126
return err
121127
}
@@ -124,7 +130,9 @@ func (h *helper) reconcileVolumePublishInfo(ctx context.Context) error {
124130
return nil
125131
}
126132

127-
func (h *helper) reconcileVolumePublishInfoFile(ctx context.Context, file string) error {
133+
func (h *helper) reconcileVolumePublishInfoFile(
134+
ctx context.Context, file string, pvToDeviceMappings map[string]string,
135+
) error {
128136
volumeId := strings.ReplaceAll(file, ".json", "")
129137
paths, ok := h.publishedPaths[volumeId]
130138
if !ok {
@@ -133,7 +141,7 @@ func (h *helper) reconcileVolumePublishInfoFile(ctx context.Context, file string
133141
Log().Warningf("Could not determine determine published paths for volume: %s", volumeId)
134142
}
135143

136-
shouldDelete, err := h.VolumePublishManager.UpgradeVolumeTrackingFile(ctx, volumeId, paths)
144+
shouldDelete, err := h.VolumePublishManager.UpgradeVolumeTrackingFile(ctx, volumeId, paths, pvToDeviceMappings)
137145
if err != nil {
138146
Log().Infof("Volume tracking file upgrade failed for volume: %s .", volumeId)
139147
return err

frontend/csi/node_helpers/kubernetes/plugin_test.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ func TestReconcileVolumeTrackingInfo(t *testing.T) {
102102

103103
_ = osFs.Mkdir("/pods", 0o777)
104104
mockVolumePublishManager.EXPECT().GetVolumeTrackingFiles().Return([]os.FileInfo{fInfo}, nil)
105-
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(ctx, volId, make(map[string]struct{})).
105+
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(ctx, volId, make(map[string]struct{}),
106+
make(map[string]string)).
106107
Return(false, errors.New("foo"))
107108
err = h.reconcileVolumePublishInfo(ctx)
108109
assert.Error(t, err, "expected error if reconcile file fails")
@@ -127,27 +128,31 @@ func TestReconcileVolumeTrackingInfoFile(t *testing.T) {
127128

128129
validH := newValidHelper(orchestrator, volId, mockVolumePublishManager)
129130

130-
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(ctx, volId, paths).Return(false, nil)
131+
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(ctx, volId, paths,
132+
nil).Return(false, nil)
131133
mockVolumePublishManager.EXPECT().ValidateTrackingFile(ctx, volId).Return(false, nil)
132134

133-
err := validH.reconcileVolumePublishInfoFile(ctx, fName)
135+
err := validH.reconcileVolumePublishInfoFile(ctx, fName, nil)
134136
assert.NoError(t, err, "did not expect an error during reconcile")
135137

136-
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(ctx, volId, paths).Return(false, errors.New("foo"))
137-
err = validH.reconcileVolumePublishInfoFile(ctx, fName)
138+
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(ctx, volId, paths,
139+
nil).Return(false, errors.New("foo"))
140+
err = validH.reconcileVolumePublishInfoFile(ctx, fName, nil)
138141
assert.Error(t, err, "expected error if upgrade to tracking file occurred")
139142

140-
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(gomock.Any(), volId, paths).Return(false, nil)
143+
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(gomock.Any(), volId, paths,
144+
nil).Return(false, nil)
141145
mockVolumePublishManager.EXPECT().ValidateTrackingFile(gomock.Any(), volId).Return(true, nil)
142146
mockVolumePublishManager.EXPECT().DeleteTrackingInfo(gomock.Any(), volId).Return(errors.New("foo error"))
143147

144-
err = validH.reconcileVolumePublishInfoFile(ctx, fName)
148+
err = validH.reconcileVolumePublishInfoFile(ctx, fName, nil)
145149
assert.Error(t, err, "expected error if file delete failed")
146150

147-
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(ctx, volId, paths).Return(false, nil)
151+
mockVolumePublishManager.EXPECT().UpgradeVolumeTrackingFile(ctx, volId, paths,
152+
nil).Return(false, nil)
148153
mockVolumePublishManager.EXPECT().ValidateTrackingFile(ctx, volId).Return(false, errors.New("foo"))
149154

150-
err = validH.reconcileVolumePublishInfoFile(ctx, fName)
155+
err = validH.reconcileVolumePublishInfoFile(ctx, fName, nil)
151156
assert.Error(t, err, "expected error if validate tracking file error occurred")
152157
}
153158

frontend/csi/node_helpers/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type VolumePublishManager interface {
3030
ReadTrackingInfo(context.Context, string) (*utils.VolumeTrackingInfo, error)
3131
DeleteTrackingInfo(context.Context, string) error
3232
ListVolumeTrackingInfo(context.Context) (map[string]*utils.VolumeTrackingInfo, error)
33-
UpgradeVolumeTrackingFile(context.Context, string, map[string]struct{}) (bool, error)
33+
UpgradeVolumeTrackingFile(context.Context, string, map[string]struct{}, map[string]string) (bool, error)
3434
DeleteFailedUpgradeTrackingFile(context.Context, os.FileInfo)
3535
ValidateTrackingFile(context.Context, string) (bool, error)
3636
GetVolumeTrackingFiles() ([]os.FileInfo, error)

frontend/csi/volume_publish_manager.go

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ func (v *VolumePublishManager) readTrackingInfo(
9898
}
9999

100100
Logc(ctx).WithField("volumeTrackingInfo", volumeTrackingInfo).Debug("Volume tracking info found.")
101+
102+
// Given upgrade logic in volume_publish_manager, this should not
103+
// be the case but adding an extra check here to move the
104+
// rawDevicePath value to devicePath.
105+
if volumeTrackingInfo.RawDevicePath != "" && volumeTrackingInfo.DevicePath == "" {
106+
volumeTrackingInfo.DevicePath = volumeTrackingInfo.RawDevicePath
107+
volumeTrackingInfo.RawDevicePath = ""
108+
}
109+
101110
return &volumeTrackingInfo, nil
102111
}
103112

@@ -153,7 +162,7 @@ func (v *VolumePublishManager) DeleteTrackingInfo(ctx context.Context, volumeID
153162
// stagedDeviceInfo or legacy tracking file do not exist, or are unable to be unmarshalled, then an upgrade is not
154163
// possible, and we must delete the tracking file because it no longer has any value.
155164
func (v *VolumePublishManager) UpgradeVolumeTrackingFile(
156-
ctx context.Context, volumeId string, publishedPaths map[string]struct{},
165+
ctx context.Context, volumeId string, publishedPaths map[string]struct{}, pvToDeviceMappings map[string]string,
157166
) (bool, error) {
158167
var err error
159168
fields := LogFields{"volumeId": volumeId}
@@ -178,8 +187,81 @@ func (v *VolumePublishManager) UpgradeVolumeTrackingFile(
178187
// upon unmarshalling the json.
179188
if volumeTrackingInfo.VolumePublishInfo.FilesystemType != "" {
180189
Logc(ctx).Debug("Volume tracking method did not need to be upgraded.")
190+
191+
// For iSCSI case confirm iSCSI `devicePath` exists, if not check
192+
// `rawDevicePath` exist, if yes then copy the value else log an
193+
// error message in logs.
194+
if volumeTrackingInfo.VolumePublishInfo.IscsiTargetPortal == "" {
195+
Logc(ctx).Debug("IscsiTargetPortal was empty in volume publish info.")
196+
return false, nil
197+
}
198+
199+
Logc(ctx).Debug("Ensuring devicePath is present if not then attempting to recover it.")
200+
201+
// In 23.01 devicePath was changed to rawDevicePath, which led to missing devicePath for
202+
// attached volumes from pre-23.01 and newly created volumes instead of devicePath would
203+
// rawDevicePath. Starting 23.07, devicePath has been re-introduced, below effort ensures
204+
// devicePath value is populated based on rawDevicePath, if both are missing Trident
205+
// tries to identify the correct device based on the published paths.
206+
if volumeTrackingInfo.DevicePath == "" {
207+
if volumeTrackingInfo.RawDevicePath != "" {
208+
volumeTrackingInfo.DevicePath = volumeTrackingInfo.RawDevicePath
209+
volumeTrackingInfo.RawDevicePath = ""
210+
211+
Logc(ctx).WithFields(LogFields{
212+
"volumeID": volumeId,
213+
"devicePath": volumeTrackingInfo.DevicePath,
214+
"iscsiTargetPortal": volumeTrackingInfo.IscsiTargetPortal,
215+
"lun": volumeTrackingInfo.IscsiLunNumber,
216+
}).Debug("Updating new publish info records.")
217+
} else if len(volumeTrackingInfo.PublishedPaths) > 0 {
218+
// This is a best-effort to identify a missing device path
219+
for publishedPath := range volumeTrackingInfo.PublishedPaths {
220+
if device, ok := pvToDeviceMappings[publishedPath]; ok {
221+
volumeTrackingInfo.DevicePath = device
222+
Logc(ctx).WithFields(LogFields{
223+
"volumeID": volumeId,
224+
"devicePath": volumeTrackingInfo.DevicePath,
225+
"iscsiTargetPortal": volumeTrackingInfo.IscsiTargetPortal,
226+
"lun": volumeTrackingInfo.IscsiLunNumber,
227+
}).Debug("Updating new publish info records based on published paths.")
228+
}
229+
}
230+
}
231+
232+
if volumeTrackingInfo.DevicePath != "" {
233+
err = v.WriteTrackingInfo(ctx, volumeId, volumeTrackingInfo)
234+
if err != nil {
235+
Logc(ctx).WithFields(LogFields{
236+
"volumeID": volumeId,
237+
"devicePath": volumeTrackingInfo.DevicePath,
238+
"iscsiTargetPortal": volumeTrackingInfo.IscsiTargetPortal,
239+
"lun": volumeTrackingInfo.IscsiLunNumber,
240+
}).Error("Failed to update tracking file with device path information.")
241+
}
242+
} else {
243+
Logc(ctx).WithFields(LogFields{
244+
"volumeID": volumeId,
245+
"iscsiTargetPortal": volumeTrackingInfo.IscsiTargetPortal,
246+
"lun": volumeTrackingInfo.IscsiLunNumber,
247+
}).Error("New publish info is missing device path.")
248+
}
249+
} else if volumeTrackingInfo.RawDevicePath != "" {
250+
Logc(ctx).WithFields(LogFields{
251+
"volumeID": volumeId,
252+
"iscsiTargetPortal": volumeTrackingInfo.IscsiTargetPortal,
253+
"lun": volumeTrackingInfo.IscsiLunNumber,
254+
"devicePath": volumeTrackingInfo.DevicePath,
255+
"rawDevicePath": volumeTrackingInfo.RawDevicePath,
256+
}).Warn("Found both devices.")
257+
258+
// No need to have two sources of device path information
259+
volumeTrackingInfo.RawDevicePath = ""
260+
}
261+
181262
return false, nil
182263
}
264+
183265
file = path.Join(volumeTrackingInfo.StagingTargetPath, volumePublishInfoFilename)
184266
err = utils.JsonReaderWriter.ReadJSONFile(ctx, publishInfo, file, "publish info")
185267
if err != nil {
@@ -202,6 +284,41 @@ func (v *VolumePublishManager) UpgradeVolumeTrackingFile(
202284
volumeTrackingInfo.VolumePublishInfo = *publishInfo
203285
volumeTrackingInfo.PublishedPaths = publishedPaths
204286

287+
// (arorar): I do not think this condition will ever be true since `rawDevicePath`
288+
// was introduced after this migration logic and `devicePath` has been re-introduced.
289+
if volumeTrackingInfo.VolumePublishInfo.IscsiTargetPortal != "" {
290+
if volumeTrackingInfo.DevicePath == "" {
291+
if volumeTrackingInfo.RawDevicePath != "" {
292+
volumeTrackingInfo.DevicePath = volumeTrackingInfo.RawDevicePath
293+
volumeTrackingInfo.RawDevicePath = ""
294+
295+
Logc(ctx).WithFields(LogFields{
296+
"volumeID": volumeId,
297+
"devicePath": volumeTrackingInfo.DevicePath,
298+
"iscsiTargetPortal": volumeTrackingInfo.IscsiTargetPortal,
299+
"lun": volumeTrackingInfo.IscsiLunNumber,
300+
}).Debug("Updating publish info records.")
301+
} else {
302+
Logc(ctx).WithFields(LogFields{
303+
"volumeID": volumeId,
304+
"iscsiTargetPortal": volumeTrackingInfo.IscsiTargetPortal,
305+
"lun": volumeTrackingInfo.IscsiLunNumber,
306+
}).Errorf("Publish info is missing device path.")
307+
}
308+
} else if volumeTrackingInfo.RawDevicePath != "" {
309+
Logc(ctx).WithFields(LogFields{
310+
"volumeID": volumeId,
311+
"iscsiTargetPortal": volumeTrackingInfo.IscsiTargetPortal,
312+
"lun": volumeTrackingInfo.IscsiLunNumber,
313+
"devicePath": volumeTrackingInfo.DevicePath,
314+
"rawDevicePath": volumeTrackingInfo.RawDevicePath,
315+
}).Warn("Found both devices.")
316+
317+
// No need to have two sources of device path information
318+
volumeTrackingInfo.RawDevicePath = ""
319+
}
320+
}
321+
205322
Logc(ctx).WithField("publishInfoLocation", volumeTrackingInfo).Debug("Publish info location found.")
206323
err = v.WriteTrackingInfo(ctx, volumeId, volumeTrackingInfo)
207324
if err != nil {

0 commit comments

Comments
 (0)