Automating Creating Load-Sharing Mirrors of the Data SVM(s) Rootvol

Introducing the “Super Rootvol LS Mirrors Creator” or SRLMC for short!

Creating load-sharing mirrors of the Data SVM’s rootvol - where the Data SVM serves NAS protocols - has been a NetApp best practice from pretty much year dot of Clustered DataONTAP (or ONTAP). It’s often arguable whether they’re really needed, and they can be a bit of a pain, but this blog post isn’t the place to go into the debate.

To make them less of a pain, here’s the “Super Rootvol LS Mirrors Creator”, and this is how it works:


- Run it (either from PowerShell, or you could create a BAT file to run the PowerShell - double-click and you’re off)
- It will prompt for cluster, username, and password.
- It does the usual, load DataONTAP PowerShell Toolkit, and connects to the cluster.
- It acquires the nodes in the cluster.
- It acquires the data aggregates in the cluster.
- If any node does not have a data aggregate, it exits!
- It automatically selects the first acquired data aggregate per node to be used for the LS Mirror volumes.
- It acquires all the running NAS data SVMs, and their root volume information.
- Then it goes ahead and creates LS Mirrors for the rootvol, for all the NAS data SVMs.
- If a data SVM already has LS Mirrors, it does nothing for that data SVM.
- If a data SVM had say only 2 nodes out of 4 with LS Mirrors, it creates LS Mirrors on the other 2 nodes (the tool might prove useful if you’re expanding your cluster.)


The Script

Copy and paste into a text editor and save as say SRLMC.ps1


######################################
## Super Rootvol LS Mirrors Creator ##
######################################

Param(
  [Parameter(Mandatory=$True)][String]$Cluster,
  [Parameter(Mandatory=$True)][String]$UserName,
  [Parameter(Mandatory=$True)][Security.SecureString]$Password
  # TIP: PS> $P = Read-Host -AsSecureString
  # ... you can use $P after -Password
)

## TITLE ##
"`nSuper Rootvol LS Mirrors Creator"
"================================`n"

## GENERIC: Loading PSTK ##
"INFO: DataONTAP PSTK loading ..."
[Void](Import-Module DataONTAP)
If(!(Get-Module DataONTAP)){"ERROR: No DataONTAP PSTK!";EXIT;PAUSE}
"INFO: DataONTAP PSTK loaded.`n"

## GENERIC: Connecting to $Cluster ##
"INFO: $Cluster connecting ..."
$Global:CurrentNcController = $NULL
$Cred = New-Object System.Management.Automation.PsCredential($UserName,$Password)
[Void](Connect-NcController -Name $Cluster -Credential $Cred)
If(!$Global:CurrentNcController){"ERROR: Cannot connect to $Cluster!";EXIT;PAUSE}
"INFO: $Cluster connected.`n"

## COLLECTING DATA - NODES ##
$Attrs_Node = Get-NcNode -Template
[System.Array]$Nodes = (Get-NcNode -Attributes $Attrs_Node).Node

## COLLECTING DATA - AGGRs ##
$Attrs_Aggr = Get-NcAggr -Template
Initialize-NcObjectProperty -Object $Attrs_Aggr -Name AggrOwnershipAttributes
$Query_Aggr = Get-NcAggr -Template
Initialize-NcObjectProperty -Object $Query_Aggr -Name AggrRaidAttributes
$Query_Aggr.AggrRaidAttributes.IsRootAggregate = $FALSE
$Aggrs = Get-NcAggr -Attributes $Attrs_Aggr -Query $Query_Aggr
If(!$Aggrs){"ERROR: No Data Aggregates!";EXIT;PAUSE}

## CHECKING ALL NODES HAVE (ATLEAST) ONE DATA AGGR ##
[System.Object]$AggrForLSM = @{}
[Boolean]$AllNodesHaveDataAggr = $TRUE
Foreach($Node in $Nodes){
  [System.Object]$DataAggrsOnNode = $Aggrs | Where{$_.AggrOwnershipAttributes.OwnerName -eq $Node}
  If($DataAggrsOnNode){
    [System.Array]$AggrsArray = $DataAggrsOnNode.Name
    $Aggregate = $AggrsArray[0]
    [String]$AggrForLSM.$Node = $Aggregate
    "INFO: Data aggr for LSM for node $Node = $Aggregate"
  } else {
    "ERROR: Node $Node has no data aggrs!";EXIT;PAUSE
  }
};""

## GET RUNNING NAS DATA SVMs with ROOTVOL INFO ##
$Attrs_DSVM = Get-NcVserver -Template
$Attrs_DSVM.RootVolume = ""
$Attrs_DSVM.AllowedProtocols = ""
$Query_DSVM = Get-NcVserver -Template
$Query_DSVM.State = "running"
$Query_DSVM.VserverType = "data"
$GetDataSVMs = Get-NcVserver -Attributes $Attrs_DSVM -Query $Query_DSVM
[System.Array]$DataSVMs = @()
$GetDataSVMs | Foreach{
  If(($_.AllowedProtocols -contains "cifs") -or ($_.AllowedProtocols -contains "nfs")){
    $DataSVMs += $_
  }
}
If(!$DataSVMs){"ERROR: No running NAS data SVMs!";EXIT;PAUSE}
else{
  $DataSVMs | Foreach{
    "INFO: Data SVM " + $_.VserverName + " has rootvol name = " + $_.RootVolume
  }
};""

