Using PowerShell to prevent thinly provisioned NetApp LUNs from going offline – Part I

Happy Day-after Thanksgiving dear readers! I hope everyone is as satisfyingly full on food, friends, and family as I am. As an early gift to myself, I’m writing a PowerShell script that utilizes NetApp’s PowerShell Toolkit. The script will help me quickly determine current volume and LUN settings so I can see what LUNs are at risk of going offline due to out of space conditions. In scripting tradition, I couldn’t find anything online that did exactly what I wanted so I rolled my own!

Here’s what the output looks like. The column names are abbreviated because I expect to have several more columns. The abbreviations are, Volume Thin Provisioning, Fractional Reserve, Snapshots, Volume AutoGrow, Snapshot AutoDelete.

The usefulness of the script can be seen in the highlighted output. The Exchange volumes are thin provisioned, Fractional Reserve is set to 0 for each, Snapshots are on, and space protection settings Volume AutoGrow and Snapshot AutoDelete are not turned on. This tells me I should investigate these volumes and LUNs to be sure they’re configured properly. I would likely want to, at a minimum, turn on Volume AutoGrow and Snapshot AutoDelete.

I expect this script to be extremely useful to our Managed Services team, in particular, as we take on more and more Managed Services clients. We’ve been bitten more than once by out of space conditions even though we use OnCommand Unified Manager. When run, the script will allow someone to see, at a glance, which settings are not set according to NetApp’s best practices.

This is Part I of several posts that will show the evolution of this script into its final form. Earlier this week I brought the script into a minimally usable form which is enough to share with the community. There’s plenty more to do, no doubt, though. I have no LUN information, for example. The sole function does not sanitize inputs, and I’m sure some of the logic could be optimized for speed. It seems kind of slow right now and I’ve only been testing against FAS2240s. Either way, here it is in all its glory! Please share your thoughts on how to improve it or perhaps share a script of your own.

In addition, I’ve of course used many ideas from the internets. So if you see something in here that looks familiar, it’s probably yours 🙂 Thanks for letting me borrow it.

Requirements

NetApp PowerShell Toolkit

Data ONTAP 7-mode

Manually log into each controller using Connect-NaController

#$ErrorActionPreference = "SilentlyContinue" Function IsSnapMirrorDest ($VolName,$Filer) { #Returns $true or $false to the question #Is $VolName a VSM Destination? #VSM destination volumes don't handle Get-NaVolAutosize or #Get-NaSnapAutodelete well, so this function discovers #VSM destination volumes which allows the main function to #avoid querying them for Volume AutoSize or Snapshot AutoDelete #which avoids errors #I don't need all these variables; some are left for reference, though #$SourceFiler = $null #$Source = $null $DestinationFiler = $null #$Destination = $null $Pair = $null $IsSnapMirrorDest = $null #Get the VSM status of the volume $Pair = Get-NaSnapmirror $VolName #If volume is not in a VSM relationship, the output of #the Get-NaSnapmirror function will return a null string #This if statement checks to see if the volume is in a VSM #relationship and falls into it if it is not if($Pair -ne $null) { #I ended up only needing the $DestinationFiler #for this function, but the others are left #for reference #$SourceFiler = ($Pair.Source.Split(":"))[0] #$Source = ($Pair.Source.Split(":"))[1] $DestinationFiler = ($Pair.Destination.Split(":"))[0] #$Destination = ($Pair.Destination.Split(":"))[1] #If this script is run on the destination controller of #this volume's VSM relationship, return $true if($Filer -eq $DestinationFiler) { $IsSnapMirrorDest = $true return $IsSnapMirrorDest } #If this script is run on the source controller of #this volume's VSM relationship, return $false $IsSnapMirrorDest = $false return $IsSnapMirrorDest } #This else condition is used when the volume is not part #of a VSM relationship at all else { $IsSnapMirrorDest = $false return $IsSnapMirrorDest } } #cls $Vol = $null $ObjVol = $null $AutoSize = $null $AutoDelete = $null #Get controller name for comparison later $Filer = (Get-NaSystemInfo).SystemName #Create an empty collection of volumes $ColVol = @() #This script counts online and offline volumes for reference $NumVols = (Get-NaVol).Count $OnlineVols = 0 foreach($Vol in Get-NaVol) { #Offline volumes cannot be queried for all conditions, so this #script avoids querying them at all to avoid unnecessary work #i.e. I'm lazy and didn't want to script for so many conditions if($Vol.State -eq "online") { $OnlineVols = $OnlineVols + 1 #Look at each option name and decide if it's something #I want to query foreach($Option in Get-NaVolOption $Vol.Name) { #Create a set of properties for custom object assignment later $Properties = @{ Name=$Vol.Name; VolTP=$ThinProvisioned; FR=$FractionalReserve; Snaps=$Snaps; VolAG=$AutoSize; SnapAD=$AutoDelete } #Look at each option name and decide if it's something #I want to query. Right now, the options are #1. actual_guarantee #2. fractional_reserve #3. nosnap switch($Option.Name) { "actual_guarantee" { switch($Option.Value) { "volume" {$ThinProvisioned = "no"} "file" {$ThinProvisioned = "file"} "none" {$ThinProvisioned = "yes"} } } "fractional_reserve" {$FractionalReserve = $Option.Value} "nosnap" { if($Option.Value -eq "on") { $Snaps = "no" } else { $Snaps = "yes" } } } #Create a new custom object for each volume and assign #the properties $ObjVol = New-Object -TypeName PSObject -Property $Properties } #keep track of offline volumes for reference $OfflineVols = $NumVols - $OnlineVols #If a volume is a VSM destination, don't query it if((IsSnapMirrorDest $Vol.Name $Filer) -eq $false) { #Discover Volume AutoSize settings if((Get-NaVolAutosize $Vol).IsEnabled -eq "True") { $ObjVol.VolAG = "on" } else { $ObjVol.VolAG = "off" } #Discover Snapshot AutoDelete settings #GetValue(4) here gets the value of the 5th OptionName #(starts counting at 0) in the hash table $ObjVol.SnapAD = ((Get-NaSnapshotAutodelete $Vol).GetValue(4)).OptionValue } #This condition occurs when a volume is a VSM destination. Since #Volume AutoSize and Snapshot AutoDelete cannot be queried #without errors, these settings will be called out #by "VSM dest," meaning the volume is a VSM destination. else { $ObjVol.VolAG = "VSM dest" $ObjVol.SnapAD = "VSM dest" } #After every pass of a volume, append the custom object to #the collection of objects $ColVol += $ObjVol } } Write-Host "`n" Write-Host "--------------------------------" Write-Host "Controller: " $Filer Write-Host "Online volumes: " $OnlineVols Write-Host "Offline volumes: " $OfflineVols Write-Host "--------------------------------" $ColVol | Format-Table Name,VolTP,FR,Snaps,VolAG,SnapAD