Visualizzazione post con etichetta esxi. Mostra tutti i post
Visualizzazione post con etichetta esxi. Mostra tutti i post

mercoledì 8 gennaio 2014

VMware: vFRC Management with GUI PowerCLI

After Automating vFRC deployment with PowerCLI let's have a step further by creating a PowerCLI script that allow administrators to manage vFRC using a Graphical User Interface (GUI).

I created this PowerCLI GUI vFRC management tool as a sample that can be used as a starting point for developing your own GUIs. What's this tool for? It simply gives you the ability to change Cache Size and Block Size of a VM disk on a vFRC enabled host.

PowerCLI GUIs, even if it would be more appropriate saying PowerShell, are very similar to .NET ones. Features, capabilities and results are quite the same since they use the common framework Microsoft provides for building frames and controls such as buttons, textboxes, labels, comboboxes, etc.

Code it's quite commented itself, I divided the script in two macro-areas: the function area, where logic is done, and a "design area" where I essentially defined all elements composing the user interface, their size, their position, what action to trigger in case of user intervention, etc.

I think it is important to spend a few words on elements positioning into the form.

An element position can be defined in several ways. In this script I used both the "compact" and the "extended" synthax.

The extended way to define an element position is:

$Component.Left=10
$Component.Top=20
$Component.Right=30
$Component.Bottom=40


While the compact way:

$Component.Location = New-Object System.Drawing.Size(10,20,30,40)
Numeric values in code snippets above are distances, measured in pixels, that the defined component has from the border of the containing element.
Let's be more clear! If a button is contained in a form and this button has: New-Object System.Drawing.Size(10,20) this indicates that button is located 10px from the left border of the form and 20px from the upper border of the form.
The positioning is relative to the containing element though, because if the same button is contained in a GroupBox which itself is contained in a form, the above 10px from left border and 20px from upper border this time are referred to GroupBox borders and not to the form ones.

Let's now have a look on how vFRC GUI management tool works.

As usual for running PowerCLI script save the code with ".ps1" extension then run it from PowerCLI console.

Here's the code for vFRC GUI management tool, I've also pushed it to GitHub, you can find it here:

vFRC GUI on GitHub

 
##################BEGIN FUNCTIONS


function connectServer{

    try {

    $connect = Connect-VIServer -Server $serverTextBox.Text -User $usernameTextBox.Text -Password $passwordTextBox.Text

    $buttonConnect.Enabled = $false #Disable controls once connected
    $serverTextBox.Enabled = $false
    $usernameTextBox.Enabled = $false
    $passwordTextBox.Enabled = $false
    $buttonDisconnect.Enabled = $true #Enable Disconnect button

    getVmHosts #Populate DropDown list with all hosts connected (if vCenter)

    $HostDropDownBox.Enabled=$true
    
    
    $outputTextBox.text = "`nCurrently connected to $($serverTextBox.Text)" #If connection is successfull let user know it

    }

    catch {
    
    $outputTextBox.text = "`nSomething went wrong!!"
    
    }

}

function disconnectServer{

    try {

    $disconnect = Disconnect-VIServer -Confirm:$false -Force:$true

    $buttonConnect.Enabled = $true #Enable login controls once disconnected
    $serverTextBox.Enabled = $true
    $usernameTextBox.Enabled = $true
    $passwordTextBox.Enabled = $true
    $buttonDisconnect.Enabled = $false #Disable Disconnect button
    
    $HostDropDownBox.Items.Clear() #Remove all items from DropDown boxes
    $HostDropDownBox.Enabled=$false #Disable DropDown boxes since they are empty
    $VmDropDownBox.Items.Clear()
    $VmDropDownBox.Enabled=$false
    $HardDiskDropDownBox.Items.Clear()
    $HardDiskDropDownBox.Enabled=$false
    $cacheBlockSizeKBTextBox.Enabled=$false
    $cacheSizeGBTextBox.Enabled=$false
    
    $outputTextBox.text = "`nSuccessfully disconnected from $($serverTextBox.Text)" #If disconnection is successfull let user know it

    }

    catch {
    
    $outputTextBox.text = "`nSomething went wrong!!"
    
    }

}

function getPoweredOffVms{

    try {
    
    $poweredoffvms = Get-VM | Select-Object Name, VMHost, PowerState, Version | Where-Object {$_.PowerState -eq "PoweredOff" -and $_.Version -eq "v10" -and $_.VMHost -eq $(Get-VMHost | Where-Object {$_.Name -eq $HostDropDownBox.SelectedItem.ToString()})} #Returns only powered Off VMs that are hardware v10 (since older hw versions are not supported)

        foreach ($vm in $poweredoffvms) {
            $VmDropDownBox.Items.Add($vm.Name) #Add VMs to DropDown List
        }

    }

    catch {
    
    $outputTextBox.text = "`nSomething went wrong!!"
    
    }


}

function getVmHosts{

    try {

    $vmhosts = Get-VMHost | Where-Object {$_.PowerState -eq "PoweredOn" -and $_.ConnectionState -eq "Connected"} #Returns only powered On VmHosts

        foreach ($vm in $vmhosts) {
            $HostDropDownBox.Items.Add($vm.Name) #Add Hosts to DropDown List
        }    

    }

    catch {
    
    $outputTextBox.text = "`nSomething went wrong getting VMHosts!!"
    
    }

}