## GET DATA FOR ROOTVOLs (need size and languge) ##
$Attrs_Vol = Get-NcVol -Template
Initialize-NcObjectProperty -Object $Attrs_Vol -Name VolumeLanguageAttributes
Initialize-NcObjectProperty -Object $Attrs_Vol -Name VolumeSpaceAttributes
[System.Object]$RootvolInfo = @{}
$DataSVMs | Foreach{
  [String]$SVM = $_.VserverName
  $RootvolInfo.$SVM = Get-NcVol -Attributes $Attrs_Vol -Name $_.RootVolume -VserverContext $SVM
  "INFO: Data SVM " + $SVM +,
  " has language " + $RootvolInfo.$SVM.VolumeLanguageAttributes.LanguageCode +,
  " and size " + $RootvolInfo.$SVM.VolumeSpaceAttributes.Size
};""

## CREATE OBJECT FOR SVM.NODE and if it has an LSM or not ##
$Attrs_SMRR = Get-NcSnapMirror -Template
$Query_SMRR = Get-NcSnapMirror -Template
$Query_SMRR.RelationshipType = "load_sharing"
Initialize-NcObjectProperty -Object $Attrs_Vol -Name VolumeIdAttributes
[System.Object]$CurrLSMs = @{}
$DataSVMs | Foreach{
  ## Setup some variables ##
  [String]$SVM = $_.VserverName
  [System.Object]$CurrLSMs.$SVM = @{}
  [Boolean]$CurrLSMs.$SVM.HasRootVolLSMs = $FALSE
  Foreach($Node in $Nodes){ [Boolean]$CurrLSMs.$SVM.$Node = $FALSE }
  ## Query for LS SnapMirrors of the RootVolume ##
  $Query_SMRR.SourceVserver = $SVM
  $Query_SMRR.SourceVolume = $_.RootVolume
  $LSMs = Get-NcSnapMirror -Attributes $Attrs_SMRR -Query $Query_SMRR
  ## Gather LSM info (if any) ##
  If($LSMs){
    "INFO: $SVM has LS mirrors of the rootvol."
    $CurrLSMs.$SVM.HasRootVolLSMs = $TRUE
    ## Cycle through LSMs ##
    Foreach($LSM in $LSMs){
      $DestLSMvol = $LSM.DestinationVolume
      $DestLSMnode = (Get-NcVol -Attributes $Attrs_Vol -Name $DestLSMvol -VserverContext $SVM).VolumeIdAttributes.Node
      "INFO: $SVM has an LSM volume on $DestLSMnode"
      $CurrLSMs.$SVM.$DestLSMnode = $TRUE
    }
  }else{
    "INFO: $SVM does NOT have LS mirrors of the rootvol."
  }
};""

## CREATE LSMs on NODES THAT DON'T HAVE THEM ##
$DataSVMs | Foreach{
  [String]$SVM = $_.VserverName
  [String]$RootVol = $_.RootVolume
  Foreach($Node in $Nodes){
    If($CurrLSMs.$SVM.$Node){}
    else{
      ## Volume Create ##
      [String]$Vol = ("$RootVol" + "_LSM_" + $Node.replace("-","_"))
      [String]$Agg = $AggrForLSM.$Node
      [Int32]$Size = $RootvolInfo.$SVM.VolumeSpaceAttributes.Size
      [String]$Lang = $RootvolInfo.$SVM.VolumeLanguageAttributes.LanguageCode
      [Void](New-NcVol -Name $Vol -VserverContext $SVM -Aggregate $Agg -Type dp -Size $Size -Language $Lang -JunctionPath $null)
      "INFO: Created LSM volume for $SVM on $Node called $Vol"
      ## LS SnapMirror Create ##
      [Void](New-NcSnapMirror -Source "//$SVM/$RootVol" -Destination "//$SVM/$Vol" -Type ls -Schedule hourly)
      "INFO: Created LSM mirror for $SVM and $RootVol to $Vol"
      ## LS SnapMirror Initialize (if didn't already have an LS mirror) ##
      If($CurrLSMs.$SVM.HasRootVolLSMs){
        [Void](Invoke-NcSnapMirrorInitialize -Destination "//$SVM/$Vol")
        "INFO: Initialized snapmirror to $Vol"
      }
    }
  }
  ## Initialize LS Set (if SVM had NO LSMs before) ##
  If($CurrLSMs.$SVM.HasRootVolLSMs){}
  Else{
    [Void](Invoke-NcSnapMirrorLsInitialize -Source "//$SVM/$RootVol")
    "INFO: //$SVM/$RootVol initialize-ls-set"
  }
};"";PAUSE



BONUS: Running with a Batch File

It’s nice to be able to double-click and run, and this is very easy to do. Copy paste the below into a text editor and save as say SRLMC.bat.

PowerShell.exe .\SRLMC.ps1

And below is an example of running this by double-clicking the SRLMC.bat file.

In this example we have 3 NAS SVMs. 1 already has LSMs on both nodes, so SRLMC has nothing to do for that SVM. The other 2 need LSMs created on both nodes.

Image: Super Rootvol LS Mirrors Creator in action!
Note: This was tested with ONTAP 9.1.

Comments