Sunday, 28 January 2018

Configuring iSCSI on ESXi using PowerCLI

In one of my previous post I stepped through the method of connecting my ESXi host to an iSCSI array using manual steps from creating the Standard vSwitch to port binding. In this post, I will talk about how I used powercli with esxcli to automate the steps so that it can be repeatable and quicker to deploy to your host. This will ensure each host is built with the same consistency and should anything go wrong it will be easier to rectify as all your host are built using a script.

I will go through my script to explain each section of how to configure:
  • A new standard vSwitch
  • Assign two physical network adapter to the vSwitch
  • Create 2 VMKernel adapters for iSCSI
  • Bind the 2 VMKernel adapters to create the port binding
  • Create the connection to your iSCSI storage array
The full script is available here at github

The first bit is to define all the values for our variables that we would use within the script. If we were to run this script against another host you will need to just modify the values at the start of the script instead of looking for those values within the script. So here we go....

The first three variables are the ones that will need to be changed as they will be unique to each ESXi host you run this script on;

Define the IP address/FQDN of the host that you will be working on
$ESXHostName = "You ESXi Host IP or FQDN"
Define IP address to be given for iSCSI VMKernel adapter 1
$iSCSIIP1 = "IP Address for iSCSI VMKernel adapter 1"
Define IP address to be given for iSCSI VMKernel adapter 2
$iSCSIIP2 =  "IP Address for iSCSI VMKernel adapter 2"

The remaining variables should not change for each host as you deploy this script to. They should remain the same i.e. vSwitch names and physical network cards that would be used;

Define the subnet for iSCSI VMkernel adapters that have been defined above. As they are in the same subnet we just need a single variable for this
$iSCSISubnet = "Subnet for iSCSI VMKernel adapter"
Define the name you want to give for this vSwitch
$iSCSISwName = "Name you want to give for vSwitch"
Define the MTU size you are using for iSCSI. Make sure this value is the same from end to end for the iSCSI connection otherwise you could encounter issues
$iSCSIMTU = "MTU Size for iSCSI"
Define Name of the 1st iSCSI port group name
$iSCSIPg1Name = "Port Group 1 name"
Define Name of the 2nd iSCSI port group name
$iSCSIPg2Name = "Port Group 2 name"
Define the physical network card 1 that will be assigned to the vSwitch
$iSCSIPhyNic1 = "Your physical Adapter Nic 1 Name"
Define the physical network card 2 that will be assigned to the vSwitch
$iSCSIPhyNic2 = "Your physical Adapter Nic 2 Name"
Define the target iSCSI Array IP address for iSCSI connection
$iSCSItargetIP = "IP address of your iSCSI Array"

First thing is to connect to our esxi host that we defined in our variable and put it in maintenance mode
Connect-VIServer $ESXHostName
Set-VMHost -State "Maintenance"

Now we create our standard vSwitch using the switch name, MTU and assign the physical network cards defined in our variables
New-VirtualSwitch -Name $iSCSISwName -Mtu $iSCSIMTU -confirm:$false
$VMHostPhysicalNic1 = Get-vmhost | Get-VMHostNetworkAdapter -Physical -Name $iSCSIPhyNic1
get-virtualSwitch -name $iSCSISwName | Add-VirtualSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $VMHostPhysicalNic1 -Confirm:$false
$VMHostPhysicalNic2 = Get-vmhost | Get-VMHostNetworkAdapter -Physical -Name $iSCSIPhyNic2
get-virtualSwitch -name $iSCSISwName | Add-VirtualSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $VMHostPhysicalNic2 -Confirm:$false

Next step is to set the vSwitch policies to what we want. By default most of the settings I have set in the script is the default settings but to be sure I prefer apply it in case VMware changes the default settings out of the box in the future. This way we can ensure we know the exact settings we have applied on the vSwitch. You will see that “Set-NicTeamingPolicy” I have split the command into a few lines and this is just for ease of reading. All the settings could be done using a one-liner
Get-VirtualSwitch -Name $iSCSISwName | Get-SecurityPolicy | Set-SecurityPolicy -AllowPromiscuous $false -MacChanges $true -ForgedTransmits $true -confirm:$false
Get-VirtualSwitch -Name $iSCSISwName | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive $iSCSIPhyNic1,$iSCSIPhyNic2
Get-VirtualSwitch -Name $iSCSISwName | Get-NicTeamingPolicy | Set-NicTeamingPolicy -LoadBalancingPolicy LoadBalanceSrcId
Get-VirtualSwitch -Name $iSCSISwName | Get-NicTeamingPolicy | Set-NicTeamingPolicy -NetworkFailoverDetectionPolicy LinkStatus
Get-VirtualSwitch -Name $iSCSISwName | Get-NicTeamingPolicy | Set-NicTeamingPolicy -FailbackEnabled:$true -NotifySwitches:$true  

Now we create the VMKernel iSCSI adapters and the portgroups for them. Each VMKernel adapter will have its own portgroup
New-VMHostNetworkAdapter -VirtualSwitch $iSCSISwName -Portgroup $iSCSIPg1Name -IP $iSCSIIP1 -SubnetMask $iSCSISubnet -mtu $iSCSIMTU
New-VMHostNetworkAdapter -VirtualSwitch $iSCSISwName -Portgroup $iSCSIPg2Name -IP $iSCSIIP2 -SubnetMask $iSCSISubnet -mtu $iSCSIMTU

