The power of PowerCLI – Labautomation

Har du någonsin behövt skapa identiska labbmiljöer till flera deltagare, i till exempel utbildningssyfte eller för en workshop? Då vet du att det inte bara är att högerklicka på en template och välja deploy from template. Det behövs kanske flera olika templates som ska rullas ut, separata virtuella switchar och portgrupper behöver skapas för varje deltagare osv. Det blir fort en väldigt stor administrativ belastning. Det finns lite olika sätta att lösa problemet, exempelvis via vApps i vCloud Director.

Men om du nu inte har vCloud Director i din miljö, du kanske bara har en eller två hostar i miljön. Vad göra? Då kommer VMware PowerCLI till din räddning! PowerCLI är VMwares utökning av Microsoft Powershell som låter dig scripta i stort sätt allt du kan tänkas vilja göra. Du behöver en windows maskin samt hämta PowerCLI som finns här.

I mitt dagliga jobb behöver jag ofta sätta upp färdiga miljöer som innehåller mellan 5-10 virtuella maskiner som jag har tillgängliga som templates. För att enkelt kunna skapa unika labbmiljöer för flera personer/deltagare så har jag skapat ett skript som automatiserar utrullningen åt mig. Det enda jag behöver göra är att ange hur många kit jag vill skapa samt var jag vill skapa dom (på vilken host och vilket datastore). Sen har jag lagt till möjligheten att ange vilket ”startnummer” jag vill använda. Exempelvis om jag vill skapa 10 kit men det datastore jag angett finns det bara plats för 5 stycken kit. Då kan jag dela upp 5 kit på datastore1 med startummer 1 därefter skapar jag ytterligare 5 kit på datastore 2 fast med startnummer 6. Då har jag 10 kit med en logisk namnstandard – från 1 till 10.

En kort förklaring vad scriptet gör (förutom att skapa en meny där man kan välja lite olika alternativ som att skapa vApps, starta / stänga vApps osv):
1. Skapa en vApp för varje deltagare
2. Rulla ut VMs från templates till vAppen
3. Skapa isolerat nätverk kopplat till varje deltagare
4. Ändra säkerhetsnivån på utvalda portgrupper till promiscous mode eftersom det är nested ESXi
5. Koppla de virtuella maskinerna i en vApp till studentens egna nätverk
6. Ändra så att de virtuella maskinerna stängs ner gracefully när vAppen stängs (från Power off till Guest Shutdown)

När kiten är skapade kan jag via skriptet starta samtliga kit eller stänga ner dom om jag vill det. I mitt exempel har jag även en VM som är tillgänglig från klientnätet för att ge deltagarna tillgång till den skyddade labbmiljön, en Control Center. Jag kan via skriptet hämta in samtliga IP adresser till dessa Control Center maskinerna så jag kan dela ut ett kit till varje deltagare som därefter loggar in på maskinen via RDP och kommer åt resten av labbkitet.

Det är ett basic skript utan felhantering och så vidare men använd det om du vill men använd det på egen risk och endast i en skydad miljö.


# ===============================================================
#     NAME: VMware_lab_setup.ps1
#     AUTHOR: Niclas Borgström, Viridis IT
#     DATE: 2014-03-12 #
#     VERSION: 0.9
# ===============================================================

Clear-Host
# Explain what the script does
Write-Host "This script will allow for set up and configure"
Write-Host "a lab environment for VMware vSphere 5.5 using"
Write-Host "existing templates."

# Ask for the Host name or IP
$VCENTER = Read-Host "Enter vCenter Server Name or IP"
Connect-VIServer -server $VCENTER