function getVmHostvFlashResource{

    try {
    
    $outputTextBox.text = "`nGetting vFRC configuration for VMHost: $($HostDropDownBox.SelectedItem.ToString())"
    
    $vFlashConfig = Get-VMHostVFlashConfiguration -VMHost $HostDropDownBox.SelectedItem.ToString()
    $capacityGbTextBox.text = $($vFlashConfig.CapacityGB)
    $swapCacheGbTextBox.text = $($vFlashConfig.SwapCacheReservationGB)
    $extentsTextBox.text = $($vFlashConfig.Extents)
    
    getPoweredOffVms #Populate DropDown list with all powered off VMs 

    $VmDropDownBox.Enabled=$true

    }

    catch {
    
    $outputTextBox.text = "`nSomething went wrong getting VMHostsvFlashResource!!"
    
    }

}

function getVmvFlashResource{

    try {
    
    $outputTextBox.text = "`nGetting vFRC configuration for VM: $($VmDropDownBox.SelectedItem.ToString())"
    
    $vFlashConfig = Get-HardDiskVFlashConfiguration -HardDisk $(Get-HardDisk -VM $VmDropDownBox.SelectedItem.ToString() -Name $HardDiskDropDownBox.SelectedItem.ToString())
        
    $cacheBlockSizeKBTextBox.text = $vFlashConfig.CacheBlockSizeKB
    
    $cacheSizeGBTextBox.text = $vFlashConfig.CacheSizeGB        
    
    $buttonSetvFrcVm.Enabled = $true #Enable vFRC related button/texbox
    $cacheBlockSizeKBTextBox.Enabled=$true
    $cacheSizeGBTextBox.Enabled=$true
    
    }

    catch {
    
    $outputTextBox.text = "`nSomething went wrong getting VMvFlashResource!!"
    
    }

}

function setVmvFlashResource{
    try{
    
    $cacheSizeGB = $cacheSizeGBTextBox.Text -as [int] #Convert values to integer
    $capacityGb = $capacityGbTextBox.Text -as [int]
    $swapCacheGb = $swapCacheGbTextBox.Text -as [int]
    
    
    if((($cacheBlockSizeKBTextBox.Text -eq 4) -or ($cacheBlockSizeKBTextBox.Text -eq 8) -or ($cacheBlockSizeKBTextBox.Text -eq 16) -or ($cacheBlockSizeKBTextBox.Text -eq 32) -or ($cacheBlockSizeKBTextBox.Text -eq 64) -or ($cacheBlockSizeKBTextBox.Text -eq 128) -or ($cacheBlockSizeKBTextBox.Text -eq 256) -or ($cacheBlockSizeKBTextBox.Text -eq 512) -or ($cacheBlockSizeKBTextBox.Text -eq 1024))){ #Control if CacheBlockSize value is allowed
 
        if($cacheSizeGB -le ($capacityGb - $swapCacheGb)){ #Control if enough resources are available
        
        Set-HardDiskVFlashConfiguration -VFlashConfiguration (Get-HardDiskVFlashConfiguration -HardDisk $(Get-HardDisk -VM $VmDropDownBox.SelectedItem.ToString() -Name $HardDiskDropDownBox.SelectedItem.ToString())) -CacheSizeGB $cacheSizeGBTextBox.Text -CacheBlockSizeKB $cacheBlockSizeKBTextBox.Text -Confirm:$false
        
        getVmvFlashResource #Display updated values
        
        $outputTextBox.text = "`nvFRC correctly set for VM $($VmDropDownBox.SelectedItem.ToString())"
        
        }
        
        else{
        
        $outputTextBox.text = "`nNot enough resources available!!"
        
        }
        
    }
    else{
    
    $outputTextBox.text = "`nvFRC -Block Size in KB- accepted values are: 4, 8, 16, 32, 64, 128, 256, 512, 1024"
    
    }    
    
    }
    catch{
    
    $outputTextBox.text = "`nSomething went wrong setting VMvFlashResource!!"
    
    }
}

function getDisks{

    try {
    
    $HardDiskDropDownBox.Items.Clear() #Remove all items from DropDown List since it may be dirtied by previous executions
    
    $harddisks = Get-HardDisk -VM $VmDropDownBox.SelectedItem.ToString()
    
        foreach ($disk in $harddisks) {
            $HardDiskDropDownBox.Items.Add($disk.Name) #Add Hosts to DropDown List
        }
        
    $HardDiskDropDownBox.Enabled = $true #Enable dropdownbox
        
    }
    catch{
       $outputTextBox.text = "`nSomething went wrong getting VmHardDisks!!"
    }
}

##################END FUNCTIONS

Import-Module VMware.VimAutomation.Extensions #Import VSAN & vFRC cmdlets

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 

##################Main Form Definition
    
    $main_form = New-Object System.Windows.Forms.Form 
    $main_form.Text = "vFRC GUI" #Form Title
    $main_form.Size = New-Object System.Drawing.Size(500,630) 
    $main_form.StartPosition = "CenterScreen"

    $main_form.KeyPreview = $True
    #$main_form.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
    #{$x=$ServerTextBox.Text;$main_form.Close()}})
    $main_form.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
    {$main_form.Close()}})

