Skip to content

Commit ea33a5a

Browse files
Fix the issue with wrong FsType when the volume is created after retry
1 parent ec74284 commit ea33a5a

12 files changed

Lines changed: 180 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
@@ -89,7 +89,7 @@ type OntapAPI interface {
8989
LunGetGeometry(ctx context.Context, lunPath string) (uint64, error)
9090
LunGetFSType(ctx context.Context, lunPath string) (string, error)
9191
LunGetAttribute(ctx context.Context, lunPath, attributeName string) (string, error)
92-
LunSetAttribute(ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions string) error
92+
LunSetAttribute(ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions, poolName string) error
9393
LunSetComment(ctx context.Context, lunPath, comment string) error
9494
LunSetQosPolicyGroup(ctx context.Context, lunPath string, qosPolicyGroup QosPolicyGroup) error
9595
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
@@ -2164,7 +2164,7 @@ func (d OntapAPIREST) LunGetGeometry(ctx context.Context, lunPath string) (uint6
21642164
}
21652165

21662166
func (d OntapAPIREST) LunSetAttribute(
2167-
ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions string,
2167+
ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions, poolName string,
21682168
) error {
21692169
if strings.Contains(lunPath, failureLUNSetAttr) {
21702170
return errors.New("injected error")
@@ -2196,6 +2196,12 @@ func (d OntapAPIREST) LunSetAttribute(
21962196
}
21972197
}
21982198

2199+
// Save the pool name attribute at the end. Set new attribute as needed before this.
2200+
if err := d.api.LunSetAttribute(ctx, lunPath, "poolName", poolName); err != nil {
2201+
Logc(ctx).WithField("LUN", lunPath).Warning("Failed to save the pool name attribute for new LUN.")
2202+
return fmt.Errorf("failed to save the pool name attribute for new LUN: %w", err)
2203+
}
2204+
21992205
return nil
22002206
}
22012207

storage_drivers/ontap/api/abstraction_rest_test.go

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

40044004
// case 1: Positive test, update LUN attribute. context is empty.
40054005
rsi.EXPECT().LunSetAttribute(ctx, "/", "filesystem", "fake-FStype").Return(nil)
4006-
err := oapi.LunSetAttribute(ctx, "/", "filesystem", "fake-FStype", "", "", "")
4006+
rsi.EXPECT().LunSetAttribute(ctx, "/", "poolName", "").Return(nil)
4007+
err := oapi.LunSetAttribute(ctx, "/", "filesystem", "fake-FStype", "", "", "", "")
40074008
assert.NoError(t, err, "error returned while modifying a LUN attribute")
40084009

40094010
// case 2: Positive test, update LUN attribute. pass the value in context..
40104011
rsi.EXPECT().LunSetAttribute(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
40114012
err = oapi.LunSetAttribute(ctx, "/", "filesystem", "fake-FStype",
4012-
"context", "LUKS", "formatOptions")
4013+
"context", "LUKS", "formatOptions", "poolName")
40134014
assert.NoError(t, err, "error returned while modifying a LUN attribute")
40144015

40154016
// case 3 Negative test, update LUN attribute returned error..
40164017
err = oapi.LunSetAttribute(ctx, "failure_7c3a89e2_7d83_457b_9e29_bfdb082c1d8b",
4017-
"filesystem", "fake-FStype", "context", "LUKS", "formatOptions")
4018+
"filesystem", "fake-FStype", "context", "LUKS", "formatOptions", "poolName")
40184019
assert.Error(t, err, "no error returned while modifying a LUN attribute")
40194020
}
40204021

storage_drivers/ontap/api/abstraction_zapi.go

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

539539
func (d OntapAPIZAPI) LunSetAttribute(
540-
ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions string,
540+
ctx context.Context, lunPath, attribute, fstype, context, luks, formatOptions, poolName string,
541541
) error {
542542
var attrResponse interface{}
543543
var err error
@@ -573,6 +573,13 @@ func (d OntapAPIZAPI) LunSetAttribute(
573573
}
574574
}
575575

