Skip to content

Commit 3860b63

Browse files
Fix the issue with wrong FsType when the volume is created after retry
1 parent a12483d commit 3860b63

12 files changed

Lines changed: 179 additions & 68 deletions

mocks/mock_storage_drivers/mock_ontap/mock_api.go

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

storage_drivers/ontap/api/abstraction.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ type OntapAPI interface {
9292
LunDestroy(ctx context.Context, lunPath string) error
9393
LunGetFSType(ctx context.Context, lunPath string) (string, error)
9494
LunGetAttribute(ctx context.Context, lunPath, attributeName string) (string, error)
95-
LunSetAttribute(ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions string) error
95+
LunSetAttribute(ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions, poolName string) error
9696
LunSetComment(ctx context.Context, lunPath, comment string) error
9797
LunSetQosPolicyGroup(ctx context.Context, lunPath string, qosPolicyGroup QosPolicyGroup) error
9898
LunGetByName(ctx context.Context, name string) (*Lun, error)

storage_drivers/ontap/api/abstraction_rest.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2224,7 +2224,7 @@ func (d OntapAPIREST) LunDestroy(ctx context.Context, lunPath string) error {
22242224
}
22252225

22262226
func (d OntapAPIREST) LunSetAttribute(
2227-
ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions string,
2227+
ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions, poolName string,
22282228
) error {
22292229
if strings.Contains(lunPath, failureLUNSetAttr) {
22302230
return errors.New("injected error")
@@ -2256,6 +2256,12 @@ func (d OntapAPIREST) LunSetAttribute(
22562256
}
22572257
}
22582258

2259+
// Save the pool name attribute at the end. Set new attribute as needed before this.
2260+
if err := d.api.LunSetAttribute(ctx, lunPath, "poolName", poolName); err != nil {
2261+
Logc(ctx).WithField("LUN", lunPath).Warning("Failed to save the pool name attribute for new LUN.")
2262+
return fmt.Errorf("failed to save the pool name attribute for new LUN: %w", err)
2263+
}
2264+
22592265
return nil
22602266
}
22612267

storage_drivers/ontap/api/abstraction_rest_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4021,18 +4021,19 @@ func TestLunSetAttribute(t *testing.T) {
40214021

40224022
// case 1: Positive test, update LUN attribute. context is empty.
40234023
rsi.EXPECT().LunSetAttribute(ctx, "/", "filesystem", "fake-FStype").Return(nil)
4024-
err := oapi.LunSetAttribute(ctx, "/", "filesystem", "fake-FStype", "", "", "")
4024+
rsi.EXPECT().LunSetAttribute(ctx, "/", "poolName", "").Return(nil)
4025+
err := oapi.LunSetAttribute(ctx, "/", "filesystem", "fake-FStype", "", "", "", "")
40254026
assert.NoError(t, err, "error returned while modifying a LUN attribute")
40264027

40274028
// case 2: Positive test, update LUN attribute. pass the value in context..
40284029
rsi.EXPECT().LunSetAttribute(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
40294030
err = oapi.LunSetAttribute(ctx, "/", "filesystem", "fake-FStype",
4030-
"context", "LUKS", "formatOptions")
4031+
"context", "LUKS", "formatOptions", "poolName")
40314032
assert.NoError(t, err, "error returned while modifying a LUN attribute")
40324033

40334034
// case 3 Negative test, update LUN attribute returned error..
40344035
err = oapi.LunSetAttribute(ctx, "failure_7c3a89e2_7d83_457b_9e29_bfdb082c1d8b",
4035-
"filesystem", "fake-FStype", "context", "LUKS", "formatOptions")
4036+
"filesystem", "fake-FStype", "context", "LUKS", "formatOptions", "poolName")
40364037
assert.Error(t, err, "no error returned while modifying a LUN attribute")
40374038
}
40384039

