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](/2018/11/12/script-create-vmware-vsphere-netapp-nfs-volume/images/New-VsphereNetappVolume.png)
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.
![Create VMware vSphere NetApp NFS Volume - PowerShell Dynamic Parameters with Dynamic ValidateSet](/2018/11/12/script-create-vmware-vsphere-netapp-nfs-volume/images/New-VsphereNetappVolume-Example.png)
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
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:
1
2
3
4
|
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:
1
2
3
4
5
|
PS C:\> Get-NcExportPolicy -Vserver svm-esxi -Name Cluster01
PolicyName PolicyId Vserver
---------- -------- -------
Cluster01 8589934597 svm-esxi
|
CLI:
1
2
3
4
|
netapp::> export-policy show -vserver svm-esxi -policyname Cluster01
Vserver: svm-esxi
Policy Name: Cluster01
|
Export Rule
PowerShell:
1
2
3
4
5
|
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:
1
2
3
4
5
6
7
8
|
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:
1
2
3
4
5
|
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!
Preview of upcoming functions of the module (and Blog Posts):
![Create VMware vSphere NetApp NFS Volume - Preview: Get-VsphereNetappVolume](/2018/11/12/script-create-vmware-vsphere-netapp-nfs-volume/images/Get-VsphereNetappVolume.png)
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.