Skip to content

Commit

Permalink
Added cleanup of internal snapshots created during ONTAP cloning
Browse files Browse the repository at this point in the history
* Updates ONTAP-* drivers to remove internal snapshots when deleting cloned volumes.
* Updates exiting unit tests and adds new unit tests.
  • Loading branch information
vivintw committed Jul 30, 2024
1 parent 722e7ef commit cc6b280
Show file tree
Hide file tree
Showing 12 changed files with 1,560 additions and 569 deletions.
2 changes: 1 addition & 1 deletion storage_drivers/ontap/api/ontap_rest_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ type RestClientInterface interface {
NodeList(ctx context.Context, pattern string) (*cluster.NodesGetOK, error)
NodeListSerialNumbers(ctx context.Context) ([]string, error)
// EmsAutosupportLog generates an auto support message with the supplied parameters
EmsAutosupportLog(ctx context.Context, appVersion string, autoSupport bool, category string, computerName string, eventDescription string, eventID int, eventSource string, logLevel int) error
EmsAutosupportLog(ctx context.Context, appVersion string, autoSupport bool, category, computerName, eventDescription string, eventID int, eventSource string, logLevel int) error
TieringPolicyValue(ctx context.Context) string
// ExportPolicyCreate creates an export policy
// equivalent to filer::> vserver export-policy create
Expand Down
4 changes: 2 additions & 2 deletions storage_drivers/ontap/api/ontap_zapi_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type ZapiClientInterface interface {
// equivalent to filer::> lun create -vserver iscsi_vs -path /vol/v/lun1 -size 1g -ostype linux -space-reserve disabled -space-allocation enabled
LunCreate(
lunPath string, sizeInBytes int, osType string, qosPolicyGroup QosPolicyGroup,
spaceReserved bool, spaceAllocated bool,
spaceReserved, spaceAllocated bool,
) (*azgo.LunCreateBySizeResponse, error)
// LunCloneCreate clones a LUN from a snapshot
LunCloneCreate(
Expand Down Expand Up @@ -370,7 +370,7 @@ type ZapiClientInterface interface {
NodeListSerialNumbers(ctx context.Context) ([]string, error)
// EmsAutosupportLog generates an auto support message with the supplied parameters
EmsAutosupportLog(
appVersion string, autoSupport bool, category string, computerName string, eventDescription string,
appVersion string, autoSupport bool, category, computerName, eventDescription string,
eventID int, eventSource string, logLevel int,
) (*azgo.EmsAutosupportLogResponse, error)
TieringPolicyValue(ctx context.Context) string
Expand Down
60 changes: 59 additions & 1 deletion storage_drivers/ontap/ontap_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -3055,9 +3055,13 @@ func createFlexvolSnapshot(

// cloneFlexvol creates a volume clone
func cloneFlexvol(
ctx context.Context, name, source, snapshot, labels string, split bool, config *drivers.OntapStorageDriverConfig,
ctx context.Context, cloneVolConfig *storage.VolumeConfig, labels string, split bool, config *drivers.OntapStorageDriverConfig,
client api.OntapAPI, qosPolicyGroup api.QosPolicyGroup,
) error {
name := cloneVolConfig.InternalName
source := cloneVolConfig.CloneSourceVolumeInternal
snapshot := cloneVolConfig.CloneSourceSnapshotInternal

fields := LogFields{
"Method": "cloneFlexvol",
"Type": "ontap_common",
Expand Down Expand Up @@ -3085,6 +3089,7 @@ func cloneFlexvol(
if err = client.VolumeSnapshotCreate(ctx, snapshot, source); err != nil {
return err
}
cloneVolConfig.CloneSourceSnapshotInternal = snapshot
}

// Create the clone based on a snapshot
Expand Down Expand Up @@ -3467,3 +3472,56 @@ func ConstructPoolForLabels(nameTemplate string, labels map[string]string) *stor

return pool
}

// deleteAutomaticSnapshot deletes a snapshot that was created automatically during volume clone creation.
// An automatic snapshot is detected by the presence of CloneSourceSnapshotInternal in the volume config
// while CloneSourceSnapshot is not set. This method is called after the volume has been deleted, and it
// will only attempt snapshot deletion if the clone volume deletion completed without error. This is a
// best-effort method, and any errors encountered will be logged but not returned.
func deleteAutomaticSnapshot(
ctx context.Context, driver storage.Driver, volDeleteError error, volConfig *storage.VolumeConfig,
snapshotDelete func(context.Context, string, string) error,
) {
name := volConfig.InternalName
source := volConfig.CloneSourceVolumeInternal
snapshotInternal := volConfig.CloneSourceSnapshotInternal
snapshot := volConfig.CloneSourceSnapshot

fields := LogFields{
"Method": "DeleteAutomaticSnapshot",
"Type": "ontap_common",
"snapshotName": snapshotInternal,
"volumeName": name,
}

methodDebugTraceFlags := driver.GetCommonConfig(ctx).DebugTraceFlags["method"]
Logd(ctx, driver.Name(), methodDebugTraceFlags).WithFields(fields).Trace(">>>> deleteAutomaticSnapshot")
defer Logd(ctx, driver.Name(), methodDebugTraceFlags).WithFields(fields).Trace("<<<< deleteAutomaticSnapshot")

logFields := LogFields{
"snapshotName": snapshotInternal,
"cloneSourceName": source,
"cloneName": name,
}

// Check if there is anything to do
if !(snapshot == "" && snapshotInternal != "") {
Logc(ctx).WithFields(logFields).Debug("No automatic clone source snapshot exists, skipping cleanup.")
return
}

// If the clone volume couldn't be deleted, don't attempt to delete any automatic snapshot.
if volDeleteError != nil {
Logc(ctx).WithFields(logFields).Debug("Error deleting volume, skipping automatic snapshot cleanup.")
return
}

if err := snapshotDelete(ctx, volConfig.CloneSourceSnapshotInternal, volConfig.CloneSourceVolumeInternal); err != nil {
if api.IsNotFoundError(err) {
Logc(ctx).WithFields(logFields).Debug("Automatic snapshot not found, skipping cleanup.")
} else {
Logc(ctx).WithFields(logFields).WithError(err).Error("Error deleting automatic snapshot. " +
"Any automatic snapshot must be manually deleted.")
}
}
}
Loading

0 comments on commit cc6b280

Please sign in to comment.