Script – Create VMware vSphere NetApp NFS Volume

A few weeks ago I started to write a PowerShell Function that creates an optimized VMware vSphere NetApp NFS Volume and mounts this new volume to all VMware ESXi hosts within a vSphere Cluster. During the scripting process, I found, that a lot of NetApp specific inputs are required to process these steps. This was the perfect project to finally play with Dynamic ValidateSets in Dynamic Parameters.  Fabian Wendlandt already created a great example for the usage of Dynamic ValidateSets in Dynamic Parameters with his Switch-VMSwitch script.

Create VMware vSphere NetApp NFS Volume - PowerShell Console

Create VMware vSphere NetApp NFS Volume Function

The New-VsphereNetappVolume PowerShell Function automates the following steps:

  1. Create a NetApp Volume
  2. Create an Export Policy if required
  3. Set recommended VMware settings for the new Volume
  4. Set Snapshot Policy for the new Volume
  5. Select the right IP of the NetApp SVM
  6. Mount the new NetApp Volume on all ESXi hosts within a vSphere Cluster

The function is designed to create or use a NetApp Export Policy per vSphere Cluster. The Export Policy is named like the vSphere Cluster. If the Export Policy does not exist on the NetApp SVM, a new one is created and all ESXi IPs are added as Export Rule.

Create VMware vSphere NetApp NFS Volume - PowerShell Dynamic Parameters with Dynamic ValidateSet

All Inputs are created as Dynamic Parameters with Dynamic ValidateSet, this means that it is possible to tab through valid inputs for e.g. the vSphere Cluster or the NetApp SVM.

Note:

The inputs are not validated against each other, so you are able to select an interface that does not exist on the selected SVM.