576+
// Save the pool name attribute at the end. Set new attribute as needed before this.
577+
attrResponse, err = d.api.LunSetAttribute(lunPath, "poolName", poolName)
578+
if err = azgo.GetError(ctx, attrResponse, err); err != nil {
579+
Logc(ctx).WithField("LUN", lunPath).Warning("Failed to save the pool name attribute for new LUN.")
580+
return fmt.Errorf("failed to save the pool name attribute for new LUN: %w", err)
581+
}
582+
576583
return nil
577584
}
578585

storage_drivers/ontap/api/abstraction_zapi_test.go

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

126126
// case 1a: Positive test, update LUN attribute - fsType.
127127
zapi.EXPECT().LunSetAttribute(tempLunPath, tempAttribute, "fake-FStype").Return(&response, nil).Times(1)
128-
err = oapi.LunSetAttribute(ctx, tempLunPath, tempAttribute, "fake-FStype", "", "", "")
128+
zapi.EXPECT().LunSetAttribute(tempLunPath, "poolName", "").Return(&response, nil).Times(1)
129+
err = oapi.LunSetAttribute(ctx, tempLunPath, tempAttribute, "fake-FStype", "", "", "", "")
129130
assert.NoError(t, err, "error returned while modifying a LUN attribute")
130131

131132
// case 1b: Negative test, d.api.LunSetAttribute for fsType return error
132133
zapi.EXPECT().LunSetAttribute(tempLunPath, tempAttribute, "fake-FStype").Return(nil, fmt.Errorf("error")).Times(1)
133-
err = oapi.LunSetAttribute(ctx, tempLunPath, tempAttribute, "fake-FStype", "", "", "")
134+
err = oapi.LunSetAttribute(ctx, tempLunPath, tempAttribute, "fake-FStype", "", "", "", "")
134135
assert.Error(t, err)
135136

136-
// case 2: Positive test, update LUN attributes those are: context, luks, formatOptions.
137+
// case 2: Positive test, update LUN attributes those are: context, luks, formatOptions, poolName.
137138
zapi.EXPECT().LunSetAttribute(tempLunPath, gomock.Any(), gomock.Any()).Return(&response, nil).AnyTimes()
138139
err = oapi.LunSetAttribute(ctx, tempLunPath, "filesystem", "",
139-
"context", "LUKS", "formatOptions")
140+
"context", "LUKS", "formatOptions", "poolName")
140141
assert.NoError(t, err, "error returned while modifying a LUN attribute")
141142
}
142143

storage_drivers/ontap/ontap_asa.go

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