storage_drivers/ontap/api/abstraction_zapi.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ func (d OntapAPIZAPI) LunGetAttribute(ctx context.Context, lunPath, attributeNam
571571
}
572572

573573
func (d OntapAPIZAPI) LunSetAttribute(
574-
ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions string,
574+
ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions, poolName string,
575575
) error {
576576
var attrResponse interface{}
577577
var err error
@@ -607,6 +607,13 @@ func (d OntapAPIZAPI) LunSetAttribute(
607607
}
608608
}
609609

610+
// Save the pool name attribute at the end. Set new attribute as needed before this.
611+
attrResponse, err = d.api.LunSetAttribute(lunPath, "poolName", poolName)
612+
if err = azgo.GetError(ctx, attrResponse, err); err != nil {
613+
Logc(ctx).WithField("LUN", lunPath).Warning("Failed to save the pool name attribute for new LUN.")
614+
return fmt.Errorf("failed to save the pool name attribute for new LUN: %w", err)
615+
}
616+
610617
return nil
611618
}
612619

storage_drivers/ontap/api/abstraction_zapi_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,19 @@ func TestLunSetAttributeZapi(t *testing.T) {
132132

133133
// case 1a: Positive test, update LUN attribute - fsType.
134134
zapi.EXPECT().LunSetAttribute(tempLunPath, tempAttribute, "fake-FStype").Return(&response, nil).Times(1)
135-
err := oapi.LunSetAttribute(ctx, tempLunPath, tempAttribute, "fake-FStype", "", "", "")
135+
zapi.EXPECT().LunSetAttribute(tempLunPath, "poolName", "").Return(&response, nil).Times(1)
136+
err := oapi.LunSetAttribute(ctx, tempLunPath, tempAttribute, "fake-FStype", "", "", "", "")
136137
assert.NoError(t, err, "error returned while modifying a LUN attribute")
137138

138139
// case 1b: Negative test, d.api.LunSetAttribute for fsType return error
139140
zapi.EXPECT().LunSetAttribute(tempLunPath, tempAttribute, "fake-FStype").Return(nil, errors.New("error")).Times(1)
140-
err = oapi.LunSetAttribute(ctx, tempLunPath, tempAttribute, "fake-FStype", "", "", "")
141+
err = oapi.LunSetAttribute(ctx, tempLunPath, tempAttribute, "fake-FStype", "", "", "", "")
141142
assert.Error(t, err)
142143

143-
// case 2: Positive test, update LUN attributes those are: context, luks, formatOptions.
144+
// case 2: Positive test, update LUN attributes those are: context, luks, formatOptions, poolName.
144145
zapi.EXPECT().LunSetAttribute(tempLunPath, gomock.Any(), gomock.Any()).Return(&response, nil).AnyTimes()
145146
err = oapi.LunSetAttribute(ctx, tempLunPath, "filesystem", "",
146-
"context", "LUKS", "formatOptions")
147+
"context", "LUKS", "formatOptions", "poolName")
147148
assert.NoError(t, err, "error returned while modifying a LUN attribute")
148149
}
149150

