Skip to content

Commit

Permalink
ontap-nas-economy fixes for 17.10.1
Browse files Browse the repository at this point in the history
Making qtree delete idempotent as needed by Trident
Allow deleting qtrees with really long names
  • Loading branch information
clintonk committed Nov 8, 2017
1 parent b925df1 commit c6c608f
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 10 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@

[Releases](https://github.com/NetApp/netappdvp/releases)

## Changes since 17.07.0
## Changes since 17.10.0

**Fixes:**
- Added delete idempotency to the ontap-nas-economy driver as needed by Trident.
- Fixed an issue where qtrees with names near the 64-character limit could not
be deleted.

**Enhancements:**


## 17.10.0

**Fixes:**
- Changed the SolidFire driver to tear down the iSCSI connection as part
Expand Down
56 changes: 48 additions & 8 deletions storage_drivers/ontap_nas_qtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
// OntapNASQtreeStorageDriverName is the constant name for this Ontap qtree-based NAS storage driver
const OntapNASQtreeStorageDriverName = "ontap-nas-economy"
const deletedQtreeNamePrefix = "deleted_"
const maxQtreeNameLength = 64
const maxQtreesPerFlexvol = 200
const defaultPruneFlexvolsPeriodSecs = uint64(600) // default to 10 minutes
const defaultResizeQuotasPeriodSecs = uint64(60) // default to 1 minute
Expand Down Expand Up @@ -171,20 +172,20 @@ func (d *OntapNASQtreeStorageDriver) startHousekeepingTasks() {

// Keep the system devoid of Flexvols with no qtrees
d.pruneUnusedFlexvols()
d.reapDeletedQtrees()
pruneTicker := time.NewTicker(time.Duration(pruneFlexvolsPeriodSecs) * time.Second)
go func() {
for t := range pruneTicker.C {
log.WithField("tick", t).Debug("Running housekeeping task: prune unused Flexvols.")
for range pruneTicker.C {
d.pruneUnusedFlexvols()
d.reapDeletedQtrees()
}
}()

// Keep the quotas current
d.resizeQuotas()
resizeTicker := time.NewTicker(time.Duration(resizeQuotasPeriodSecs) * time.Second)
go func() {
for t := range resizeTicker.C {
log.WithField("tick", t).Debug("Running housekeeping task: resize quotas.")
for range resizeTicker.C {
d.resizeQuotas()
}
}()
Expand Down Expand Up @@ -219,6 +220,11 @@ func (d *OntapNASQtreeStorageDriver) Create(name string, sizeBytes uint64, opts
return fmt.Errorf("Volume %s already exists.", name)
}

// Ensure qtree name isn't too long
if len(name) > maxQtreeNameLength {
return fmt.Errorf("Volume %s name exceeds the limit of %d characters.", name, maxQtreeNameLength)
}

// Get Flexvol options with default fallback values
// see also: ontap_common.go#PopulateConfigurationDefaults
size := strconv.FormatUint(sizeBytes, 10)
Expand Down Expand Up @@ -336,11 +342,19 @@ func (d *OntapNASQtreeStorageDriver) Destroy(name string) error {
}
if !exists {
log.WithField("qtree", name).Warn("Qtree not found.")
return nil
}

// Rename qtree so it doesn't show up in lists while ONTAP is deleting it in the background
// Rename qtree so it doesn't show up in lists while ONTAP is deleting it in the background.
// Ensure the deleted name doesn't exceed the qtree name length limit of 64 characters.
path := fmt.Sprintf("/vol/%s/%s", flexvol, name)
deletedPath := fmt.Sprintf("/vol/%s/%s", flexvol, deletedQtreeNamePrefix+name+"_"+utils.RandomString(5))
deletedName := deletedQtreeNamePrefix + name + "_" + utils.RandomString(5)
if len(deletedName) > maxQtreeNameLength {
trimLength := len(deletedQtreeNamePrefix) + 10
deletedName = deletedQtreeNamePrefix + name[trimLength:] + "_" + utils.RandomString(5)
}
deletedPath := fmt.Sprintf("/vol/%s/%s", flexvol, deletedName)

renameResponse, err := d.API.QtreeRename(path, deletedPath)
if err = ontap.GetError(renameResponse, err); err != nil {
log.Errorf("Qtree rename failed. %v", err)
Expand Down Expand Up @@ -801,6 +815,8 @@ func (d *OntapNASQtreeStorageDriver) resizeQuotas() {
d.provMutex.Lock()
defer d.provMutex.Unlock()

log.Debug("Housekeeping, resizing quotas.")

for flexvol, resize := range d.quotaResizeMap {

if resize {
Expand Down Expand Up @@ -872,6 +888,8 @@ func (d *OntapNASQtreeStorageDriver) pruneUnusedFlexvols() {
d.provMutex.Lock()
defer d.provMutex.Unlock()

log.Debug("Housekeeping, checking for managed Flexvols with no qtrees.")

// Get list of Flexvols managed by this driver
volumeListResponse, err := d.API.VolumeList(d.FlexvolNamePrefix())
if err = ontap.GetError(volumeListResponse, err); err != nil {
Expand All @@ -885,8 +903,6 @@ func (d *OntapNASQtreeStorageDriver) pruneUnusedFlexvols() {
flexvols = append(flexvols, volName)
}

log.WithField("flexvols", len(flexvols)).Debug("Housekeeping, checking for managed Flexvols with qtrees.")

// Destroy any Flexvol if it is devoid of qtrees
for _, flexvol := range flexvols {
qtreeCount, err := d.API.QtreeCount(flexvol)
Expand All @@ -897,6 +913,30 @@ func (d *OntapNASQtreeStorageDriver) pruneUnusedFlexvols() {
}
}

// reapDeletedQtrees is called periodically by a background task. Any qtrees
// that have been deleted (discovered by virtue of having a well-known hardcoded
// prefix on their names) are destroyed. This is only needed for the exceptional case
// in which a qtree was renamed (prior to being destroyed) but the subsequent
// destroy call failed or was never made due to a process interruption.
func (d *OntapNASQtreeStorageDriver) reapDeletedQtrees() {

log.Debug("Housekeeping, checking for deleted qtrees.")

// Get all deleted qtrees in all FlexVols managed by this driver
prefix := deletedQtreeNamePrefix + *d.Config.StoragePrefix
listResponse, err := d.API.QtreeList(prefix, d.FlexvolNamePrefix())
if err = ontap.GetError(listResponse, err); err != nil {
log.Errorf("Error listing deleted qtrees. %v", err)
}

// AttributesList() returns []QtreeInfoType
for _, qtree := range listResponse.Result.AttributesList() {
qtreePath := fmt.Sprintf("/vol/%s/%s", qtree.Volume(), qtree.Qtree())
log.WithField("qtree", qtreePath).Debug("Housekeeping, reaping deleted qtree.")
d.API.QtreeDestroyAsync(qtreePath, true)
}
}

// ensureDefaultExportPolicy checks for an export policy with a well-known name that will be suitable
// for setting on a Flexvol and will enable access to all qtrees therein. If the policy exists, the
// method assumes it created the policy itself and that all is good. If the policy does not exist,
Expand Down
2 changes: 1 addition & 1 deletion storage_drivers/storage_drivers.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const (
const ConfigVersion = 1

// DriverVersion is the actual release version number
const DriverVersion = "17.10.0"
const DriverVersion = "17.10.1"

// FullDriverVersion is the DriverVersion as well as any pre-release tags
var FullDriverVersion = DriverVersion
Expand Down

0 comments on commit c6c608f

Please sign in to comment.