##################GroupBox Definition

    $groupBox1 = New-Object System.Windows.Forms.GroupBox
    $groupBox1.Location = New-Object System.Drawing.Size(10,5) 
    $groupBox1.size = New-Object System.Drawing.Size(190,200) #Width, Heigth
    $groupBox1.text = "Connect to vCenter or ESXi host:" 
    $main_form.Controls.Add($groupBox1) 

    $groupBox2 = New-Object System.Windows.Forms.GroupBox
    $groupBox2.Location = New-Object System.Drawing.Size(10,215) 
    $groupBox2.size = New-Object System.Drawing.Size(470,100) #Width, Heigth
    $groupBox2.text = "Hosts Operations:" 
    $main_form.Controls.Add($groupBox2) 

    $groupBox3 = New-Object System.Windows.Forms.GroupBox
    $groupBox3.Location = New-Object System.Drawing.Size(10,325) 
    $groupBox3.size = New-Object System.Drawing.Size(470,100) #Width, Heigth
    $groupBox3.text = "VMs Operations:" 
    $main_form.Controls.Add($groupBox3) 

    $groupBox4 = New-Object System.Windows.Forms.GroupBox
    $groupBox4.Location = New-Object System.Drawing.Size(10,435) 
    $groupBox4.size = New-Object System.Drawing.Size(470,150) #Width, Heigth
    $groupBox4.text = "Output:" 
    $main_form.Controls.Add($groupBox4)
    
    $groupBox5 = New-Object System.Windows.Forms.GroupBox
    $groupBox5.Location = New-Object System.Drawing.Size(210,5) 
    $groupBox5.size = New-Object System.Drawing.Size(270,200) #Width, Heigth
    $groupBox5.text = "Instructions:" 
    $main_form.Controls.Add($groupBox5)  

