In this chapter, you will learn to:
There was a time when automating an installation and configuration of the vSphere Hypervisor was quite difficult. Fortunately, VMware has worked hard to simplify the overall process. Today 90 percent of the installation is automated out of the box. In this chapter we will briefly walk through the various installation methods before taking a deep dive into automating that last 10 percent. We will cover several techniques for streamlining the installation and configuration of vSphere.
The first step in preparing for an installation is to ensure that your install media is up-to-date and has all of the needed drivers and other vendor packages for your servers. This includes things like storage vendor plug-ins, as well as the Fiber Channel Host Based Adapter (HBA), NIC, SCSI controller, and IPMI/CIM drivers that enable vSphere to better interact with your hardware and provide increased performance, stability, and reporting. PowerCLI has a feature known as the Image Builder CLI, which enables you to manage the packages contained in the install ISO and customize them for your needs.
VMware ships the ESXi ISO with many default packages. You may not need all of them. Often, you need additional drivers. The install image can be customized using PowerCLI. You can tailor it specifically for your environment and include only those packages that are required for your servers.
To get started, make sure that you have downloaded the offline bundle for the version of ESXi you plan to use. Offline bundles are zip files that typically are much larger than the default ISO download. Once you have downloaded an offline bundle, download to the same directory the driver packages that you need. Like the ESXi packages, if your vendor gives you options for online or offline bundles, choose the offline bundle.
To start, you need to add the packages that have been downloaded, which are treated as depots of software packages by PowerCLI. Listing 2-1 shows how to make the Image Builder CLI aware of a downloaded update package. We also want to make sure that the PSSnapin that provides the cmdlets has been added to the environment.
Listing 2-1: Adding an offline bundle package as a software depot
Add-PSSnapin Vmware.ImageBuilder -ErrorAction SilentlyContinue
Add-EsxSoftwareDepot $pathToEsxiOfflineBundle_zip
Add-EsxSoftwareDepot $pathToVendorBundle_zip
You can add as many of these bundles as needed to the cmdlet in Listing 2-2, which checks for packages that have been added and shows an example return.
Listing 2-2: Showing available bundles
Get-EsxSoftwareDepot
Depot Url
---------
zip:C: empVMware-ESXi-6.0.0-2494585-depot.zip?index.xml
zip:C: empNetAppNasPlugin.v21.zip?index.xml
Each bundle contains one or more software packages that will be combined, using the cmdlets, to make the customized install media for your installation. To list the available packages, use the Get-EsxSoftwarePackage
cmdlet. The most interesting will be the non-VMware packages, since these are the ones you are probably trying to add to the default set. In Listing 2-3, we use PowerShell to show only those packages that are not part of VMware’s default bundle.
Listing 2-3: Listing non-VMware software packages
Get-EsxSoftwarePackage | Where-Object {$_.Vendor -ne "VMware"}
After you have downloaded the bundles, you can begin to modify the default images to customize them for your environment. Each bundle includes several image profiles; you can build an image profile to meet your needs from there. To view the existing image profiles, use the Get-ESXImageProfile
cmdlet, as we did in Listing 2-4.
Listing 2-4: Showing available image profiles
Get-EsxImageProfile -Name ESXi-6* | Select-Object Name
Name
----
ESXi-6.0.0-2494585-no-tools
ESXi-6.0.0-2494585-standard
The packages have three basic types: Standard, which includes VMware Tools; No-tools, which is self-explanatory; and those that have a name ending with “s,” which are security updates images. The steps for creating a package are as follows:
Listing 2-5 shows the PowerCLI used to execute those steps and ends by exporting the modified profile as an ISO image that can be used for loading your servers.
Listing 2-5: Modifying the ESXi profile
New-EsxImageProfile `
-CloneProfile ESXi-6.0.0-2494585-standard `
-Name ESXi-6.0.0-PowerCLI `
-Vendor Custom |
Add-EsxSoftwarePackage `
-SoftwarePackage $additionalPackageName |
Remove-EsxSoftwarePackage `
-SoftwarePackage $removeThisPackage
Name Vendor Last Modified Acceptance Level
---- ------ ------------- ----------------
ESXi-6.0.0-PowerCLI Custom 3/8/2015 12:... PartnerSupported
Pipelining the commands makes for an easy way to do all three operations (clone, add, and remove) in one simple step. The final operation is to export the newly customized installation profile to an ISO image (see Listing 2-6).
Listing 2-6: Exporting the customized image
Export-EsxImageProfile -ImageProfile ESXi-6.0.0-PowerCLI `
-FilePath $destinationFolder `
-ExportToIso
The final parameter for the command can be either ExportToIso
, which will output an ISO that can be used to install vSphere to the host, or ExportToBundle
, which will output a bundle capable of being ingested by Update Manager or directly on the host for providing updates to packages.
Now that you have ensured the drivers and other packages for your physical servers are a part of the default install package, let’s investigate the different ways of loading the OS onto the physical host.
There are several different methods to install vSphere, ranging from the humble CD/DVD to the more complex, but more flexible, PXE. The installation method is the starting point from which you work backward. Once you have selected an install medium, you then tailor your automation and workflows to that method.
A large part of choosing the installation method is related to the size of your vSphere environment. Each of the available methods carries with it a series of trade-offs. We’ll cover each medium available, highlighting the advantages and disadvantages of each in addition to identifying a target environment size.
We’re going to make the assumption that, since you’re reading a PowerCLI book, your management station is a Windows PC. Therefore, the following requirements apply:
Automating a vSphere installation can mean many different things. At its core, it means you have a zero-touch installation. As you learned earlier, this can be accomplished regardless of the media you choose. You will, however, outgrow this minimal automation solution very quickly, as it doesn’t help solve the bigger problem of host configuration. To resolve that issue, you must first answer one simple, multiple-choice question.
If you chose option A, you will want to try to do as much as possible with the first boot and postinstall sections within Kickstart—but you will find you cannot do everything. The advantage of option A is that there are no external requirements. This is a great solution for small environments. If you have the time and skill set to configure a vSphere host via BusyBox/Python, it is possible to automate just about every aspect of vSphere.
If you chose option B, you will want to configure the bare minimum via Kickstart. Most likely, you’ll configure the management vmknic and partition assignment. That said, it is exponentially easier to perform some actions, like password and license assignment, from Kickstart.
If you chose option C, you undoubtedly have Enterprise+ licensing and want to use this advanced feature. Unfortunately, there are some things that you cannot do using host profiles (see Chapter 5, “Using Advanced vSphere Features,” for more information). Host profiles do offer a compelling capability—compliance. Anything that can be done via host profiles should be done via host profiles, because they will ensure that your hosts continue to be configured correctly.
If you haven’t figured it out already, option D is the best answer. You should use a combination of all three, assuming you have sufficient licensing to use host profiles. There are some aspects of vSphere configuration that are just easier to do while loading the host. Some matters are best left to host profiles. PowerCLI is the glue in all this that will bridge these two disparate worlds. If host profiles are off the table, take the path of least resistance and use both Kickstart and PowerCLI.
As of ESXi 4.1, VMware supports a scripted installation mode: Kickstart. Kickstart is a configuration file that the installer reads in and then uses to perform a silent installation. Exploring the full set of options and capabilities of the Kickstart configuration file is beyond the scope of this book, but we will go over the basics, starting with how to have a non-interactive installation from the CD/DVD and USB installation mediums (see Listing 2-7).
Listing 2-7: A Kickstart configuration for non-interactive installation
# A minimal ks.cfg file which will provide a non-interactive
# installation experience. Note that you will need to customize
# the boot media to specify the ks.cfg path to fully remove
# interaction. This is simply a default configuration, no
# customization will be done.
# Accept the EULA. This is a mandatory parameter.
vmaccepteula
# Set the root password. The password is mandatory, and
# can optionally be encrypted.
rootpw Power$hell
# Install to the first local drive, overwriting any VMFS partitions.
# This can be customized to select different drives, upgrade only, and
# many other operations.
install --firstdisk --overwritevmfs
# Default to DHCP for network connectivity. The option addvmportgroup
# can be left out, which will cause the install to create a default
# virtual machine port group on the vSwitch. Setting the value to
# zero bypasses that step.
network --bootproto=dhcp --device=vmnic0 --addvmportgroup=0
# Reboot after completion. Without this option the install will wait
# for the administrator to press a button at the end of the install
# process.
reboot
Using a USB key for the installation media makes including Kickstart files incredibly easy. Simply create a directory in the root of the drive and place the file there. Figure 2-1 shows the file structure of the install media after it has been loaded. This USB device was created by taking a customized ISO and leveraging UNetbootin to copy the media to the drive.
Notice in Figure 2-1 that a folder named kickstarts
was created at the root of the device. Simply copy any Kickstart files to that folder location, but don’t forget their names! After booting to the USB device you will need to specify the Kickstart location at the boot loader prompt.
Figure 2-2 shows the host after booting to the USB media. When the boot menu screen is displayed, press any key to interrupt the process. Press the Tab key to edit the boot options for your device and append ks=usb:/kickstarts/
ks.cfg, where ks.cfg is the name of your Kickstart file. Once you provide the path to your Kickstart file (Figure 2-3), simply press Enter and go get a cup of coffee (but don’t bring it in the datacenter!).
If this is too much effort for you, you can edit the file ISOLINUX.CFG
in the root of your USB media. Find the line under the “LABEL install
” section that contains the APPEND
descriptor and append the same text we used earlier. Listing 2-8 shows what the file should look like after editing.
Listing 2-8: A completely hands-off ISOLINUX.CFG
DEFAULT handsfree
MENU TITLE ESXi-6.0.0-PowerCLI Boot Menu
NOHALT 1
PROMPT 0
TIMEOUT 80
LABEL install
KERNEL mboot.c32
APPEND -c boot.cfg
MENU LABEL ESXi-5.5.0-PowerCLI ^Installer
LABEL handsfree
KERNEL mboot.c32
APPEND -c boot.cfg ks=usb:/kickstarts/ks.cfg
MENU LABEL Hands-Free ESXi Install
LABEL hddboot
LOCALBOOT 0x80
MENU LABEL ^Boot from local disk
As we indicated earlier, you have several options for postinstallation configuration. They all fall into one of two categories: online or stand-alone. An example of a stand-alone installation is the traditional monolithic Kickstart.
A stand-alone installation should only be used in scenarios where the network connectivity cannot be assumed. In such an install, all the postconfiguration tasks must be handled via the Kickstart %post
and %firstboot
scripts. This is neither easy nor recommended, but under certain conditions, it is the only way to automate all parts of installation. For instance, when you port-channel all network connections to your host, it will not be able to connect to the network until the load-balance configuration has been done on the vSwitch. Because this is a prerequisite for network connectivity, it cannot be done remotely.
As shown in Listing 2-9, you can use a script as the %post
section of a Kickstart configuration file. This two-line script adds a second NIC to the standard vSwitch and enables an IP hash load-balancing scheme.
Listing 2-9: Configuring vSwitch load balancing using Kickstart
%firstboot --interpreter=busybox
# add a second NIC to the standard vSwitch
esxcli network vswitch standard uplink add
-v vSwitch0 -u vmnic1
# update the load balance to use ip hash
esxcli network vswitch standard policy failover set
-v vSwitch0 -a vmnic0,vmnic1 -l iphash
An online installation is the preferred method for configuring vSphere. Host profiles fall into this category because they require network access to function. It is possible to perform online postinstallation configuration as either a semiautomated or fully automated task. For instance, you could manually run a PowerCLI/vCLI script to configure a fresh vSphere host. This approach is still far better than the completely manual process. For example, Listing 2-10 takes a fresh vSphere host and performs the following configuration tasks:
Listing 2-10: Postinstallation configuration from a manually run script
# Add our host to vCenter, and immediately enable lockdown mode!
$VMhost = Add-VMHost -Name vSphere03.vSphere.local `
-User root `
-Password pa22word `
-Location (Get-Datacenter) `
-Force
Set-VMHostLockdown -VMHost $VMhost -Enable
# Add iSCSI VMkernel vNIC
$vSwitch = Get-VirtualSwitch -VMHost $VMHost -Name 'vSwitch0'
# we have to first create a portgroup to bind our vNIC to.
$vPG = New-VirtualPortGroup -Name iSCSI `
-VirtualSwitch $vSwitch `
-VLanId 55
# Create our new vNIC in the iSCSI PG we just created
$vNIC = New-VMHostNetworkAdapter -VMHost $VMHost `
-PortGroup iSCSI `
-VirtualSwitch $vSwitch `
-IP 10.10.55.3 `
-SubnetMask 255.255.255.0
# Enable the software iSCSI adapter if not already enabled.
$VMHostStorage = Get-VMHostStorage -VMHost $VMhost |
Set-VMHostStorage -SoftwareIScsiEnabled $True
#sleep while iSCSI starts up
Start-Sleep -Seconds 30
# By default vSphere will set the Target Node name to
# iqn.1998-01.com.vmware:<HostName>-<random number> the
# following cmd will remove everything after the hostname, set
# Chap auth, and add a send Target.
#
# Example iqn.1998-01.com.vmware:esx01-165435 becomes
# iqn.1998-01.com.vmware:esx01
#
# Note that if your hostname has dashes in it, you'll
# need to change the regex below.
$pattern = "iqn.1998-01.com.vmware:w*"
Get-VMHostHba -VMHost $VMHost -Type IScsi |
Where-Object {$_.IScsiName -match $pattern} |
Set-VMHostHba -IScsiName $Matches[0] |
Set-VMHostHba -ChapName 'vmware' `
-ChapPassword 'password' `
-ChapType "Required" |
New-IScsiHbaTarget -Address '192.168.1.1' -Port "3260" |
Out-Null
The advantage of a script like the one in Listing 2-10 is that it is efficient and repeatable. You can reload vSphere03
with reckless abandon, knowing it will be a quick and simple process to get your host back to hosting virtual machines. You’ll notice that we used a custom PowerCLI function to enable Lockdown mode on the vSphere host. Set-VMHostLockdown
, featured in Listing 2-11, can be used to automate vSphere host Lockdown mode en masse.
Listing 2-11: Using the Set-VMHostLockdown
function
function Set-VMHostLockdown {
<# .SYNOPSIS
Enable or disable lockdown mode for an ESXi host.
.EXAMPLE
Enable lockdown mode for an ESXi host
Set-VMHostLockdown -VMHost (Get-VMHost $name) -Enable
.EXAMPLE
Use the pipeline to disable lockdown mode for a cluster
Get-Cluster someCluster | Set-VMHostLockdown -Enable:$false
.PARAMETER VMHost
The host to modify.
.PARAMETER Enable
Enable lockdown mode for the specified host.
.PARAMETER Disable
Disable lockdown mode for the specified host.
.INPUTS
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl]
#>
[CmdletBinding(SupportsShouldProcess=$true)]
Param(
# the VMHost to enable or disable lockdown on
[Parameter(
Mandatory=$true,
ValueFromPipeline=$true,
HelpMessage="VMHost"
)]
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl]
$VMHost
,
# enable/disable lockdown
[Parameter(Mandatory=$true)]
[switch]
$Enable
)
Process {
$hostView = $VMHost | Get-View -Property Name
if ($Enable) {
$msg = "Entering lockdown mode"
if ($PsCmdlet.ShouldProcess($VMHost.Name, $msg)) {
$hostView.EnterLockdownMode()
}
} else {
$msg = "Exiting lockdown mode"
if ($PsCmdlet.ShouldProcess($VMHost.Name, $msg)) {
$hostView.ExitLockdownMode()
}
}
}
}
As powerful as Listing 2-10 is, it can be expanded. By simply adding a couple of parameters and wrapping your work in a PowerCLI script, you can make your one-off solution an enterprise-wide solution. In Listing 2-12, we expanded on our original example. This additional layer of abstraction enables some powerful use cases. For instance, if you loaded a number of hosts, you could then configure them all at once:
1..50 | ForEach-Object {
Assert-VMHostConfiguration `
-VMHostName ("vSphere{0:00}.vSphere.local" -f $_) `
-User root `
-password pa22word `
-IPAddress 10.10.1.$_
}
Listing 2-12: Parameterized vSphere host configuration function
function Assert-VMHostConfiguration {
<# .SYNOPSIS
Apply configuration to a specified host.
.EXAMPLE
Configure a host.
Assert-VMHostConfiguration -VMHostName host3 -User root `
-Password letmein -IPAddress $iSCSI_IP
.PARAMETER VMHostName
The name or IP of the ESXi host to configure.
.PARAMETER User
The username to connect to the ESXi host with.
.PARAMETER Password
ESXi password.
.PARAMETER IPAddress
The IP address to be assigned to the iSCSI vmknic.
.Parameter Location
The location in the vCenter inventory to add the
ESXi host.
#>
Param(
[String]$VMHostName
, [String]$User
, [String]$password
, [String]$IPAddress
, [Object]$Location = (Get-Datacenter | Select-Object -First 1)
)
# Add our host to vCenter, and immediately enable
# lockdown mode!
$VMhost = Add-VMHost -Name $VMHostName `
-User $user `
-Password $Password `
-Location $Location `
-Force
Set-VMHostLockdown -VMHost $VMhost -Enable
# Add iSCSI VMkernel vNIC
$vSwitch = Get-VirtualSwitch -VMHost $VMHost `
-Name 'vSwitch0'
# we have to first create a portgroup to bind our vNIC to.
$vPG = New-VirtualPortGroup -Name iSCSI `
-VirtualSwitch $vSwitch `
-VLanId 55
# Create our new vNIC in the iSCSI PG we just created
$vNIC = New-VMHostNetworkAdapter -VMHost $VMHost `
-PortGroup iSCSI `
-VirtualSwitch $vSwitch `
-IP $IPAddress `
-SubnetMask 255.255.255.0
# Enable the software ISCSI adapter if not already enabled.
$VMHostStorage = Get-VMHostStorage -VMHost $VMhost |
Set-VMHostStorage -SoftwareIScsiEnabled $True
#sleep while iSCSI starts up
Start-Sleep -Seconds 30
# By default vSphere will set the Target Node name to
# iqn.1998-01.com.vmware:<HostName>-<random number> This
# script will remove everything after the hostname, set Chap
# auth, and add a send Target.
#
# Example iqn.1998-01.com.vmware:esx01-165435 becomes
# iqn.1998-01.com.vmware:esx01
#
# Note that if your hostname has dashes in it, you'll
# need to change the regex below.
$pattern = "iqn.1998-01.com.vmware:w*"
Get-VMHostHba -VMHost $VMHost -Type IScsi |
Where-Object {$_.IScsiName -match $pattern} |
Set-VMHostHba -IScsiName $Matches[0] |
Set-VMHostHba -ChapName 'vmware' `
-ChapPassword 'password' `
-ChapType "Required" |
New-IScsiHbaTarget -Address '192.168.1.1' -Port "3260" |
Out-Null
$VMhost
}
At this point, you have a fairly high level of automation in play. Let’s bring it to the next level by leveraging host profiles. Keep in mind that you must have the Enterprise Plus license level to take advantage of host profiles, but remember that you can use PowerCLI to apply all the settings manually.
Most settings within host profiles have three possible settings:
As shown in Figure 2-4, your selection within the host profile will determine how you script against them. If you select User Specified Setting Will Be Applied, you will always have to supply the setting. If you choose Prompt User If No Default Is Provided, you should test whether a value is necessary before providing one. Finally, if you choose to use a static or dynamic value—that is, a static IP or DHCP—you don’t have to provide a value. The interdependency mesh that is host profiles has led to a lot of confusion on the topic. We’ll go over several techniques to show how to handle each scenario before we circle back around and use host profiles in a vSphere host configuration script.
Regardless of how your settings are applied, automating host profiles is a three-step process:
For example, to attach the host profile named PROD01
to a vSphere host named vSphere03,
run the following command:
$HostProfile = Get-VMHostProfile -Name PROD01
$VMHost = Get-VMHost vSphere03*
Invoke-VMHostProfile -Entity $VMHost `
-Profile $HostProfile `
-AssociateOnly
At this point, the PROD01
host profile is attached to vSphere03
. Now you need to test apply your profile against the host. If the profile has additional information that needs to be answered before the profile can be applied, the Invoke-VMHostProfile
will return a hash table of settings. Therefore, after placing the host in maintenance mode you could capture the output of this action in a variable for use later:
$AdditionalConfiguration = Invoke-VMHostProfile `
-Entity $VMHost `
-ApplyOnly
In our case, it’s a hash table of IP settings:
$AdditionalConfiguration | Select-Object Name
Name
----
network.hostPortGroup["key-vim-profile-host-HostPortgroup↵
Profile-iSCSI"].ipConfig.IpAddressPolicy.address
network.hostPortGroup["key-vim-profile-host-HostPortgroup↵
Profile-vMotion"].ipConfig.IpAddressPolicy.subnetmask
network.hostPortGroup["key-vim-profile-host-HostPortgroup↵
Profile-vMotion"].ipConfig.IpAddressPolicy.address
network.hostPortGroup["key-vim-profile-host-HostPortgroup↵
Profile-iSCSI"].ipConfig.IpAddressPolicy.subnetmask
Before you can apply your profile, you must provide values for these settings. You can accomplish this by addressing each entry in the hash table and setting a simple string value:
$AdditionalConfiguration['network.hostPortGroup[↵
"key-vim-profile-host-HostPortgroupProfile-iSCSI"].ipConfig.↵
IpAddressPolicy.address'] = '10.10.10.1'
$AdditionalConfiguration['network.hostPortGroup[↵
"key-vim-profile-host-HostPortgroupProfile-iSCSI"].ipConfig.↵
IpAddressPolicy.subnetmask'] = '255.255.255.0'
$AdditionalConfiguration['network.hostPortGroup[↵
"key-vim-profile-host-HostPortgroupProfile-vMotion"].ipConfig.↵
IpAddressPolicy.address'] = '10.10.10.1'
$AdditionalConfiguration['network.hostPortGroup[↵
"key-vim-profile-host-HostPortgroupProfile-vMotion"].ipConfig.↵
IpAddressPolicy.subnetmask'] = '255.255.255.0'
Only the PowerCLI team knows why it chose to expose such long and unruly key names. Normally, PowerShell cuts off such long strings, so be sure to pipe to Select-Object
to get the full key name. You can verify your variables by looking at your $AdditionalConfiguration
variable once more:
$AdditionalConfiguration
Name Value
---- -----
network.hostPortGroup["key-... 10.10.10.3
network.hostPortGroup["key-... 255.255.255.0
network.hostPortGroup["key-... 10.10.11.3
network.hostPortGroup["key-... 255.255.255.0
At this point, you are ready to apply the profile. To accomplish this, omit any optional switches and provide the variable parameter with your additional settings. We will take advantage of the PowerShell pipeline and drop our host in and out of Maintenance mode—all in one command:
Set-VMHost -VMHost $VMHost `
-State 'Maintenance' |
Invoke-VMHostProfile -Variable $AdditionalConfiguration |
Set-VMHost -State 'Connected'
Once you’ve satisfied all the requirements, host profiles are quite easy to automate. The tricky part is determining what needs to be configured prior to applying the profile. Sadly, you can’t simply just apply everything all the time; PowerCLI will issue an error if you apply a setting the host profile didn’t expect. Therefore, to automate host profiles you’re forced to either write rather intelligent code or use simplified profiles. For example, Listing 2-13 would safely automate the following tasks:
PROD01
host profile to vSphere03
.Listing 2-13: Applying a host profile to one vSphere host
# Get our target Profiles
$HostProfile = Get-VMHostProfile -Name 'PRO*'
# Get our target VMHost
$VMHost = Get-VMHost 192*
# Associate our host profile with the target host
Invoke-VMHostProfile -Entity $VMHost -Profile $HostProfile `
-AssociateOnly | Out-Null
#test apply the host profile
$AdditionConfiguration = Apply-VMHostProfile -Entity $VMHost `
-ApplyOnly
# process any required values filling in known values, and
# prompting for anything unexpected.
$var = @{}
switch ($AdditionConfiguration.GetEnumerator()) {
{$_.Name -like '*iSCSI*.address' } {
$var += @{$_.Name = '10.10.10.40'}
}
{$_.Name -like '*iSCSI*.subnetmask'} {
$var += @{$_.Name = '255.255.255.0'}
}
{$_.Name -like '*vMotion*.address'} {
$var += @{$_.Name = '10.10.11.40'}
}
{$_.Name -like '*vMotion*.subnetmask'} {
$var += @{$_.Name = '255.255.255.0'}
}
default {
$value=Read-Host "Please provide a value for $($_.Name)"
$var += @{ $_.Name = $value}
}
}
# 1. Place our host in maintenance mode
# 2. Apply our profile
# 3. Exit maintenance mode
# 4. Test for profile compliance
Set-VMHost -VMHost $VMHost -State 'Maintenance'|
Invoke-VMHostProfile -Variable $var |
Set-VMHost -State 'Connected'|
Test-VMHostProfileCompliance
At this point we have fully automated applying host profiles. Let’s wrap everything you’ve learned thus far into a master configuration script. Listing 2-14 is a complete vSphere host provisioning script that will take a new host and perform the following configuration tasks:
iSCSI IQN
.Listing 2-14: Complete vSphere host configuration function
function Invoke-VMHostConfiguration {
<# .SYNOPSIS
Apply expanded configuration to a specified host.
.EXAMPLE
Configure a host.
Invoke-VMHostConfiguration -IPAddress $ip -Cluster "Cluster1" `
-User root -Password letmein
.PARAMETER IPAddress
The IP of the ESXi host to configure.
.PARAMETER Cluster
The name of the cluster which the host will join.
.PARAMETER User
ESXi username.
.PARAMETER Password
ESXi password.
#>
[CmdletBinding()]
Param(
[Parameter(
Mandatory=$true,
ValueFromPipelineByPropertyname=$true
)]
[String]
$IPAddress
,
[Parameter(
Mandatory=$true,
ValueFromPipelineByPropertyName=$True
)]
[String]
$Cluster
,
[Parameter(
ValueFromPipelineByPropertyName=$True
)]
[String]
$User = 'root'
,
[Parameter(
ValueFromPipelineByPropertyName=$True
)]
[String]
$password
)
Process {
# while static enough to not be parameterized we'll still
# define our advanced iSCSI configuration up front thereby
# simplifying any future modifications.
$ChapName = 'vmware'
$ChapPassword = 'password'
$ChapType = 'Required'
$IScsiHbaTargetAddress = '10.10.11.200','10.10.11.201'
$IScsiHbaTargetPort = '3260'
# we'll use the last octet of the IPAddress as the ID for
# the host.
$ESXID = $IPaddress.Split(".")[3]
# Get the actual cluster object for our targeted cluster.
$ClusterImpl = Get-Cluster -Name $Cluster
# Get the parent folder our cluster resides in.
$Folder = Get-VIObjectByVIView $ClusterImpl.ExtensionData.Parent
Write-Verbose "Adding $($IPAddress) to vCenter"
# Add our host to vCenter, and immediately enable
# lockdown mode!
$VMHost = Add-VMHost -Name $IPAddress `
-User $user `
-Password $Password `
-Location $Folder `
-Force `
-ErrorAction 'STOP'
$VMHost | Set-VMHostLockdown -Enable
# Enter Maintenance mode
$VMHost = Set-VMHost -State 'Maintenance' -VMHost $VMHost |
Move-VMHost -Destination $Cluster
# Get the Host profile attached to that cluster
$Hostprofile = Get-VMHostProfile -Entity $Cluster
# attach profile to our new host
Apply-VMHostProfile -Entity $VMHost `
-Profile $HostProfile `
-AssociateOnly `
-Confirm:$false |
Out-Null
# Apply our host profile to gather any required values
$AdditionConfiguration = `
Apply-VMHostProfile -Entity $VMHost `
-Profile $HostProfile `
-ApplyOnly `
-Confirm:$false
# If we have a hashtable then there are additional config
# items that need to be defined. Loop through and attempt
# to fill them in, prompting if we come across something
# we're not prepared for.
if ($AdditionConfiguration.GetType().Name -eq 'Hashtable') {
#Create a new hashtable to hold our information
$var = @{}
# Loop through the collection
switch ($AdditionConfiguration.GetEnumerator()) {
{$_.Name -like '*iSCSI*.address' } {
$var +=@{$_.Name = $('10.10.10.{0}' -f $ESXID)}
}
{$_.Name -like '*iSCSI*.subnetmask'} {
$var += @{$_.Name = '255.255.255.0'}
}
{$_.Name -like '*vMotion*.address'} {
$var +=@{$_.Name = $('10.10.11.{0}' -f $ESXID)}
}
{$_.Name -like '*vMotion*.subnetmask'} {
$var += @{$_.Name = '255.255.255.0'}
}
default {
$value = Read-Host `
"Please provide a value for $($_.Name)"
$var += @{ $_.Name = $value}
}
}
# Apply our profile with the additional config info
$VMHost = Apply-VMHostProfile -Entity $VMHost `
-Confirm:$false `
-Variable $var
} else {
# Apply our profile.
$VMHost = Apply-VMHostProfile -Entity $VMHost `
-Confirm:$false
}
# update vCenter with our new Profile compliance status
Test-VMHostProfileCompliance -VMHost $VMHost | Out-Null
# Enable the software ISCSI adapter if not already enabled.
$VMHostStorage = Get-VMHostStorage -VMHost $VMhost |
Set-VMHostStorage -SoftwareIScsiEnabled $True
# sleep while iSCSI starts up
Start-Sleep -Seconds 30
# By default vSphere will set the Target Node name to
# iqn.1998-01.com.vmware:<HostName>-<MAC Address> This
# script will remove everything after the hostname, set Chap
# auth, and add a send target.
#
# Note that if your hostname has dashes in it, you'll
# need to change the regex below.
$pattern = "iqn.1998-01.com.vmware:w*"
$HBA = Get-VMHostHba -VMHost $VMHost -Type 'IScsi'|
Where-Object {$_.IScsiName -match $pattern}
if ($HBA.IScsiName -ne $Matches[0]) {
$HBA = Set-VMHostHba -IScsiHba $HBA `
-IScsiName $Matches[0]
}
Set-VMHostHba -IScsiHba $HBA `
-ChapName $ChapName `
-ChapPassword $ChapPassword `
-ChapType $ChapType
$IScsiHbaTargetAddress | Foreach-Object {
$HBA | New-IScsiHbaTarget -Address $_ `
-Port $IScsiHbaTargetPort | Out-Null
}
$VMhost
}
}
That’s all well and good, but what if you don’t have access to host profiles? Well, you’re going to need a bigger script, most of which will be filled with pieces of code from all over this book. You’ll have a little storage, network, authentication, licensing, and so on. But wanting to be as complete as possible, we’ll highlight a few additional cmdlets that you’ll find useful.
Add-VmHostNtpServer
cmdlet will do much more than add an NTP server. It can also enable and start the NTP service in case it is stopped:
Add-VmHostNtpServer -NtpServer time.nist.gov `
-VMHost vSphere02.domain.local
Set-VMHostSysLogServer
cmdlet to set up Syslog on vSphere:
Set-VMHostSysLogServer -SysLogServer "log01:507" `
-VMHost vSphere02.domain.local
Set-VMHostAccount
cmdlet. Unfortunately, you will have to connect directly to the host to do so.
Connect-VIServer -Server vSphere02.getadmin.local `
-User root `
-Password ""
Set-VMHostAccount -UserAccount root -Password PowerShell!
Enabling SNMP
Get-VMHostSnmp | Set-VMHostSnmp -Enabled $true
Configuring Communities
Set-VMHostSnmp -ReadOnlyCommunity $communityName `
-HostSnmp (Get-VMHostSnmp)
Adding a Target
Set-VMHostSnmp -TargetHost $sendTrapsHere `
-TargetCommunity $sendCommunity `
-AddTarget`
-HostSnmp (Get-VMHostSnmp)
Set-AdvancedSetting
cmdlet. To enable vMotion, you run the following:
Get-AdvancedSetting -Entity (Get-VMHost vSphere02) `
-Name Migrate.Enabled |
Set-AdvancedSetting -Value 1
Set-AdvancedSetting
cmdlet. For instance, to tune vSphere to run NFS on a NetApp FAS system, you run the following:
@{
'NFS.MaxVolumes' = 256
'Net.TcpipHeapMax' = 512
'Net.TcpipHeapSize' = 32
'NFS.HeartbeatFrequency' = 12
'NFS.HeartbeatTimeout' = 5
'NFS.HeartbeatMaxFailures' = 10
'NFS.MaxQueueDepth' = 64
}.GetEnumerator() | Foreach-Object {
Get-AdvancedSetting -Entity (Get-VMHost vSphere02) `
-Name $_.Name |
Set-AdvancedSetting -Value $_.Value
}
Using the cmdlets we’ve highlighted, and the automation workflow from earlier in the chapter, you can create a zero-touch installation for any environment. Now that you have both a zero-touch vSphere installation via Kickstart and a fully automated host configuration script, it’s time to glue these together and deliver on the promise of a fully automated host provisioning life cycle. To accomplish this task, we adapted a technique originally documented by Lance Berc. The general workflow looks like this:
The PowerCLI script features a custom PowerCLI function, shown in Listing 2-15.
Listing 2-15: The Trace-Port
function
function Trace-Port {
<# .SYNOPSIS
This function will listen on a specified port for a
connection, after one is created, it will return an object
containing the hostname and IP address of the host
which connected.
.EXAMPLE
Listen on port 3333, on the loopback IP
Trace-Port -IPAddress 127.0.0.1 -Port 3333
.PARAMETER IPAddress
The IP of the host to listen on.
.PARAMETER Port
The port number to listen on.
.OUTPUTS
[System.Management.Automation.PSCustomObject]
#>
[CmdletBinding()]
Param (
[Parameter(
Mandatory=$true,
Position=0,
HelpMessage="Address to listen for the connection"
)]
[string]
$IPAddress
,
[int]
$Port=3333
)
End {
[byte[]]$B = 0..255 | Foreach-Object {0}
$ip = [Net.IPAddress]::Parse($IPAddress)
$listener = New-Object System.Net.Sockets.TcpListener(
$ip, $Port
)
$listener.Start()
Write-Debug "Waiting for a connection on port $port..."
$client = $listener.AcceptTcpClient()
$RemoteEndPoint = $client.Client.RemoteEndPoint
$stream = $client.GetStream()
$raw = while (($i = $stream.Read($B, 0, $B.Length)) -ne 0) {
$B[0..($i-1)] | Foreach-Object { $_ }
}
$client.Close()
$listener.Stop()
Write-Debug "Connection closed."
New-Object PSObject -Property @{
'Source' = $RemoteEndPoint.Address.ToString().Split(':')[0]
'Data' = [string]::Join("" ,[char[]]$raw)
}
}
}
Now that you have all the tools in place, it’s time to put it all together. First, as shown in Listing 2-16, place a simple Python script that will reach out and connect to the midwife configuration host. The IP address in the connect method should be the IP address of your midwife server.
Listing 2-16: FirstBoot for wholly automated system installation
%firstboot --interpreter=busybox
esxcli network firewall set --enabled false
cat > /tmp/findme.py << __EOF__
import socket
s = socket.socket()
s.connect(('192.168.145.1',3333))
s.send(socket.gethostname())
s.close()
__EOF__
chmod 755 /tmp/findme.py
python /tmp/findme.py
esxcli network firewall set --enabled true
That’s all there is to it. The Python simply reaches out to the configured host on the designated port and sends its hostname. Now, run the following on your midwife server and Kickstart your host. In about 20 minutes, you’ll have a new host ready to host virtual machines!
Trace-Port -IPAddress 192.168.145.1 -Port 3333 |
Foreach-Object {
Invoke-VMHostConfiguration -IPAddress $_.Source `
-Cluster prod01 `
-User root `
-password pa22word
}
Automating the installation of vSphere hosts can be a complex task, but at the core, it is much like any automation task. Take it step by step, identify the things that need to be done, and leverage the tools at your disposal. For smaller environments, expediting the install process may not be needed, unless you are frequently reloading your servers. In larger environments, it may be critical to automate every aspect of administration. When done manually, configuring a vSphere host can take over an hour; reducing that to just a couple of minutes of administrator time makes great justification for a promotion!