function New-VsphereNetappVolume {
    <#
    .DESCRIPTION
        Creates a new a NetApp Volume and mounts it to ESXi Hosts.

    .NOTES
        File Name  : New-VsphereNetappVolume.psm1
        Author     : Markus Kraus
        Version    : 1.1
        State      : Ready

    .LINK
        https://mycloudrevolution.com/

    .EXAMPLE
        New-VsphereNetappVolume -VolName vol_vmware_11 -VolSize 1 -vSphereCluster Cluster01 -NetAppAggregate aggr_data -NetAppVserver svm-esxi -NetAppInterface svm-nfs_data -NetAppSnapshotPolicy default-1weekly

    .PARAMETER VolName
        Name of the new Volume

    .PARAMETER VolSize
        Size of the new Volume in GB

    .PARAMETER vSphereClusterName
        Name of the vSphere Cluster where the Volume needs to be mounted

    .PARAMETER NetAppAggregateName
        Name of the Aggregate where the Volume is created

    .PARAMETER NetAppVserverName
        Name of the SVM where the Volume is created

    .PARAMETER NetAppInterfaceName
        Name of the Interface that should be used for the mount

    #>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the new Volume")]
        [ValidateNotNullorEmpty()]
            [String]$VolName,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Size of the new Volume in GB")]
        [ValidateNotNullorEmpty()]
            [int]$VolSize
    )

    DynamicParam {
        # vSphere Cluster parameter
        $vSphereClusterName = 'vSphereCluster'
        $vSphereClusterAttributeProperty = @{
            Mandatory = $true;
            ValueFromPipeline = $False;
            HelpMessage = 'The vSphere Cluster Name'
        }
        $vSphereClusterAttribute = New-Object System.Management.Automation.ParameterAttribute -Property $vSphereClusterAttributeProperty

        $vSphereClusterValidateSet = Get-Cluster | Select-Object -ExpandProperty Name
        $vSphereClusterValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($vSphereClusterValidateSet)

        $vSphereClusterAttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $vSphereClusterAttributeCollection.Add($vSphereClusterAttribute)
        $vSphereClusterAttributeCollection.Add($vSphereClusterValidateSetAttribute)

        $vSphereClusterRuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($vSphereClusterName, [string], $vSphereClusterAttributeCollection)

        # NetApp vServer parameter
        $NetAppVserverName = 'NetAppVserver'
        $NetAppVserverAttributeProperty = @{
            Mandatory = $true;
            ValueFromPipeline = $False;
            HelpMessage = 'The NetApp Vserver Name'
        }
        $NetAppVserverAttribute = New-Object System.Management.Automation.ParameterAttribute -Property $NetAppVserverAttributeProperty

        $NetAppVserverValidateSet = (Get-NcVserver).where({$_.VserverType -eq "data"}) | Select-Object -ExpandProperty Vserver
        $NetAppVserverValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($NetAppVserverValidateSet)

        $NetAppVserverAttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $NetAppVserverAttributeCollection.Add($NetAppVserverAttribute)
        $NetAppVserverAttributeCollection.Add($NetAppVserverValidateSetAttribute)

        $NetAppVserverRuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($NetAppVserverName, [string], $NetAppVserverAttributeCollection)

        # NetApp Aggregate parameter
        $NetAppAggregateName = 'NetAppAggregate'
        $NetAppAggregateAttributeProperty = @{
            Mandatory = $true;
            ValueFromPipeline = $False;
            HelpMessage = 'The NetApp Aggregate Name'
        }
        $NetAppAggregateAttribute = New-Object System.Management.Automation.ParameterAttribute -Property $NetAppAggregateAttributeProperty

        $NetAppAggregateValidateSet = Get-NcAggr | Select-Object -ExpandProperty Name
        $NetAppAggregateValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($NetAppAggregateValidateSet)

        $NetAppAggregateAttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $NetAppAggregateAttributeCollection.Add($NetAppAggregateAttribute)
        $NetAppAggregateAttributeCollection.Add($NetAppAggregateValidateSetAttribute)

        $NetAppAggregateRuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($NetAppAggregateName, [string], $NetAppAggregateAttributeCollection)

        # NetApp Interface parameter
        $NetAppInterfaceName = 'NetAppInterface'
        $NetAppInterfaceAttributeProperty = @{
            Mandatory = $true;
            ValueFromPipeline = $False;
            HelpMessage = 'The NetApp Aggregate Name'
        }
        $NetAppInterfaceAttribute = New-Object System.Management.Automation.ParameterAttribute -Property $NetAppInterfaceAttributeProperty

        $NetAppInterfaceValidateSet = (Get-NcNetInterface).where({$_.FirewallPolicy -eq "data"}) | Select-Object -ExpandProperty InterfaceName
        $NetAppInterfaceValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($NetAppInterfaceValidateSet)

        $NetAppInterfaceAttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $NetAppInterfaceAttributeCollection.Add($NetAppInterfaceAttribute)
        $NetAppInterfaceAttributeCollection.Add($NetAppInterfaceValidateSetAttribute)

        $NetAppInterfaceRuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($NetAppInterfaceName, [string], $NetAppInterfaceAttributeCollection)

        # NetApp SnapShot Policy parameter
        $NetAppSnapshotPolicyName = 'NetAppSnapshotPolicy'
        $NetAppSnapshotPolicyAttributeProperty = @{
            Mandatory = $true;
            ValueFromPipeline = $False;
            HelpMessage = 'The NetApp Aggregate Name'
        }
        $NetAppSnapshotPolicyAttribute = New-Object System.Management.Automation.ParameterAttribute -Property $NetAppSnapshotPolicyAttributeProperty

        $NetAppSnapshotPolicyValidateSet = (Get-NcSnapshotPolicy).where({$_.Enabled -eq "True"}) | Select-Object -ExpandProperty Policy
        $NetAppSnapshotPolicyValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($NetAppSnapshotPolicyValidateSet)

        $NetAppSnapshotPolicyAttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $NetAppSnapshotPolicyAttributeCollection.Add($NetAppSnapshotPolicyAttribute)
        $NetAppSnapshotPolicyAttributeCollection.Add($NetAppSnapshotPolicyValidateSetAttribute)

        $NetAppSnapshotPolicyRuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($NetAppSnapshotPolicyName, [string], $NetAppSnapshotPolicyAttributeCollection)

        # Create and return parameter dictionary
        $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
        $RuntimeParameterDictionary.Add($vSphereClusterName, $vSphereClusterRuntimeParameter)
        $RuntimeParameterDictionary.Add($NetAppAggregateName, $NetAppAggregateRuntimeParameter)
        $RuntimeParameterDictionary.Add($NetAppVserverName, $NetAppVserverRuntimeParameter)
        $RuntimeParameterDictionary.Add($NetAppInterfaceName, $NetAppInterfaceRuntimeParameter)
        $RuntimeParameterDictionary.Add($NetAppSnapshotPolicyName, $NetAppSnapshotPolicyRuntimeParameter)

        $RuntimeParameterDictionary
    }

    Begin {

        # Assign DynamicParams to actual variables
        $vSphereClusterName = $PsBoundParameters[$vSphereClusterName]
        $NetAppAggregateName = $PsBoundParameters[$NetAppAggregateName]
        $NetAppVserverName = $PsBoundParameters[$NetAppVserverName]
        $NetAppInterfaceName = $PsBoundParameters[$NetAppInterfaceName]
        $NetAppSnapshotPolicyName = $PsBoundParameters[$NetAppSnapshotPolicyName]

        # Get real objects from parameters
        try {
            $vSphereCluster = Get-Cluster -Name $vSphereClusterName -Debug:$False
        }catch{ Throw "Failed to get Cluster" }

        try {
            $NetAppAggr = Get-NcAggr -Name $NetAppAggregateName
        }catch{ Throw "Failed to get NetApp Aggr" }

        try {
            $NetAppVserver = Get-NcVserver -Name $NetAppVserverName
        }catch{ Throw "Failed to get NetApp vServer (SVM)" }

        try {
            $NetAppInterface = Get-NcNetInterface -Name $NetAppInterfaceName
        }catch{ Throw "Failed to get NetApp Interface)" }

        try {
            $NetAppSnapshotPolicy = Get-NcSnapshotPolicy -Name $NetAppSnapshotPolicyName
        }catch{ Throw "Failed to get NetApp Snapshot Policy)" }

        if ($DebugPreference -eq "Inquire") {
                "vSphere Cluster:"
                $vSphereCluster | Format-Table -Autosize
                "NetApp Aggregate:"
                $NetAppAggr | Format-Table -Autosize
                "NetApp Vserver (SVM):"
                $NetAppVserver | Format-Table -Autosize
                "NetApp Interface:"
                $NetAppInterface | Format-Table -Autosize
                "NetApp Snapshot Policy:"
                $NetAppSnapshotPolicy | Format-Table -Autosize

        }

        $VolSizeByte = $VolSize * 130023424

    }

    Process {

        $IPs = ($vSphereCluster | Get-VMHost | Get-VMHostNetworkAdapter -VMKernel).IP
        $ClientMatch = $IPs -join ","

        if(!(Get-NcExportPolicy -Name $vSphereCluster.Name -VserverContext $NetAppVserver )){
            "Create new NetApp Export Policy '$($vSphereCluster.Name)' on SVM '$($NetAppVserver.Name)' ..."
            $NetAppExportPolicy = New-NcExportPolicy -Name $vSphereCluster.Name -VserverContext $NetAppVserver
            $NetAppExportRule = New-NcExportRule -VserverContext $NetAppVserver  -Policy $NetAppExportPolicy.PolicyName -ClientMatch $ClientMatch `
            -Protocol NFS -Index 1 -SuperUserSecurityFlavor any -ReadOnlySecurityFlavor any -ReadWriteSecurityFlavor any
        }else{"NetApp Export Policy '$($vSphereCluster.Name)' on SVM '$($NetAppVserver.Name)' aleady exists"}

        "Create new NetApp Volume '$VolName' on Aggregate '$($NetAppAggr.AggregateName)' ..."
        $NetAppVolume = New-NcVol -VserverContext $NetAppVserver -Name $VolName -Aggregate $NetAppAggr.AggregateName -JunctionPath $("/" + $VolName) `
        -ExportPolicy $vSphereCluster.Name -Size $VolSizeByte -SnapshotReserve 20 -SnapshotPolicy $NetAppSnapshotPolicy.Policy

        "Set Advanced Options for NetApp Volume '$VolName' ..."
        $NetAppVolume | Set-NcVolOption -Key fractional_reserve -Value 0
        $NetAppVolume | Set-NcVolOption -Key guarantee -Value none
        $NetAppVolume | Set-NcVolOption -key no_atime_update -Value on

        $VMHosts = $vSphereCluster | Get-VMHost
        ForEach ($VMHost in $VMHosts) {
            "Add new NetApp Datastore '$($NetAppVolume.Name)' to ESXi Host '$($VMHost.Name)' ..."
            $NewDatastore = $VMHost | New-Datastore -Nfs -Name $NetAppVolume.Name  -Path $("/" + $NetAppVolume.Name) -NfsHost $NetAppInterface.Address
        }

    }

}

