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 Function
The New-VsphereNetappVolume PowerShell Function automates the following steps:
- Create a NetApp Volume
- Create an Export Policy if required
- Set recommended VMware settings for the new Volume
- Set Snapshot Policy for the new Volume
- Select the right IP of the NetApp SVM
- 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.
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.
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):
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.
No Responses