We now modify the port group settings for the 1st iSCSI and make the necessary changes where we inherit all the policies from the vSwitch. We set one network card as active and the other one as unused
get-virtualportgroup -Name $iSCSIPg1Name | get-nicteamingpolicy | Set-NicTeamingPolicy -MakeNicActive $iSCSIPhyNic1 -MakeNicUnused $iSCSIPhyNic2
Get-Virtualportgroup -Name $iSCSIPg1Name | Get-SecurityPolicy | Set-SecurityPolicy -AllowPromiscuousInherited $true -ForgedTransmitsInherited $true -MacChangesInherited $true -confirm:$false
get-virtualportgroup -Name $iSCSIPg1Name | get-nicteamingpolicy | Set-NicTeamingPolicy -InheritLoadBalancingPolicy:$true -InheritNetworkFailoverDetectionPolicy:$true
get-virtualportgroup -Name $iSCSIPg1Name | get-nicteamingpolicy | Set-NicTeamingPolicy -InheritNotifySwitches:$true -InheritFailback:$true -InheritFailoverOrder:$false

We now modify the port group settings for the other/2nd iSCSI and make the necessary changes where we inherit all the policies from the vSwitch. On this portgroup we do the opposite to the other port group. The unused network card on the port group above is set to active on this one and the active one is set to unused
get-virtualportgroup -Name $iSCSIPg2Name | get-nicteamingpolicy | Set-NicTeamingPolicy -MakeNicActive $iSCSIPhyNic2 -MakeNicUnused $iSCSIPhyNic1
Get-Virtualportgroup -Name $iSCSIPg2Name | Get-SecurityPolicy | Set-SecurityPolicy -AllowPromiscuousInherited $true -ForgedTransmitsInherited $true -MacChangesInherited $true -confirm:$false
get-virtualportgroup -Name $iSCSIPg2Name | get-nicteamingpolicy | Set-NicTeamingPolicy -InheritLoadBalancingPolicy:$true -InheritNetworkFailoverDetectionPolicy:$true
get-virtualportgroup -Name $iSCSIPg2Name | get-nicteamingpolicy | Set-NicTeamingPolicy -InheritNotifySwitches:$true -InheritFailback:$true -InheritFailoverOrder:$false

We will enable the iSCSI software adapter and let the script sleep for 30 seconds. This is really to let the iSCSI software enable itself in this period of time before moving on
Get-vmhoststorage | set-vmhoststorage -SoftwareIScsiEnabled $true
Write-Host "Sleeping for 30 Seconds..." -ForegroundColor Green
Start-Sleep -Seconds 30

We now get all VMKernel adapters information to be used later for port binding
$vmks = Get-VMHostNetworkAdapter | where {$_.name -like "vmk*"}

We store the iSCSI HBA details to be used later as well
$hba = Get-vmhost | Get-VMHostHba -Type iScsi | Where {$_.Model -eq "iSCSI Software Adapter"}

We create the connection using to our iSCSI target IP address from our variables using the hba details we got from above
New-IScsiHbaTarget -IScsiHba $hba -Address $iSCSItargetIP

Now we must filter out our VMKernel adapters and only get the ones that are connected to the iSCSI portgroups. We need to capture the device name and store those information
ForEach ($vmk in $vmks){If ($vmk.PortGroupName -eq $iSCSIPg1Name) {$vmkscsi01 = $vmk.DeviceName}}
ForEach ($vmk in $vmks){If ($vmk.PortGroupName -eq $iSCSIPg2Name) {$vmkscsi02 = $vmk.DeviceName}}

To do port binding we have to use esxcli commands but as you can run that in powershell context we will do that
$esxcli = Get-EsxCli -VMHost $ESXHost -v2

We issue the esxcli commands to create the port bindings with the two VMKernel adapters
$esxcli.iscsi.networkportal.add.invoke(@{adapter = $hba.device;nic = $vmkscsi01})
$esxcli.iscsi.networkportal.add.invoke(@{adapter = $hba.device;nic = $vmkscsi02})

I have got the command to print the iSCSI iqn out to screen. If your array just needs this information to create connections, then at this point you could put your code there if it supports powershell so that it goes in to the SAN array to finish off the configurations
$hba.iscsiname  

We issue a command to get the host to rescan all the HBA and hopefully this will pick up all the LUNS that has been presented to this host and let the script sleep for 30 seconds before carrying on
Get-VMHostStorage -VMHost $ESXHost -RescanAllHba
Write-Host "Sleeping for 30 Seconds to let the host scan and pick up all the luns ..." -ForegroundColor Green
Start-Sleep -Seconds 30
Finally we just disconnect from the host to complete the task
Disconnect-VIServer $ESXHostName -Force -Confirm:$false


Hope this script can come to some use for people that want to automate the build of the iSCSI connections from their ESXi host to iSCSI array. The script could be further enhanced where the variables information of all your host could be in a CSV file and you get the script to just read from the CSV file.

No comments:

Post a Comment

Azure Resource Support for Availability Zone

Over the years, an increasing number of services are consumed in the cloud and as architects one of the key considerations is designing the ...