Created NetApp objects

Volume

PowerShell:

PS C:\> Get-NcVol -Vserver svm-esxi -Name vol_vmware_13

Name                      State       TotalSize  Used  Available Dedupe Aggregate                 Vserver                                                                                                                                                     
----                      -----       ---------  ----  --------- ------ ---------                 -------                                                                                                                                                     
vol_vmware_13             online       124,0 MB   20%    99,0 MB False  aggr_data                 svm-esxi                                                                                                                                                    



PS C:\> Get-NcVolOption -Vserver svm-esxi -Name vol_vmware_13

Name                      NcController     Value      
----                      ------------     -----      
actual_guarantee          netapp.lab.local none       
convert_ucode             netapp.lab.local on         
create_ucode              netapp.lab.local on         
dr_force_nvfail           netapp.lab.local off        
effective_guarantee       netapp.lab.local none       
extent                    netapp.lab.local off        
fractional_reserve        netapp.lab.local 0          
fs_size_fixed             netapp.lab.local off        
guarantee                 netapp.lab.local none       
ignore_inconsistent       netapp.lab.local off        
max_write_alloc_blocks    netapp.lab.local 0          
maxdirsize                netapp.lab.local 83804      
minra                     netapp.lab.local off        
no_atime_update           netapp.lab.local on         
no_i2p                    netapp.lab.local off        
nosnap                    netapp.lab.local off        
nosnapdir                 netapp.lab.local off        
nvfail                    netapp.lab.local off        
read_realloc              netapp.lab.local off        
root                      netapp.lab.local false      
schedsnapname             netapp.lab.local create_time
snapmirrored              netapp.lab.local off        
snapshot_clone_dependency netapp.lab.local off        
try_first                 netapp.lab.local volume_grow