Clear-Host
# Setup Our MENU
do {
     # Select environment MENU
     Write-Host "*** Config Menu for VMW55 ***"
     Write-Host "-----------------------------"
     # Print out the MENU
     Write-Host "What task would you like to perform?"
     Write-Host " "
     Write-Host " 1. Set up a new lab environment"
     Write-Host " 2. Power on vApps"
     Write-Host " 3. Get IP addresses of Desktop and ControlCenter VMs"
     Write-Host " 4. Get IP addresses of all VMs in vApps"
     Write-Host " 5. Power off (gracefully) vApps"
     Write-Host " "
     Write-Host " 0. Quit"
     Write-Host " "
     $response = Read-Host "Select 1-5"
     Write-Host " "

     switch ($response)
{
1 {
    Clear-Host

    # Show a welcome message
    Write-Host "VMware vSphere 5.5 lab environment set up v1.03"
    Write-Host "-----------------------------------------------"
    Write-Host " "

    # Select amount of Labkits to set up and what number the studentkit wil be assigned
    [int]$labkit = Read-Host "How many student kits will be needed? (1-12)"
    [int]$start = Read-Host "What startnumber would you like to use? (1-100)"
    [int]$end = $start + $labkit -1

    # Select host to install Lab kits on
    Write-Host " "
    Write-Host "Choose one of the hosts below from the Rescoures_Cluster:"
    Get-Cluster "Resources_Cluster" | Get-VMhost | Select Name
    $labhost = Read-Host "Type FQDN/IP address of host do you want to use"
    Get-VMhost $labhost | select Name

    # Select what datastore to use with enough capacity for thin vmdk and vswp
    Get-VMhost $labhost | Get-Datastore | Where-Object {$_.freespaceGB -gt ($labkit*(40+30))} | Select Name
    $datastore = Read-Host "What datastore would you like to use? (only showing datastores with enough free space)"
    Get-VMhost $labhost | Get-Datastore $datastore | Select Name
    Write-Host "Datastore" $datastore "will be used to install the vApp(s)"
    Clear-Host

    # Print summary
    Write-Host "Summary of lab environment set up:"
    Write-Host "---------------------------------"
    Write-Host "Lab kits to set up: " $labkit
    Write-Host "First kit name:     " "VMW55_Student$start"
    Write-Host "Last kit name:      " "VMW55_Student$end"
    Write-Host "Startnumber:        " $start
    Write-Host "Host:               " $labhost
    Write-Host "Datastore:          " $datastore
    Write-Host "                    "
    Write-Host "Required resources: "
    Write-Host "RAM:                " ($labkit*30) "GB"
    Write-Host "CPU:                " ($labkit*11) "vCPU"
    Write-Host "Storage (intial):   " ($labkit*40) "GB"
    Write-Host "Storage (max):      " ($labkit*316) "GB"
    $choice = @()
    $choice = Read-Host "Is this correct (Y/N)?"
    if ($choice -eq "y")
    {
        # Start setting up the lab environment for each student
        $start..$end | Foreach {
        Write-Host "Setting up environment for student" $start "..."
        $studentid = "VMW55_Student$start"

        # Create a vSwitch for each student
        Write-Host "Creating Network environment..."
        New-VirtualSwitch -VMHost $labhost -Name $studentid

        # Create Portgroups for 3 use cases
        New-VirtualPortGroup -Name $studentid"_Production" -VirtualSwitch $studentid
        New-VirtualPortGroup -Name $studentid"_Management" -VirtualSwitch $studentid
        New-VirtualPortGroup -Name $studentid"_vMotion" -VirtualSwitch $studentid

        # Set the Management Portgroup to allow PromiscousMode
        $netsys = Get-View (Get-VMHost $labhost | Get-View).configmanager.networksystem
        $portgroupspec = New-Object VMWare.Vim.HostPortGroupSpec
        $portgroupspec.vswitchname = $studentid
        $portgroupname = $studentid
        $portgroupname = ($portgroupname += "_Management")
        $portgroupspec.Name = $portgroupname
        $portgroupspec.policy = New-object vmware.vim.HostNetworkPolicy
        $portgroupspec.policy.Security = New-object vmware.vim.HostNetworkSecurityPolicy
        $portgroupspec.policy.Security.AllowPromiscuous = $true
        $netsys.UpdatePortGroup($portgroupname,$PortGroupSpec)

        # Create a vApp for each student
        Write-Host "Creating vApp..."
        New-VApp -Name $studentid -Location "Resources_Cluster"

        # Start deploying virtual machines
        Write-Host "Deploying virtual machines..."
        New-VM -VMHost $labhost -Name ControlCenter -Template VMW55_ControlCenter -Datastore $datastore -DiskStorageFormat Thin -ResourcePool $studentid
        New-VM -VMHost $labhost -Name iscsi -Template VMW55_iscsi -Datastore $datastore -DiskStorageFormat Thin -ResourcePool $studentid
        New-VM -VMHost $labhost -Name nfs -Template VMW55_nfs -Datastore $datastore -DiskStorageFormat Thin -ResourcePool $studentid
        New-VM -VMHost $labhost -Name esxi01 -Template VMW55_esxi01 -Datastore $datastore -DiskStorageFormat Thin -ResourcePool $studentid
        New-VM -VMHost $labhost -Name esxi02 -Template VMW55_esxi02 -Datastore $datastore -DiskStorageFormat Thin -ResourcePool $studentid
        New-VM -VMHost $labhost -Name vcva01 -Template VMW55_vcva01 -Datastore $datastore -DiskStorageFormat Thin -ResourcePool $studentid
        New-VM -VMHost $labhost -Name Desktop01 -Template VMW55_Desktop01 -Datastore $datastore -DiskStorageFormat Thin -ResourcePool $studentid

        # Change networking to dedicated portgroups
        Write-Host "Change portgroups on all virtual machines in the vApp..."
        Get-VApp $studentid | Get-VM | Get-NetworkAdapter | Where {$_.NetworkName -eq "Production_template" } | Set-NetworkAdapter -NetworkName $studentid"_Production" -Confirm:$false
        Get-VApp $studentid | Get-VM | Get-NetworkAdapter | Where {$_.NetworkName -eq "vMotion_template" } | Set-NetworkAdapter -NetworkName $studentid"_vMotion" -Confirm:$false
        Get-VApp $studentid | Get-VM | Get-NetworkAdapter | Where {$_.NetworkName -eq "Management_template" } | Set-NetworkAdapter -NetworkName $studentid"_Management" -Confirm:$false

        # Change StopAction for all VMs in the vApp
        Write-Host "Change settings for vApp" $studentid "..."
        $AppView = Get-VApp $studentid | Get-View
        Foreach ($Entity in $AppView.VAppconfig.EntityConfig)
            {
            If ($Entity.Stop.Action -ne "guestShutdown")
                {
                $VAppConfigSpec = New-Object VMware.Vim.VAppConfigSpec
                $EntityConfig = New-Object VMware.Vim.VAppEntityConfigInfo
                $EntityConfig.Key = (Get-View $Entity.Key).MoRef
                #$EntityConfig.startDelay = 120
                $EntityConfig.waitingForGuest = $true
                #$EntityConfig.stopDelay = 120
                $EntityConfig.StopAction = "guestShutdown"
                $VAppConfigSpec.EntityConfig = $EntityConfig

                $AppView.UpdateVAppConfig($VAppConfigSpec)
                }
            }
    [int]$start = $start + 1
    }
    }
    else
    {
        Break
    }
    Clear-Host
    break;
}
2 {
    Clear-Host

    # Power on all VMs in vApp
    # To power on all lab kits just type the first letters, i.e to power on
    # all lab kits called VMW55_student1, VMW55_student2, and so on you only
    # need to typ "VMW55"
    Write-Host "Power on all vApps for VMW55 lab"
    Write-Host "--------------------------------"
    Write-Host " "
    Get-vApp | Select-Object -property Name
    $vappinput = Read-Host "What lab should power on? (case sensitive)"
    Get-VApp | Where {$_.Name -like "$vappinput*"} | Start-VApp
    Clear-Host
    break;
    }
3 {
    Clear-Host

    # List Ip address of all Desktop01 & ControlCenter VMs in selected vApps
    Write-Host "IP address of all Desktop01 & ControlCenter VMs for VMW55 class"
    Write-Host "-------------------------------------------------------------------"
    Write-Host " "
    Get-vApp | Select-Object -property Name
    $vappinput = Read-Host "What Class should we list? (case sensitive)"
    Write-Host "Saving result to file 'IPAddress_of_Desktop.txt'"
    $FencedVMIP = Get-VApp | Where {$_.Name -like "$vappinput*"} | Get-VM | Where {$_.Name -like "Desktop*" -or $_.Name -eq "ControlCenter"} | Select {$_.VApp},Name,{$_.Guest.IpAddress[0]}
    $FencedVMIP | Out-File C:\PS_Scripts\VMware\VMW55\IPAddress_Of_Desktop.txt
    Clear-Host
    break;
    }
4 {
    Clear-Host

    # List Ip address of all VMs in selected vApps
    Write-Host "IP address of all VMs for VMW55 lab"
    Write-Host "-------------------------------------"
    Write-Host " "
    Get-vApp | Select-Object -property Name
    $vappinput = Read-Host "What Class should we list? (case sensitive)"
    Write-Host "Saving result to file 'IPAddress_All_VMs.txt'"
    $AllVMIP = Get-VApp | Where {$_.Name -like "$vappinput*"} | Get-VM | Select Name,{$_.VApp},{$_.Guest.IpAddress}
    $AllVMIP | Out-File C:\PS_Scripts\VMware\VMW55\IPAddress_All_VMs.txt

    Clear-Host
    break;
    }
5 {
    Clear-Host

    # Shutdown all VMs in the selected vApps
    Write-Host "Power off all vApps for VMW55 class"
    Write-Host "-----------------------------------"
    Write-Host " "
    Get-vApp | Select-Object -property Name

$vappinput = Read-Host "What Class should power off? (case sensitive)"
    $choice = Read-Host "Are you sure you want to stop all vApps (Y/N)?"
    if ($choice -eq "y")
        {
        Get-VApp | Where {$_.Name -like "$vappinput*"} | Stop-VApp
        }
    else
        {
        Break
        }

Clear-Host
    break;
    }

0 {
    "** Exiting Script **";
    Write-Host "Quit";
    Disconnect-viserver -server $VCENTER -confirm:$false

    break;
    }
default {
    "** The selection could not be determined **";
    Start-Sleep 1

    Clear-Host
    break;
    }
  }
}
while ($response -ne "0")