storage_drivers/ontap/ontap_asa.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,9 @@ func (d *ASAStorageDriver) Create(
420420

421421
// Save the fstype in a LUN attribute so we know what to do in Attach. If this fails, clean up and
422422
// move on to the next pool.
423-
// Save the context, fstype, and LUKS value in LUN comment
423+
// Save the context, fstype, LUKS value, and pool name in LUN comment
424424
err = d.API.LunSetAttribute(ctx, name, LUNAttributeFSType, fstype, string(d.Config.DriverContext),
425-
luksEncryption, formatOptions)
425+
luksEncryption, formatOptions, storagePool.Name())
426426
if err != nil {
427427

428428
errMessage := fmt.Sprintf("error saving file system type for LUN %s: %v", name, err)

storage_drivers/ontap/ontap_asa_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ func TestCreateASA(t *testing.T) {
737737
mockAPI.EXPECT().TieringPolicyValue(ctx).Return("fake").Times(1)
738738
mockAPI.EXPECT().LunCreate(ctx, gomock.Any()).Return(nil).Times(1)
739739
mockAPI.EXPECT().LunSetComment(ctx, volumeName, labels).Return(nil).Times(1)
740-
mockAPI.EXPECT().LunSetAttribute(ctx, volumeName, LUNAttributeFSType, storagePool.InternalAttributes()[FileSystemType], string(driver.Config.DriverContext), storagePool.InternalAttributes()[LUKSEncryption], storagePool.InternalAttributes()[FormatOptions]).Return(nil).Times(1)
740+
mockAPI.EXPECT().LunSetAttribute(ctx, volumeName, LUNAttributeFSType, storagePool.InternalAttributes()[FileSystemType], string(driver.Config.DriverContext), storagePool.InternalAttributes()[LUKSEncryption], storagePool.InternalAttributes()[FormatOptions], storagePool.Name()).Return(nil).Times(1)
741741
},
742742
verify: func(t *testing.T, err error) {
743743
assert.NoError(t, err, "Should not be an error")
@@ -763,7 +763,7 @@ func TestCreateASA(t *testing.T) {
763763
mockAPI.EXPECT().TieringPolicyValue(ctx).Return("fake").Times(1)
764764
mockAPI.EXPECT().LunCreate(ctx, gomock.Any()).Return(nil).Times(1)
765765
mockAPI.EXPECT().LunSetComment(ctx, volumeName, labels).Return(nil).Times(1)
766-
mockAPI.EXPECT().LunSetAttribute(ctx, volumeName, LUNAttributeFSType, storagePool.InternalAttributes()[FileSystemType], string(driver.Config.DriverContext), storagePool.InternalAttributes()[LUKSEncryption], storagePool.InternalAttributes()[FormatOptions]).Return(nil).Times(1)
766+
mockAPI.EXPECT().LunSetAttribute(ctx, volumeName, LUNAttributeFSType, storagePool.InternalAttributes()[FileSystemType], string(driver.Config.DriverContext), storagePool.InternalAttributes()[LUKSEncryption], storagePool.InternalAttributes()[FormatOptions], storagePool.Name()).Return(nil).Times(1)
767767
},
768768
verify: func(t *testing.T, err error) {
769769
assert.NoError(t, err, "Should not be an error")
@@ -782,7 +782,7 @@ func TestCreateASA(t *testing.T) {
782782
assert.Equal(t, expectedLabels, labels, "Labels should match the expected value")
783783
return nil
784784
}).Times(1)
785-
mockAPI.EXPECT().LunSetAttribute(ctx, volumeName, LUNAttributeFSType, storagePool.InternalAttributes()[FileSystemType], string(driver.Config.DriverContext), storagePool.InternalAttributes()[LUKSEncryption], storagePool.InternalAttributes()[FormatOptions]).Return(nil).Times(1)
785+
mockAPI.EXPECT().LunSetAttribute(ctx, volumeName, LUNAttributeFSType, storagePool.InternalAttributes()[FileSystemType], string(driver.Config.DriverContext), storagePool.InternalAttributes()[LUKSEncryption], storagePool.InternalAttributes()[FormatOptions], storagePool.Name()).Return(nil).Times(1)
786786
},
787787
verify: func(t *testing.T, err error) {
788788
assert.NoError(t, err, "Should not be an error")
@@ -857,7 +857,8 @@ func TestCreateASA(t *testing.T) {
857857
storagePool.InternalAttributes()[FileSystemType],
858858
string(driver.Config.DriverContext),
859859
storagePool.InternalAttributes()[LUKSEncryption],
860-
storagePool.InternalAttributes()[FormatOptions]).
860+
storagePool.InternalAttributes()[FormatOptions],
861+
storagePool.Name()).
861862
Return(errors.New("api-error")).Times(1)
862863
mockAPI.EXPECT().LunDestroy(ctx, volumeName).Return(nil).Times(1)
863864
},