CLI:

netapp::> volume show -vserver svm-esxi -volume vol_vmware_13 -fields volume, vserver, aggregate,  snapshot-policy, fractional-reserve
vserver  volume        aggregate fractional-reserve snapshot-policy
-------- ------------- --------- ------------------ ---------------
svm-esxi vol_vmware_13 aggr_data 0%                 default-1weekly

Export Policy

PowerShell:

PS C:\> Get-NcExportPolicy -Vserver svm-esxi -Name Cluster01

PolicyName                                 PolicyId Vserver                                                                                                                                                                                                   
----------                                 -------- -------                                                                                                                                                                                                   
Cluster01                                8589934597 svm-esxi

CLI:

netapp::> export-policy show -vserver svm-esxi -policyname Cluster01

    Vserver: svm-esxi
Policy Name: Cluster01

Export Rule

PowerShell:

PS C:\> Get-NcExportRule -Vserver svm-esxi -Policy Cluster01

PolicyName               RuleIndex    ClientMatch      Protocol     RoRule       RwRule       Vserver                                                                                                                                                         
----------               ---------    -----------      --------     ------       ------       -------                                                                                                                                                         
Cluster01                1            192.168.3.110... {nfs}        {any}        {any}        svm-esxi

CLI:

netapp::> export-policy rule show -vserver svm-esxi -policyname Cluster01
             Policy          Rule    Access   Client                RO
Vserver      Name            Index   Protocol Match                 Rule
------------ --------------- ------  -------- --------------------- ---------
svm-esxi     Cluster01       1       nfs      192.168.3.110,        any
                                              10.100.10.101,
                                              192.168.3.111,
                                              10.100.10.102

VMware Datastore

PowerShell:

PS C:\> Get-Cluster -Name Cluster01 | Get-Datastore -Name vol_vmware_13 | select Name, Type, RemoteHost, RemotePath

Name          Type RemoteHost      RemotePath    
----          ---- ----------      ----------    
vol_vmware_13 NFS  {10.100.10.100} /vol_vmware_13

Get the Module

The function is part of my new vSphere NetApp Toolkit PowerShell Module. At the moment it`s the only only function in the module, but more function will follow!

PowerShell Gallery Read The Docs GitHub Project

 

Preview of upcoming functions of the module (and Blog Posts):

Create VMware vSphere NetApp NFS Volume - Preview: Get-VsphereNetappVolume

Contribute

Feel free to share your NetApp Best Practice to make this PowerShell function even better.

  • Do you set any additional Volume options?
  • Do you use any special Snapshot settings or options?

You are welcome to leave a comment or raise a GitHub issue.

Leave a Reply