407407
// Save the fstype in a LUN attribute so we know what to do in Attach. If this fails, clean up and
408408
// move on to the next pool.
409-
// Save the context, fstype, and LUKS value in LUN comment
409+
// Save the context, fstype, LUKS value, and pool name in LUN comment
410410
err = d.API.LunSetAttribute(ctx, name, LUNAttributeFSType, fstype, string(d.Config.DriverContext),
411-
luksEncryption, formatOptions)
411+
luksEncryption, formatOptions, storagePool.Name())
412412
if err != nil {
413413

414414
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
@@ -663,7 +663,7 @@ func TestCreateASA(t *testing.T) {
663663
mockAPI.EXPECT().TieringPolicyValue(ctx).Return("fake").Times(1)
664664
mockAPI.EXPECT().LunCreate(ctx, gomock.Any()).Return(nil).Times(1)
665665
mockAPI.EXPECT().LunSetComment(ctx, volumeName, labels).Return(nil).Times(1)
666-
mockAPI.EXPECT().LunSetAttribute(ctx, volumeName, LUNAttributeFSType, storagePool.InternalAttributes()[FileSystemType], string(driver.Config.DriverContext), storagePool.InternalAttributes()[LUKSEncryption], storagePool.InternalAttributes()[FormatOptions]).Return(nil).Times(1)
666+
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)
667667
},
668668
verify: func(t *testing.T, err error) {
669669
assert.NoError(t, err, "Should not be an error")
@@ -689,7 +689,7 @@ func TestCreateASA(t *testing.T) {
689689
mockAPI.EXPECT().TieringPolicyValue(ctx).Return("fake").Times(1)
690690
mockAPI.EXPECT().LunCreate(ctx, gomock.Any()).Return(nil).Times(1)
691691
mockAPI.EXPECT().LunSetComment(ctx, volumeName, labels).Return(nil).Times(1)
692-
mockAPI.EXPECT().LunSetAttribute(ctx, volumeName, LUNAttributeFSType, storagePool.InternalAttributes()[FileSystemType], string(driver.Config.DriverContext), storagePool.InternalAttributes()[LUKSEncryption], storagePool.InternalAttributes()[FormatOptions]).Return(nil).Times(1)
692+
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)
693693
},
694694
verify: func(t *testing.T, err error) {
695695
assert.NoError(t, err, "Should not be an error")
@@ -708,7 +708,7 @@ func TestCreateASA(t *testing.T) {
708708
assert.Equal(t, expectedLabels, labels, "Labels should match the expected value")
709709
return nil
710710
}).Times(1)
711-
mockAPI.EXPECT().LunSetAttribute(ctx, volumeName, LUNAttributeFSType, storagePool.InternalAttributes()[FileSystemType], string(driver.Config.DriverContext), storagePool.InternalAttributes()[LUKSEncryption], storagePool.InternalAttributes()[FormatOptions]).Return(nil).Times(1)
711+
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)
712712
},
713713
verify: func(t *testing.T, err error) {
714714
assert.NoError(t, err, "Should not be an error")
@@ -783,7 +783,8 @@ func TestCreateASA(t *testing.T) {
783783
storagePool.InternalAttributes()[FileSystemType],
784784
string(driver.Config.DriverContext),
785785
storagePool.InternalAttributes()[LUKSEncryption],
786-
storagePool.InternalAttributes()[FormatOptions]).
786+
storagePool.InternalAttributes()[FormatOptions],
787+
storagePool.Name()).
787788
Return(fmt.Errorf("api-error")).Times(1)
788789
mockAPI.EXPECT().LunDestroy(ctx, volumeName).Return(nil).Times(1)
789790
},

storage_drivers/ontap/ontap_san.go

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

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

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

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

333363
// Early exit if volume+LUN exist. Clean up volume if no LUN exists.
334-
volExists, err := d.destroyVolumeIfNoLUN(ctx, volConfig)
364+
volExists, err := d.cleanupIncompleteLUN(ctx, volConfig, storagePool.Name())
335365
if err != nil {
336366
return fmt.Errorf("failure checking for existence of volume and cleaning if any: %v", err)
337367
}
@@ -573,9 +603,9 @@ func (d *SANStorageDriver) Create(
573603

574604
// Save the fstype in a LUN attribute so we know what to do in Attach. If this fails, clean up and
575605
// move on to the next pool.
576-
// Save the context, fstype, and LUKS value in LUN comment
606+
// Save the context, fstype, LUKS value, and pool name in LUN comment
577607
err = d.API.LunSetAttribute(ctx, lunPath, LUNAttributeFSType, fstype, string(d.Config.DriverContext),
578-
luksEncryption, formatOptions)
608+
luksEncryption, formatOptions, storagePool.Name())
579609
if err != nil {
580610

581611
errMessage := fmt.Sprintf("ONTAP-SAN pool %s/%s; error saving file system type for LUN %s: %v",

storage_drivers/ontap/ontap_san_economy.go

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

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

699699
errMessage := fmt.Sprintf(

0 commit comments

Comments
 (0)