storage_drivers/ontap/ontap_san.go

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,11 @@ func (d *SANStorageDriver) validate(ctx context.Context) error {
260260
return nil
261261
}
262262

263-
// destroyVolumeIfNoLUN attempts to destroy volume if there exists a volume with no associated LUN.
264-
// This is used to make Create() idempotent by cleaning up a Flexvol with no LUN.
263+
// cleanupIncompleteLUN attempts to destroy volume if there exists a volume with no associated LUN.
264+
// This is used to make Create() idempotent by cleaning up a Flexvol with no LUN or
265+
// the LUN exists but is associated with a different pool as it was not cleaned up properly and creation is retried
266+
// with different pool.
267+
// This can happen if volume creation succeeded but LUN creation failed in a previous Create() call.
265268
// Returns (Volume State, error)
266269
//
267270
// Caller can check for:
@@ -271,15 +274,18 @@ func (d *SANStorageDriver) validate(ctx context.Context) error {
271274
// - Could not destroy the required volume for an error.
272275
// Volume state:true indicating both volume and required LUN exist.
273276
// Volume state:false indicating no volume existed or cleaned up now.
274-
func (d *SANStorageDriver) destroyVolumeIfNoLUN(ctx context.Context, volConfig *storage.VolumeConfig) (bool, error) {
277+
func (d *SANStorageDriver) cleanupIncompleteLUN(
278+
ctx context.Context, volConfig *storage.VolumeConfig, poolName string,
279+
) (bool, error) {
275280
name := volConfig.InternalName
276281
fields := LogFields{
277-
"Method": "destroyVolumeIfNoLUN",
278-
"Type": "SANStorageDriver",
279-
"name": name,
282+
"Method": "cleanupIncompleteLUN",
283+
"Type": "SANStorageDriver",
284+
"name": name,
285+
"poolName": poolName,
280286
}
281-
Logd(ctx, d.Name(), d.Config.DebugTraceFlags["method"]).WithFields(fields).Trace(">>>> destroyVolumeIfNoLUN")
282-
defer Logd(ctx, d.Name(), d.Config.DebugTraceFlags["method"]).WithFields(fields).Trace("<<<< destroyVolumeIfNoLUN")
287+
Logd(ctx, d.Name(), d.Config.DebugTraceFlags["method"]).WithFields(fields).Trace(">>>> cleanupIncompleteLUN")
288+
defer Logd(ctx, d.Name(), d.Config.DebugTraceFlags["method"]).WithFields(fields).Trace("<<<< cleanupIncompleteLUN")
283289

284290
volExists, err := d.API.VolumeExists(ctx, name)
285291
if err != nil {
@@ -297,20 +303,44 @@ func (d *SANStorageDriver) destroyVolumeIfNoLUN(ctx context.Context, volConfig *
297303
// Verify if LUN exists.
298304
newLUNPath := lunPath(name)
299305
extantLUN, err := d.API.LunGetByName(ctx, newLUNPath)
300-
if extantLUN != nil {
301-
// Volume and LUN both exist. No clean up needed.
302-
return true, nil
303-
}
304-
if !errors.IsNotFoundError(err) {
306+
if err != nil && !errors.IsNotFoundError(err) {
305307
// Could not verify if LUN exists. Clean up pending.
306308
return false, fmt.Errorf("error checking for existing LUN %s: %v", newLUNPath, err)
307309
}
308-
// LUN does not exist, but volume. Initiate clean-up.
309-
if err = d.API.VolumeDestroy(ctx, name, true, true); err != nil {
310-
Logc(ctx).WithField("volume", name).Errorf("Could not clean up volume: %v", err)
311-
return true, fmt.Errorf("could not clean up partial create of vol/lun: %v", err)
310+
311+
var destroyReason string
312+
var destroyErrorMsg string
313+
314+
if extantLUN != nil {
315+
// Both the volume and LUN exist. Check if the last attribute set on the LUN, i.e., the pool name, matches.
316+
lunPoolName, err := d.API.LunGetAttribute(ctx, newLUNPath, "poolName")
317+
if err != nil || lunPoolName != poolName {
318+
// If there is an error getting pool name or pool name doesn't match
319+
Logc(ctx).WithFields(LogFields{
320+
"LUN": newLUNPath,
321+
"lunPoolName": lunPoolName,
322+
"inputPoolName": poolName,
323+
"error": err,
324+
}).Info("Pool name not found or mismatch detected. Destroying volume.")
325+
326+
destroyReason = "Destroyed volume with mismatched pool name."
327+
destroyErrorMsg = "could not destroy volume with mismatched pool"
328+
} else {
329+
// Pool name matches or no pool name attribute. No clean up needed.
330+
return true, nil
331+
}
332+
} else {
333+
// LUN does not exist, but volume does. Initiate clean-up.
334+
destroyReason = "Cleaned up volume since LUN create failed."
335+
destroyErrorMsg = "could not clean up partial create of vol/lun"
336+
}
337+
338+
if err := d.API.VolumeDestroy(ctx, name, true, true); err != nil {
339+
Logc(ctx).WithError(err).WithField("volume", name).Errorf("Could not clean up volume")
340+
return true, fmt.Errorf("%s: %v", destroyErrorMsg, err)
312341
}
313-
Logc(ctx).WithField("volume", name).Debug("Cleaned up volume since LUN create failed.")
342+
Logc(ctx).WithField("volume", name).Debug(destroyReason)
343+
314344
return false, nil
315345
}
316346

@@ -332,7 +362,7 @@ func (d *SANStorageDriver) Create(
332362
defer Logd(ctx, d.Name(), d.Config.DebugTraceFlags["method"]).WithFields(fields).Trace("<<<< Create")
333363

334364
// Early exit if volume+LUN exist. Clean up volume if no LUN exists.
335-
volExists, err := d.destroyVolumeIfNoLUN(ctx, volConfig)
365+
volExists, err := d.cleanupIncompleteLUN(ctx, volConfig, storagePool.Name())
336366
if err != nil {
337367
return fmt.Errorf("failure checking for existence of volume and cleaning if any: %v", err)
338368
}
@@ -574,11 +604,10 @@ func (d *SANStorageDriver) Create(
574604

575605
// Save the fstype in a LUN attribute so we know what to do in Attach. If this fails, clean up and
576606
// move on to the next pool.
577-
// Save the context, fstype, and LUKS value in LUN comment
607+
// Save the context, fstype, LUKS value, and pool name in LUN comment
578608
err = d.API.LunSetAttribute(ctx, lunPath, LUNAttributeFSType, fstype, string(d.Config.DriverContext),
579-
luksEncryption, formatOptions)
609+
luksEncryption, formatOptions, storagePool.Name())
580610
if err != nil {
581-
582611
errMessage := fmt.Sprintf("ONTAP-SAN pool %s/%s; error saving file system type for LUN %s: %v",
583612
storagePool.Name(), aggregate, name, err)
584613
Logc(ctx).Error(errMessage)

storage_drivers/ontap/ontap_san_economy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ func (d *SANEconomyStorageDriver) Create(
709709

710710
// Save the fstype in a LUN attribute so we know what to do in Attach
711711
err = d.API.LunSetAttribute(ctx, lunPathEco, LUNAttributeFSType, fstype, string(d.Config.DriverContext),
712-
luksEncryption, formatOptions)
712+
luksEncryption, formatOptions, storagePool.Name())
713713
if err != nil {
714714

715715
errMessage := fmt.Sprintf(

0 commit comments

Comments
 (0)