Thursday, December 4, 2014

Automatic VMware VLAN connectivity testing

Story behind this post

Recently we have built new datacenter network because old one wasn't anymore enough modern.
New network structure contains lot of more VLANs than earlier one because servers are now own VLANs based who owns them and which are they role.

After our network provider got new VLANs created and configured to VMware hosts I noticed that we should some how to test that all of them are configured correctly and connection at least to gateway works from each VLAN on each VMware hosts.

Automatic testing

Like always there is many ways to do automation so I choosed first idea what I got.

I created PowerCLI script which do following things with Windows Server 2012 R2 (probably it works with 2012 server too):

  • Migrates virtual machine to each host on VMware cluster one by one.
  • Moves virtual machine to each VLAN what is configured to VLANs.csv one by one.
  • Set IP address which is listed on VLANs.csv to virtual machine.
  • Uses ICMP (Ping) to test gateway connectivity.
  • Writes results to log file (which updates after every test) and to report file (which is generated after all the tests).

NOTE! You must disable UAC from virtual machine. Other why script can't change IP address on VM.

Configuring script

Because I didn't wanted to re-test all old networks I needed to generate list of VLAN I want to test.
This can be easily done by exporting list of all VLANs on VMware using following command and removing VLANs what you don't want to test from it.

Get-VirtualPortGroup | Select-Object Name, VLanID | Export-Csv .\VLANs.csv -NoTypeInformation

Because script needs configure IP address to virtual machine and ping to gateway I also added "Subnet" column to CSV file where is subnet number without last number.

Example CSV:
"Name","VLanId","Subnet"
"Frontend","100","192.168.100."
"Backend","200","192.168.200."

Script itselves

Script is located below. I hope that you think that this is useful too.
$vCenter = "vcenter.domain.local"
$ClusterName = "VM cluster"
$TestVMname = "VLAN-Tester"
$VLANsList = Import-Csv ".\VLANs.csv"
$GatewayIP = "1"
$TestVMIP = "253"
$Netmask = "255.255.255.0"
$vCenterCred = Get-Credential -Message "Give vCenter account"
$HostCred = Get-Credential -Message "Give shell account to VMware hosts"
$GuestCred = Get-Credential -Message "Give guest vm credentials"
$LogFile = ".\VLAN_test.log"
$ReportFile = ".\VLAN_test_report.csv"

### 
Connect-VIServer -Server $vCenter -Credential $vCenterCred

$Cluster = Get-Cluster -Name $ClusterName
$vmHosts = $Cluster | Get-VMHost
$TestVM = Get-VM -Name $TestVMname

ForEach ($vmHost in $vmHosts) {
 # Migrate VM to vmHost
 $TestVM | Move-VM -Destination $vmHost
 
 # Find networks which are available for testing on current host
 $vmHostVirtualPortGroups = $vmHost | Get-VirtualPortGroup
 ForEach ($VLAN in $vmHostVirtualPortGroups) {
  ForEach ($VLANtoTest in $VLANsList) {
   If ($VLANtoTest.Name -eq $VLAN.Name) {
    $NetworkAdapters = $TestVM | Get-NetworkAdapter
    Set-NetworkAdapter -NetworkAdapter $NetworkAdapters[0] -Connected:$true -NetworkName $VLAN.Name -Confirm:$False
    
    # Set IP address to guest VM
    $IP = $VLANtoTest.Subnet + $TestVMIP
    $GW =  $VLANtoTest.Subnet + $GatewayIP
    $netsh = "c:\windows\system32\netsh.exe interface ip set address Ethernet static $IP $Netmask 0.0.0.0 1"
    Invoke-VMScript -VM $TestVM -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType bat -ScriptText $netsh
    
    # Wait little bit and try ping to gateway
    Start-Sleep -Seconds 5
    $PingGWResult = Invoke-VMScript -VM $TestVM -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType PowerShell -ScriptText "Test-NetConnection $GW"
    $ParsedPingGWResult = $PingGWResult.ScriptOutput | Select-String True -Quiet
    If ($ParsedPingGWResult -ne $True) { 
     Start-Sleep -Seconds 30
     $PingGWResult = Invoke-VMScript -VM $TestVM -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType PowerShell -ScriptText "Test-NetConnection $GW"
     $ParsedPingGWResult = $PingGWResult.ScriptOutput | Select-String True -Quiet
    }
    
    # Generate report line
    $ReportLine = New-Object -TypeName PSObject -Property @{
     "VMhost" = $vmHost.Name
     "Network" = $VLAN.Name
     "GatewayConnection" = $ParsedPingGWResult
    }
    
    $ReportLine.VMhost+"`t"+$ReportLine.Network+"`t"+$ReportLine.GatewayConnection | Out-File $LogFile -Append
    [array]$Report += $ReportLine
    Remove-Variable ParsedPingGWResult
   }
  }
 }
}
$Report | Export-Csv $ReportFile -NoTypeInformation