##################Label Definition

    $Label1 = New-Object System.Windows.Forms.Label
    $Label1.Location = New-Object System.Drawing.Point(10, 20)
    $Label1.Size = New-Object System.Drawing.Size(120, 14)
    $Label1.Text = “IP Address or FQDN:”
    $groupBox1.Controls.Add($Label1) #Member of GroupBox1

    $Label2 = New-Object System.Windows.Forms.Label
    $Label2.Location = New-Object System.Drawing.Point(10, 70)
    $Label2.Size = New-Object System.Drawing.Size(120, 14)
    $Label2.Text = "Username:”
    $groupBox1.Controls.Add($Label2) #Member of GroupBox1

    $Label3 = New-Object System.Windows.Forms.Label
    $Label3.Location = New-Object System.Drawing.Point(10, 120)
    $Label3.Size = New-Object System.Drawing.Size(120, 14)
    $Label3.Text = "Password:”
    $groupBox1.Controls.Add($Label3) #Member of GroupBox1
    
    $Label4 = New-Object System.Windows.Forms.Label
    $Label4.Location = New-Object System.Drawing.Point(10, 15)
    $Label4.Size = New-Object System.Drawing.Size(120, 14)
    $Label4.Text = “Select Host:”
    $groupBox2.Controls.Add($Label4) #Member of GroupBox2
    
    $Label5 = New-Object System.Windows.Forms.Label
    $Label5.Location = New-Object System.Drawing.Point(200, 55)
    $Label5.Size = New-Object System.Drawing.Size(90, 14)
    $Label5.Text = “Capacity in GB:”
    $groupBox2.Controls.Add($Label5) #Member of GroupBox2
    
    $Label6 = New-Object System.Windows.Forms.Label
    $Label6.Location = New-Object System.Drawing.Point(300, 55)
    $Label6.Size = New-Object System.Drawing.Size(160, 14)
    $Label6.Text = “Swap Cache reserved in GB:”
    $groupBox2.Controls.Add($Label6) #Member of GroupBox2
    
    $Label7 = New-Object System.Windows.Forms.Label
    $Label7.Location = New-Object System.Drawing.Point(10, 55)
    $Label7.Size = New-Object System.Drawing.Size(80, 14)
    $Label7.Text = “Extents:”
    $groupBox2.Controls.Add($Label7) #Member of GroupBox2
    
    $Label8 = New-Object System.Windows.Forms.Label
    $Label8.Location = New-Object System.Drawing.Point(10, 15)
    $Label8.Size = New-Object System.Drawing.Size(120, 14)
    $Label8.Text = “Select VM:”
    $groupBox3.Controls.Add($Label8) #Member of GroupBox3
    
    $Label9 = New-Object System.Windows.Forms.Label
    $Label9.Location = New-Object System.Drawing.Point(10, 55)
    $Label9.Size = New-Object System.Drawing.Size(90, 14)
    $Label9.Text = “Block Size in KB:”
    $groupBox3.Controls.Add($Label9) #Member of GroupBox3
    
    $Label10 = New-Object System.Windows.Forms.Label
    $Label10.Location = New-Object System.Drawing.Point(200, 55)
    $Label10.Size = New-Object System.Drawing.Size(160, 14)
    $Label10.Text = “Cache size in GB:”
    $groupBox3.Controls.Add($Label10) #Member of GroupBox3
    
    $Label11 = New-Object System.Windows.Forms.Label
    $Label11.Location = New-Object System.Drawing.Point(200, 15)
    $Label11.Size = New-Object System.Drawing.Size(80, 14)
    $Label11.Text = “Hard Disk:”
    $groupBox3.Controls.Add($Label11) #Member of GroupBox3
    
    $Label12 = New-Object System.Windows.Forms.Label
    $Label12.Location = New-Object System.Drawing.Point(10, 15)
    $Label12.Size = New-Object System.Drawing.Size(250, 180)
    $Label12.Text = “1)Connect to vCenter or ESXi host `r`n`r`n2)Select host and get vFRC configuration `r`n`r`n3)Select VM `r`n`r`n4)Select VM Hard Disk to which enable vFRC `r`n`r`n5)Change -Block Size- and -Cache Size- to desired values `r`n`r`n6)Apply changes pressing -Set vFRC- button `r`n`r`n`Developed by @HostileCoding”
    $groupBox5.Controls.Add($Label12) #Member of GroupBox3

##################Button Definition

    $buttonConnect = New-Object System.Windows.Forms.Button
    $buttonConnect.add_click({connectServer})
    $buttonConnect.Text = "Connect"
    $buttonConnect.Top=170
    $buttonConnect.Left=10
    $groupBox1.Controls.Add($buttonConnect) #Member of GroupBox1

    $buttonDisconnect = New-Object System.Windows.Forms.Button
    $buttonDisconnect.add_click({disconnectServer})
    $buttonDisconnect.Text = "Disconnect"
    $buttonDisconnect.Top=170
    $buttonDisconnect.Left=100
    $buttonDisconnect.Enabled = $false #Disabled by default
    $groupBox1.Controls.Add($buttonDisconnect) #Member of GroupBox1

    $buttonvFrcHost = New-Object System.Windows.Forms.Button
    $buttonvFrcHost.Size = New-Object System.Drawing.Size(260,25) 
    $buttonvFrcHost.add_click({getVmHostvFlashResource})
    $buttonvFrcHost.Text = "Get vFRC configuration for selected Host"
    $buttonvFrcHost.Left=200
    $buttonvFrcHost.Top=25
    $groupBox2.Controls.Add($buttonvFrcHost) #Member of GroupBox2
    
    $buttonGetvFrcVm = New-Object System.Windows.Forms.Button
    $buttonGetvFrcVm.Size = New-Object System.Drawing.Size(125,25) 
    $buttonGetvFrcVm.add_click({getVmvFlashResource})
    $buttonGetvFrcVm.Text = "Get VM vFRC"
    $buttonGetvFrcVm.Left=335
    $buttonGetvFrcVm.Top=25
    $buttonGetvFrcVm.Enabled = $false #Disabled by default
    $groupBox3.Controls.Add($buttonGetvFrcVm) #Member of GroupBox3
    
    $buttonSetvFrcVm = New-Object System.Windows.Forms.Button
    $buttonSetvFrcVm.Size = New-Object System.Drawing.Size(125,25) 
    $buttonSetvFrcVm.add_click({setVmvFlashResource})
    $buttonSetvFrcVm.Text = "Set VM vFRC"
    $buttonSetvFrcVm.Left=335
    $buttonSetvFrcVm.Top=65
    $buttonSetvFrcVm.Enabled = $false #Disabled by default
    $groupBox3.Controls.Add($buttonSetvFrcVm) #Member of GroupBox3

##################TextBox Definition

    $serverTextBox = New-Object System.Windows.Forms.TextBox 
    $serverTextBox.Location = New-Object System.Drawing.Size(10,40) #Left, Top, Right, Bottom
    $serverTextBox.Size = New-Object System.Drawing.Size(165,20) 
    $groupBox1.Controls.Add($serverTextBox) #Member of GroupBox1

    $usernameTextBox = New-Object System.Windows.Forms.TextBox 
    $usernameTextBox.Location = New-Object System.Drawing.Size(10,90)
    $usernameTextBox.Size = New-Object System.Drawing.Size(165,20) 
    $groupBox1.Controls.Add($usernameTextBox) #Member of GroupBox1

    $passwordTextBox = New-Object System.Windows.Forms.MaskedTextBox #Password TextBox
    $passwordTextBox.PasswordChar = '*'
    $passwordTextBox.Location = New-Object System.Drawing.Size(10,140)
    $passwordTextBox.Size = New-Object System.Drawing.Size(165,20)
    $groupBox1.Controls.Add($passwordTextBox) #Member of GroupBox1
    
    $capacityGbTextBox = New-Object System.Windows.Forms.TextBox
    $capacityGbTextBox.Location = New-Object System.Drawing.Size(200,70)
    $capacityGbTextBox.Size = New-Object System.Drawing.Size(90,20)
    $capacityGbTextBox.Enabled=$false 
    $groupBox2.Controls.Add($capacityGbTextBox) #Member of GroupBox2
    
    $swapCacheGbTextBox = New-Object System.Windows.Forms.TextBox
    $swapCacheGbTextBox.Location = New-Object System.Drawing.Size(300,70)
    $swapCacheGbTextBox.Size = New-Object System.Drawing.Size(160,20)
    $swapCacheGbTextBox.Enabled=$false 
    $groupBox2.Controls.Add($swapCacheGbTextBox) #Member of GroupBox2
    
    $extentsTextBox = New-Object System.Windows.Forms.TextBox
    $extentsTextBox.Location = New-Object System.Drawing.Size(10,70)
    $extentsTextBox.Size = New-Object System.Drawing.Size(180,20)
    $extentsTextBox.Enabled=$false 
    $groupBox2.Controls.Add($extentsTextBox) #Member of GroupBox2
    
    $cacheBlockSizeKBTextBox = New-Object System.Windows.Forms.TextBox
    $cacheBlockSizeKBTextBox.Location = New-Object System.Drawing.Size(10,70)
    $cacheBlockSizeKBTextBox.Size = New-Object System.Drawing.Size(90,20)
    $cacheBlockSizeKBTextBox.Enabled=$false 
    $groupBox3.Controls.Add($cacheBlockSizeKBTextBox) #Member of GroupBox3
    
    $cacheSizeGBTextBox = New-Object System.Windows.Forms.TextBox
    $cacheSizeGBTextBox.Location = New-Object System.Drawing.Size(200,70)
    $cacheSizeGBTextBox.Size = New-Object System.Drawing.Size(125,20)
    $cacheSizeGBTextBox.Enabled=$false 
    $groupBox3.Controls.Add($cacheSizeGBTextBox) #Member of GroupBox3

    $outputTextBox = New-Object System.Windows.Forms.TextBox 
    $outputTextBox.Location = New-Object System.Drawing.Size(10,20)
    $outputTextBox.Size = New-Object System.Drawing.Size(450,120)
    $outputTextBox.MultiLine = $True 
    $outputTextBox.ReadOnly = $True
    $outputTextBox.ScrollBars = "Vertical"  
    $groupBox4.Controls.Add($outputTextBox) #Member of groupBox4

##################DropDownBox Definition

    $VmDropDownBox = New-Object System.Windows.Forms.ComboBox
    $VmDropDownBox.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList #Disable user input in ComboBox
    $VmDropDownBox.Location = New-Object System.Drawing.Size(10,30) 
    $VmDropDownBox.Size = New-Object System.Drawing.Size(180,20) 
    $VmDropDownBox.DropDownHeight = 200
    $VmDropDownBox.Enabled=$false 
    $groupBox3.Controls.Add($VmDropDownBox)
    
    $handler_VmDropDownBox_SelectedIndexChanged={ #DropDownBox SelectedIndexChanged Handler
        try{
            if ($VmDropDownBox.Text.Length -gt 0) {
               getDisks 
            }
        }catch{
        }
    }
    $VmDropDownBox.add_SelectedIndexChanged($handler_VmDropDownBox_SelectedIndexChanged)

    $HostDropDownBox = New-Object System.Windows.Forms.ComboBox
    $HostDropDownBox.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList #Disable user input in ComboBox
    $HostDropDownBox.Location = New-Object System.Drawing.Size(10,30) 
    $HostDropDownBox.Size = New-Object System.Drawing.Size(180,20) 
    $HostDropDownBox.DropDownHeight = 200
    $HostDropDownBox.Enabled=$false 
    $groupBox2.Controls.Add($HostDropDownBox)
    
    $HardDiskDropDownBox = New-Object System.Windows.Forms.ComboBox
    $HardDiskDropDownBox.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList #Disable user input in ComboBox
    $HardDiskDropDownBox.Location = New-Object System.Drawing.Size(200,30) 
    $HardDiskDropDownBox.Size = New-Object System.Drawing.Size(125,20) 
    $HardDiskDropDownBox.DropDownHeight = 200
    $HardDiskDropDownBox.Enabled=$false 
    $groupBox3.Controls.Add($HardDiskDropDownBox)
    
    $handler_HardDiskDropDownBox_SelectedIndexChanged={ #DropDownBox SelectedIndexChanged Handler
        try{
            if ($HardDiskDropDownBox.Text.Length -gt 0) {
               $buttonGetvFrcVm.Enabled = $true #Enable button
            }
        }catch{
        }
    }
    $HardDiskDropDownBox.add_SelectedIndexChanged($handler_HardDiskDropDownBox_SelectedIndexChanged)

##################Show Form

    $main_form.Add_Shown({$main_form.Activate()})
    [void] $main_form.ShowDialog()

Once you launch it main form will pop-out:



Enter credentials of your vCenter Server or ESXi host and connect to it. If connected to a vCenter Server all powered on hosts connected to vCenter itself will be added to dropdown box. Select a vFRC-capable host and click Get vFRC configuration for selected Host.



Any powered off virtual machine with hardware version 10 (ESXi 5.5 VMs) residing on selected host will be listed. Select intended VM and the VM's hard disk on which you need to enable or change vFRC settings.



Press Get VM vFRC button to retrieve current vFRC informations for selected VM. Here you can change both Block Size in KB and Cache Size in GB for selected hard disk.



Once done press Set VM vFRC to apply changes.



When setting vFRC the tool checks whether Block Size is permitted (either 4,8,16,32,64,128,256,512 or 1024 KB) and if enough Cache Size is available (i.e. you cannot assign more cache that the available one).

That's all!!

lunedì 30 dicembre 2013

VMware: Shrink VMDKs by removing zeroed blocks

VMDK size is one of the main aspects to consider for administrators when deploying new VMs since it could introduce several hazards in storage space usage. By introducing thin provisioning VMware mitigated space exhaustion issues due to the fact that this provisioning mechanism allocates only blocks that are effectively used by the operating system residing on VMDK itself preventing in this way storage to be pre-emptively filled by overzealous admins planning for big virtual machine disks.



But what about shrinking size of those VMDKs that were already provisioned using thick provisioning? They usually consume a lot of storage space and not always their thick allocation is justified. Usually thick eager is the allocation mechanism choosen for I/O intensive virtual machines due to the fact that by zeroing blocks during VMDK creation, and not when operating system issues the first write on a block, introduce a little performance increase (just on first write though).



As most of you certainly know thick lazy zeroed is another allocation mechanism that pre-emptively reserve storage space required by the virtual machine VMDK. Difference between thick lazy and thick eager is that the former reserve whole VMDK size on storage without zeroing blocks, which will be zeroed at first write.



Another crucial aspect to consider is that ESXi is not aware of space freed by the upper operating system due to file deletion. This space cannot be reclaimed by underlying hypervisor and because of this VMDK cannot be "downsized automatically".

Let's clarify this with an example: suppose that we have a virtual machine whose VMDK is thin provisioned.
Operating system is 5GB in size. We install 2GB of additional software. Operating system will report a space consumption of 5+2=7GB. VMDK will be the same (5+2=7GB) size.
We later decide that additional software just installed is useless so we delete/uninstall it. Operating system will report a space consumption of 7-2=5GB. VMDK will be unchanged with a size of 7GB.
This is because ESXi is not aware that space is currently unused by the guest OS and cannot reclaim it.

By shrinking VMDKs this space can be reclaimed. A prior important condition for unused space reclamation is that operating system zeroes currently unused blocks, this means that for shrink to be the most effective guest operating system should fill all currently unused space with zeroes. This can be done in Windows guests by using softwares like Hard Disk Scrubber or SDelete and in Linux guest with dd if=/dev/zero of=/<destination_path>/placeholderfile bs=8192 && rm -rf /<destination_path>/placeholderfile command.

Since unused space is reclaimed after a shrink operation VMDK will be converted from thin, eager zeroed, lazy zeroed to a thin provisioned VMDK.

Let's now delve into how shrinking is performed. A common method is using Storage vMotion. When storage vMotioning a virtual machine resulting disk format can be choosen. Another method is using VMware Converter by converting guest OS like a classic P2V conversion. Pros of those two methods is that they can be performed while VM is powered on.

A third method to shrink a VMDK is by Using vmkfstools.

This method requires the VM to be powered off during shrinking process and you to connect to ESXi host using SSH to run some commands.

For article purpouse I created a VM with a thick provisioned VMDK. Following image show you space usage reported at Linux guest level:



Guest OS reports a total space of 60GB of which 2.3 GB are currently used.

Since it's thick provisioned VMDK is also 60GB in size



To shrink VMDK using vmkfstools the following command is used:

vmkfstools --punchzero <path_to_VMDK_to_shrink>.vmdk



--punchzero option is quite self-explicative, it basically removes all zeroed blocks in a VMDK by freeing up space.

As you can expect, based on previous explanation, the resultant VMDK will be shrinked down to the size of effective guest OS space usage.



That's all!!

venerdì 20 dicembre 2013

VMware: ESXi Unattended Scripted Installation

ESXi installation is an easy job for one or two hosts, but imagine to repeat such installation for 40/50 hosts: it would take all day. To prevent such time-consuming situation VMware allow administrators to perform unattended ESXi installation.

Unattended installation is performed using a kickstart script that will be provided during boot. Kickstart script contains all parameters needed by ESXi to automatically complete installation process without further human intervention.

At first I suggest you to have a look at official documentation regarding ESXi 5.5 scripted installation:

Deploying ESXi 5.x using the Scripted Install feature (2004582)
About Installation and Upgrade Scripts

Here's my kickstart file. I named it ks.cfg. You can use it as a base template and edit it according to your requirements.

 #  
 # Sample scripted installation file  
 #  
 # Accept EULA  
 vmaccepteula  
 # Set root password  
 rootpw mypassword  
 #Install on local disk overwriting any existing VMFS datastore  
 install --firstdisk --overwritevmfs  
 # Network configuration  
 network --bootproto=static --device=vmnic0 --ip=192.168.116.228 --netmask=255.255.255.0 --gateway=192.168.116.2 --nameserver=192.168.116.2 --hostname=esx1.testdomain.local --vlanid=100 --addvmportgroup=1  
 #Reboot after installation completed  
 reboot  

As you can see the code is already commented but let me spend a few words on:

install --firstdisk --overwritevmfs

This is used to install ESXi on first available local disk overwriting any existent VMFS partition.

While:

network --bootproto=static --device=vmnic0 --ip=192.168.116.228 --netmask=255.255.255.0 --gateway=192.168.116.2 --nameserver=192.168.116.2 --hostname=esx1.testdomain.local --vlanid=100 --addvmportgroup=1

Specifies that vmnic0 will be used for management and assigns to it IP address, netmask, gateway and vlan id.

--addvmportgroup=1 creates the VM Network portgroup to which virtual machines will be connected by default.

Let me now explain how to use this kickstart file during installation.

Boot your host with ESXi installation media attached (I use CDROM). During boot press SHIFT + O to Edit boot options. Weasel prompt will appear.

> runweasel

Basic command to use a network accessible (HTTP, HTTPS, NFS, FTP) kickstart file is:

> runweasel ks=<kickstart_file_location> ip=<ip_address_to_use_to_retrieve_ks> netmask=<netmask_to_use_to_retrieve_ks> gateway=<gateway_to_use_to_retrieve_ks> vlanid=<vlan_to_use_to_retrieve_ks>

kickstart script s location can be not just an HTTP(S) server. Even FTP, NFS, cdrom or usb are accepted in the form of:

ks=protocol://<serverpath>
ks=cdrom:/<path\>
ks=file://<path>
ks=usb:</path>


In this example I retrieve kickstart file from a webserver (an HTTP location) and assign 192.168.116.222 as IP address for host during installation process.

> runweasel ks=http://192.168.116.1:8080/ks.cfg ip=192.168.116.222 netmask=255.255.255.0 gateway=192.168.116.2




Unattended installation will begin by parsing kickstart file.



When installation is completed host will reboot and ESXi will be ready to be used.



That's all!!

sabato 21 settembre 2013

VMware: IP-Hash LB in IP Storage

In this post I would like to explain IP-Hash Load Balancing principles used for connecting VMware hosts to IP storage, like NFS, for better understanding how traffic balancement across various NICs occurs.

As reported in previous VMware: Uplink used by a VM in a LB NIC Teaming article Load Balancing policies are effective between vmnics and physical storage and all pSwitches inbetween.


Load Balancing does not occur between VMs, VMkernels and Port Groups in vSwitches.

IP-Hash Load Balancing is the LB technique that could potentially achieve the highest degree of efficiency since it uses different vmnics based on an algorithm that considers the destination IP address the packet has to be sent to and, unlike Route Based on originating virtual port ID it doesen't use a Round Robin vmnic assignation methodology.

Although IP-Hash Load Balancing lead to a better traffic load balancing it also brings the most complex set-up because it also requires particular configuration changes in all pSwitches packets will traverse to reach IP storage.

In pSwitches inbetween your VMware hosts and IP storage you will need to enable IEEE 802.3ad LACP, or Etherchannel if you deal with Cisco equipment, in order to benefit IP-Hash Load Balancing. LACP basically aggregates from 2 up to 8 ethernet channels providing a link with more aggregate bandwidth and resiliency.

Here's a simple connection schema, please bear in mind that in a real case scenario using a single pSwitch introduces a single point of failure in your infrastructure.


You should also consider VLAN implementation in order to isolate storage traffic. This, as you certainly know, is a thumb rule not just for storage traffic such as NFS or iSCSI but even for management traffic, vMotion traffic, FT traffic, etc.

Since my post is VMware related I will assume you have already configured LACP properly in your physical network. For more info on LACP setup please have a look at 1004048 KB.

Let's start by setting up our virtual networking. For sake of simplicity we will use just two vmnics.
We create a new vSwitch and a VMkernel for IP Storage (NFS in my case) assigning these two vmnics to it.


Please be sure that all vmnics are set as Active and that there are no vmnics set as Standby or Unused. IP-Hash Load Balancing must be set at vSwitch level and not overridden at VMkernel/PortGroup level.


IP-Hash Load Balancing algorithm chooses which vmnic utilize for any IP connection based on destination IP address upon the following equation:

vmnic used = [HEX(IP VMkernel) xor HEX(IP Storage)] mod (Number of vmnics)

where:

HEX indicates that the IP address has been converted in hexadecimal format. This is done octet by octet which means that for example 10.11.12.13 IP address in HEX base is 0A.0B.0C.0D that will be represented as 0x0A0B0C0D.

IP VMkernel is the IP address assigned to the VMkernel used for IP Storage

IP Storage is the IP address assigned to the NFS storage

xor is the exclusive or operand

mod is modulo operation

Now that we know how vmnic are choosen for data transfer let's examine how we can wisely assign IP addresses to our IP storage systems.

In this example I will use a NFS server with two NICs (no vIP). I've already assigned IP 192.168.116.10 to VMkernel responsible for carrying IP storage data.

1) Bad IP addresses choice


VMkernel = 192.168.116.10
NFS 1 = 192.168.116.50
NFS 2 = 192.168.116.60


Let's do some math:

vmnic used for NFS1 = [HEX(192.168.116.10) xor HEX(192.168.116.50)] mod (2)

= [0xC0A8740A xor 0xC0A87432] mod (2)

= [38] mod (2)

= 0 -> vmnic0 will be used


vmnic used for NFS2 = [HEX(192.168.116.10) xor HEX(192.168.116.60)] mod (2)

= [0xC0A8740A xor 0xC0A8743C] mod (2)

= [36] mod (2)

= 0 -> vmnic0 will be used

As you can see assigning these two IP addresses to NFS storage was a bad choice becase communications toward both NFS1 and NFS2 will utilize vmnic0 leaving vmnic1 unused.

2) Good IP addresses choice


VMkernel = 192.168.116.10
NFS 1 = 192.168.116.50
NFS 2 = 192.168.116.51


Let's do some math again:

vmnic used for NFS1 = [HEX(192.168.116.10) xor HEX(192.168.116.50)] mod (2)

= [0xC0A8740A xor 0xC0A87432] mod (2)

= [38] mod (2)

= 0 -> vmnic0 will be used


vmnic used for NFS2 = [HEX(192.168.116.10) xor HEX(192.168.116.51)] mod (2)

= [0xC0A8740A xor 0xC0A87433] mod (2)

= [39] mod (2)

= 1 -> vmnic1 will be used

These was a wise choice since communications with NFS1 will use vmnic0 and communications with NFS2 will use vmnic1 achieving traffic balance and both uplinks utilization.

Some useful links:

Best Practices for running VMware vSphere on Network Attached Storage

Sample configuration of EtherChannel / Link Aggregation Control Protocol (LACP) with ESXi/ESX and Cisco/HP switches

That's all!!

lunedì 9 settembre 2013

VMware: Uplink used by a VM in a LB NIC Teaming

In this post I will explain how to show the uplink used by a VM in a vSwitch with NIC Teaming Load Balancing.

Since we all put our uplinks in a Load Balancing NIC Teaming sometimes it could be useful for troubleshooting purpouses to see what's the specific physical uplink used by that particular VM to access the network.

To explain this I will use a real case scenario that happened to me today.

A customer reported that after vMotioning a VM from one physical host to another this VM was unable to reach a specific IP Address in his network (a router, fyi).

I checked the basic networking settings from vSphere Client like vSwitch configuration and if every vmnic reported network activity (i.e. plugged cable) and everything was fine.

vSwitch configuration was similar to this:



vm4 was the VM reporting issues.

Analyzing vSwitch0 settings this was the result:



As you can see all vmnics (vmnic0, vmnic1, vmnic2, vmnic3) are set as Active and Route Based on originating virtual port ID was selected as Load Balancing method.

Next step was to take a look at physical networking. Customer has a blade enclosure with 3 hosts, each blade (i.e. ESXi physical host) with  4 NIC: vmnic0, vmnic1, vmnic2 and vmnic3.

Each NIC was connected to a different physical switch to achieve path realiability and every switch is connected to the one 'core switch' (second switch from the top in picture below) EXCEPT switch 4...and here all yours bells and whistles will ring.



To make this story short, as most of you have already understood, this was the flaw in this configuration. By per se it's not an issue having a switch not connected to other switches but in this scenario it's a fault because it's used in conjunction with Route Based on originating virtual port ID Load Balancing.

Route Based on originating virtual port ID it's based on a Round Robin uplink assignation. This means that every VM powered on recieve in sequence the next available uplink (vmnic) in the vSwitch.

Take a look at this picture for better understandment:



VM power-on sequence in this case was:

POWER-ON SEQ.  UPLINK ASSIGNED
vm1            vmnic0
vm2            vmnic1
vm3            vmnic2
vm4            vmnic3
vm5            vmnic0


...and so on...let's pretend for example a new vm6 will be powered on this VM will use vmnic1. If vm3  and vm6 are powered off and vm6 is powered on back again it will use vmnic2 as uplink. Pretty simple, right?

In my case vm4 reported network issues reaching the router IP Address (the rightmost grey block on the picture above) because after vMotion from one host to another vm4 ended on a host's vSwitch which assigned it to vmnic3 which is connected to an isolated physical switch. This is easily solvable either by adding the missing intra-switch link or by removing vmnic3 from the Load Balancing active adapters.

After this theorethical prologue let's dive a bit into practice by explaining how it's possible to display which uplink (in a LB NIC Team) is used by a VM.

Let's login into our ESXi host.

To retrieve port informations for a particular VM we need to use the following command:

~ # esxcli network vm port list -w <World_ID>

Where <World_ID> is the World ID of our VM. This World ID uniquely identificates a VM in a host and changes every time a VM is vMotioned and a power status change occurs (i.e. vm is powered off and back on again).

To display World ID for our VMs we need to execute following command. Informations about every VM running in the host are retrieved. To keep things clean I only show you the output of vm4.

~ # esxcli vm process list

vm4
   World ID: 3307679
   Process ID: 0
   VMX Cartel ID: 3307678
   UUID: 42 19 4a 84 a3 52 c7 ca-d9 28 93 bf 20 6c 2d bc
   Display Name: vm4
   Config File: /vmfs/volumes/51dc35ee-c4b96dc0-1c1c-b4b53f5110c0/vm4/vm4.vmx



World ID: 3307679 if the value of interest.

If we run the command above this time specifying World ID we get:

~ # esxcli network vm port list -w 3307679
   Port ID: 33554444
   vSwitch: vSwitch0
   Portgroup: VM Network
   DVPort ID:
   MAC Address: 00:50:56:99:45:3b
   IP Address: 0.0.0.0
   Team Uplink: vmnic3
   Uplink Port ID: 33554438
   Active Filters:


As you can see Team Uplink: vmnic3 indicates that vmnic3 is used by this VM.

That's all!