PowerCLI Create vCloud Organization

Creating vCloud Organizations was always a bit tedious in my opinion, if you are a service provider you choose the same options over and over for each customer. So as always, why not spend a bit of time and do it programmatically via powercli and save yourself some clicks.

[String]$OrgName = Read-Host "Enter the Customer Core Account Number (to be used for creating the URL)"
[String]$OrgFullName = Read-Host "Enter the Customer Core Account Name"
[String]$OrgDescription = Read-Host "Enter the Organization Description" 

try {
    $NewOrg = New-Org -Name $OrgName -FullName $OrgFullName -Description $OrgDescription

    $org = Get-Org -Name $OrgName
 
    # Configure Org to use the system LDAP
    $org.ExtensionData.Settings.OrgLdapSettings.OrgLdapMode = "SYSTEM"
    $org.ExtensionData.UpdateServerData()
    $org.ExtensionData.UpdateViewData()
 
    # Allow sharing of catalogs to other organizations
    $org.ExtensionData.Settings.OrgGeneralSettings.CanPublishCatalogs = $True
    $org.ExtensionData.Settings.OrgGeneralSettings.CanPublishExternally = $True
    $org.ExtensionData.Settings.OrgGeneralSettings.CanSubscribe = $True
    $org.ExtensionData.UpdateServerData()
    $org.ExtensionData.UpdateViewData()
 
    # Set vApp lease times
    $leases = $org.ExtensionData.Settings.GetVAppLeaseSettings()
    $leases.DeploymentLeaseSeconds = 0
    $leases.StorageLeaseSeconds = 0
    $leases.DeleteOnStorageLeaseExpiration = $False
    $leases.UpdateServerData()
 
    # Set vApp template lease times
    $templateleases = $org.ExtensionData.Settings.GetVAppTemplateLeaseSettings()
    $templateleases.StorageLeaseSeconds = 0
       $templateleases.DeleteOnStorageLeaseExpiration = $False
    $templateleases.UpdateServerData()
 
    # Set Org operations limits
    $limits = $org.ExtensionData.Settings.GetOperationLimitsSettings()
    $limits.OperationsPerUser = "3"
    $limits.OperationsPerOrg = "6"
    $limits.UpdateServerData()

    # Set Password Policy Limits
    $PasswordLimits = $org.ExtensionData.Settings.OrgPasswordPolicySettings
    $PasswordLimits.AccountLockoutEnabled = $True
    $PasswordLimits.UpdateServerData()

    } catch {
        $removeOrg = Search-Cloud Organization -name $OrgName
        if ($removeOrg -eq $null) {
            Write-Host "The Org was never created, closing down Program"
            DisconnectServers
            Exit
        } else {
            RemoveOrg
            Exit
            }
    }

PowerCLI create Load Balancer

Been a few days since my last post but wanted to come back and post the code to create a Load Balancer in vCloud via Powercli.

This took a very long time to finally get right and frankly the amount of code that needs to be entered is just silly. Creating a Load Balancer in NSX is so much easier compared to this so I cannot wait until NSX gets full integration with vCloud so we can skip this mess.

The use case here was to create a Edge Load Balancer for 2 vCloud cells to use. This would require HTTP/S as well as Console Load Balancing over 2 networks (ExNet and VMNet.) Feel free to hit me up with any questions regarding this. I’ll post how much simpler it is with NSX in the near future.

#Configuring the LB on the Edge
$edgegateway = Search-Cloud -QueryType EdgeGateway -name $orgName | Get-CIView

#Enable LB Service
$LoadBalancer = New-Object VMware.VimAutomation.Cloud.Views.LoadBalancerService
$LoadBalancer.IsEnabled = $true

#Creation of HTTP/S IP Pool Object
$LoadBalancer.Pool = New-Object VMware.VimAutomation.Cloud.Views.LoadBalancerPool
$LoadBalancer.Pool += New-Object VMware.VimAutomation.Cloud.Views.LoadBalancerPool
$LoadBalancer.Pool[0].Name = "vCloud-HTTP-Pool"
$LoadBalancer.Pool[0].Description = "vCloud HTTP Pool of IPs"
$LoadBalancer.Pool[0].Id = "1"

#Creation of Console IP Pool Object
$LoadBalancer.Pool[1].Name = "vCloud-Console-Pool"
$LoadBalancer.Pool[1].Description = "vCloud Console Pool of IPs"
$LoadBalancer.Pool[1].Id = "2"

#Create HTTPS Health Check for Pool
$LoadBalancer.Pool[0].ServicePort = New-Object VMware.VimAutomation.Cloud.Views.LBPoolServicePort
$LoadBalancer.Pool[0].ServicePort += New-Object VMware.VimAutomation.Cloud.Views.LBPoolServicePort
$LoadBalancer.Pool[0].ServicePort[0].Port = "443"
$LoadBalancer.Pool[0].ServicePort[0].IsEnabled = $true
$LoadBalancer.Pool[0].ServicePort[0].HealthCheckPort = "443"
$LoadBalancer.Pool[0].ServicePort[0].Protocol = "HTTPS"
$LoadBalancer.Pool[0].ServicePort[0].Algorithm = "ROUND_ROBIN"
$LoadBalancer.Pool[0].ServicePort[0].HealthCheck = New-Object VMware.VimAutomation.Cloud.Views.LBPoolHealthCheck
$LoadBalancer.Pool[0].ServicePort[0].HealthCheck[0].Mode = "SSL"
$LoadBalancer.Pool[0].ServicePort[0].HealthCheck[0].Interval = "10"
$LoadBalancer.Pool[0].ServicePort[0].HealthCheck[0].Timeout = "15"
$LoadBalancer.Pool[0].ServicePort[0].HealthCheck[0].HealthThreshold = "2"
$LoadBalancer.Pool[0].ServicePort[0].HealthCheck[0].UnHealthThreshold = "3"
$LoadBalancer.Pool[0].ServicePort[0].HealthCheck[0].Uri = "/cloud/server_status"

#Create HTTP Health Check for Pool
$LoadBalancer.Pool[0].ServicePort[1].Port = "80"
$LoadBalancer.Pool[0].ServicePort[1].IsEnabled = $true
$LoadBalancer.Pool[0].ServicePort[1].HealthCheckPort = "80"
$LoadBalancer.Pool[0].ServicePort[1].Protocol = "HTTP"
$LoadBalancer.Pool[0].ServicePort[1].Algorithm = "ROUND_ROBIN"
$LoadBalancer.Pool[0].ServicePort[1].HealthCheck = New-Object VMware.VimAutomation.Cloud.Views.LBPoolHealthCheck
$LoadBalancer.Pool[0].ServicePort[1].HealthCheck[0].Mode = "HTTP"
$LoadBalancer.Pool[0].ServicePort[1].HealthCheck[0].Interval = "10"
$LoadBalancer.Pool[0].ServicePort[1].HealthCheck[0].Timeout = "15"
$LoadBalancer.Pool[0].ServicePort[1].HealthCheck[0].HealthThreshold = "2"
$LoadBalancer.Pool[0].ServicePort[1].HealthCheck[0].UnHealthThreshold = "3"
$LoadBalancer.Pool[0].ServicePort[1].HealthCheck[0].Uri = "/cloud/server_status"

#Create Console Health Check for Pool
$LoadBalancer.Pool[1].ServicePort = New-Object VMware.VimAutomation.Cloud.Views.LBPoolServicePort
$LoadBalancer.Pool[1].ServicePort[0].Port = "443"
$LoadBalancer.Pool[1].ServicePort[0].IsEnabled = $true
$LoadBalancer.Pool[1].ServicePort[0].HealthCheckPort = "443"
$LoadBalancer.Pool[1].ServicePort[0].Protocol = "TCP"
$LoadBalancer.Pool[1].ServicePort[0].Algorithm = "ROUND_ROBIN"
$LoadBalancer.Pool[1].ServicePort[0].HealthCheck = New-Object VMware.VimAutomation.Cloud.Views.LBPoolHealthCheck
$LoadBalancer.Pool[1].ServicePort[0].HealthCheck[0].Mode = "TCP"
$LoadBalancer.Pool[1].ServicePort[0].HealthCheck[0].Interval = "10"
$LoadBalancer.Pool[1].ServicePort[0].HealthCheck[0].Timeout = "15"
$LoadBalancer.Pool[1].ServicePort[0].HealthCheck[0].HealthThreshold = "2"
$LoadBalancer.Pool[1].ServicePort[0].HealthCheck[0].UnHealthThreshold = "3"
$LoadBalancer.Pool[1].ServicePort[0].HealthCheck[0].Uri = "/"

#Create HTTP/S Pool Member #1
$LoadBalancer.Pool[0].Member = New-Object VMware.VimAutomation.Cloud.Views.LBPoolMember
$LoadBalancer.Pool[0].Member += New-Object VMware.VimAutomation.Cloud.Views.LBPoolMember
$LoadBalancer.Pool[0].Member[0].IpAddress = $vCloud_CellA_HTTP
$LoadBalancer.Pool[0].Member[0].Weight = 1
$LoadBalancer.Pool[0].Member[0].ServicePort = New-Object VMware.VimAutomation.Cloud.Views.LBPoolServicePort
$LoadBalancer.Pool[0].Member[0].ServicePort += New-Object VMware.VimAutomation.Cloud.Views.LBPoolServicePort
$LoadBalancer.Pool[0].Member[0].ServicePort[0].Port = "443"
$LoadBalancer.Pool[0].Member[0].ServicePort[0].HealthCheckPort = "443"
$LoadBalancer.Pool[0].Member[0].ServicePort[0].Protocol = "HTTPS"
$LoadBalancer.Pool[0].Member[0].ServicePort[1].Port = "80"
$LoadBalancer.Pool[0].Member[0].ServicePort[1].HealthCheckPort = "80"
$LoadBalancer.Pool[0].Member[0].ServicePort[1].Protocol = "HTTP"

#Create HTTP/S Pool Member #2
$LoadBalancer.Pool[0].Member[1].IpAddress = $vCloud_CellB_HTTP
$LoadBalancer.Pool[0].Member[1].Weight = 1
$LoadBalancer.Pool[0].Member[1].ServicePort = New-Object VMware.VimAutomation.Cloud.Views.LBPoolServicePort
$LoadBalancer.Pool[0].Member[1].ServicePort += New-Object VMware.VimAutomation.Cloud.Views.LBPoolServicePort
$LoadBalancer.Pool[0].Member[1].ServicePort[0].Port = "443"
$LoadBalancer.Pool[0].Member[1].ServicePort[0].HealthCheckPort = "443"
$LoadBalancer.Pool[0].Member[1].ServicePort[0].Protocol = "HTTPS"
$LoadBalancer.Pool[0].Member[1].ServicePort[1].Port = "80"
$LoadBalancer.Pool[0].Member[1].ServicePort[1].HealthCheckPort = "80"
$LoadBalancer.Pool[0].Member[1].ServicePort[1].Protocol = "HTTP"

#Create Console Pool Member #1
$LoadBalancer.Pool[1].Member = New-Object VMware.VimAutomation.Cloud.Views.LBPoolMember
$LoadBalancer.Pool[1].Member += New-Object VMware.VimAutomation.Cloud.Views.LBPoolMember
$LoadBalancer.Pool[1].Member[0].IpAddress = $vCloud_CellA_Console
$LoadBalancer.Pool[1].Member[0].Weight = 1
$LoadBalancer.Pool[1].Member[0].ServicePort = New-Object VMware.VimAutomation.Cloud.Views.LBPoolServicePort
$LoadBalancer.Pool[1].Member[0].ServicePort[0].Port = "443"
$LoadBalancer.Pool[1].Member[0].ServicePort[0].HealthCheckPort = "443"
$LoadBalancer.Pool[1].Member[0].ServicePort[0].Protocol = "TCP"

#Create Console Pool Member #2
$LoadBalancer.Pool[1].Member[1].IpAddress = $vCloud_CellB_Console
$LoadBalancer.Pool[1].Member[1].Weight = 1
$LoadBalancer.Pool[1].Member[1].ServicePort = New-Object VMware.VimAutomation.Cloud.Views.LBPoolServicePort
$LoadBalancer.Pool[1].Member[1].ServicePort[0].Port = "443"
$LoadBalancer.Pool[1].Member[1].ServicePort[0].HealthCheckPort = "443"
$LoadBalancer.Pool[1].Member[1].ServicePort[0].Protocol = "TCP"

#Instantiate the Virtual Server Object Array
$LoadBalancer.VirtualServer = New-Object VMware.VimAutomation.Cloud.Views.LoadBalancerVirtualServer
$LoadBalancer.VirtualServer += New-Object VMware.VimAutomation.Cloud.Views.LoadBalancerVirtualServer

#Create Virtual Server #1 for HTTP/S
$LoadBalancer.VirtualServer[0].Name = "vCloud-HTTPS-VIP"
$LoadBalancer.VirtualServer[0].IsEnabled = $true
$LoadBalancer.VirtualServer[0].IPAddress = $VMNetExTernalBlock[1]
$LoadBalancer.VirtualServer[0].Interface = $VMNetExternalNetwork.href
$LoadBalancer.VirtualServer[0].Description = "Virtual IP connecting VMNet to vCloud Web Client"
$LoadBalancer.VirtualServer[0].ServiceProfile = New-Object VMware.VimAutomation.Cloud.Views.LBVirtualServerServiceProfile
$LoadBalancer.VirtualServer[0].ServiceProfile[0].isEnabled = $true
$LoadBalancer.VirtualServer[0].ServiceProfile[0].Protocol = "HTTPS"
$LoadBalancer.VirtualServer[0].ServiceProfile[0].Port = "443"
$LoadBalancer.VirtualServer[0].ServiceProfile[0].Persistence = New-Object VMware.VimAutomation.Cloud.Views.LBPersistence
$LoadBalancer.VirtualServer[0].ServiceProfile[0].Persistence.Method = "SSL_SESSION_ID"
$LoadBalancer.VirtualServer[0].Logging = $true
$LoadBalancer.VirtualServer[0].Pool = "vCloud-HTTP-Pool"

#Create Virtual Server #2 for Console
$LoadBalancer.VirtualServer[1].Name = "vCloud-Console-VIP"
$LoadBalancer.VirtualServer[1].IsEnabled = $true
$LoadBalancer.VirtualServer[1].IPAddress = $VMNetExTernalBlock[2]
$LoadBalancer.VirtualServer[1].Interface = $VMNetExternalNetwork.href
$LoadBalancer.VirtualServer[1].Description = "Virtual IP connecting VMNet to vCloud Console"
$LoadBalancer.VirtualServer[1].ServiceProfile = New-Object VMware.VimAutomation.Cloud.Views.LBVirtualServerServiceProfile
$LoadBalancer.VirtualServer[1].ServiceProfile[0].isEnabled = $true
$LoadBalancer.VirtualServer[1].ServiceProfile[0].Protocol = "TCP"
$LoadBalancer.VirtualServer[1].ServiceProfile[0].Port = "443"
$LoadBalancer.VirtualServer[1].ServiceProfile[0].Persistence = New-Object VMware.VimAutomation.Cloud.Views.LBPersistence
$LoadBalancer.VirtualServer[1].ServiceProfile[0].Persistence.Method = $null
$LoadBalancer.VirtualServer[1].Logging = $true
$LoadBalancer.VirtualServer[1].Pool = "vCloud-Console-Pool"


$edgegateway.ConfigureServices($LoadBalancer)

PowerCLI Create Edge Firewall

In our labs I had need to be able to create Edge Firewalls via PowerCLI in order to speed along deployment for various vendors and customers. Using the UI was cumbersome and often lead to mistakes so time to do this all via powerCLI. This will deploy an Edge with the following variables:

 

  • HA Edge
  • DNS Relay Enabled
  • Compact Size
  • 2 External Interfaces called ExNet and VMNet
    • The Interface IP’s are also sub-allocated to the Edge allowing for later SNAT outbound connectivity
# Create Edge Firewall
$firewall = New-Object VMware.VimAutomation.Cloud.Views.Gateway
$firewall.Name = $orgName
$firewall.Configuration = New-Object VMware.VimAutomation.Cloud.Views.GatewayConfiguration
$firewall.Configuration.BackwardCompatibilityMode = $false
$firewall.Configuration.GatewayBackingConfig = "compact"
$firewall.Configuration.UseDefaultRouteForDnsRelay = $true
$firewall.Configuration.HaEnabled = $true

$firewall.Configuration.EdgeGatewayServiceConfiguration = New-Object VMware.VimAutomation.Cloud.Views.GatewayFeatures
$firewall.Configuration.GatewayInterfaces = New-Object VMware.VimAutomation.Cloud.Views.GatewayInterfaces

$firewall.Configuration.GatewayInterfaces.GatewayInterface = New-Object VMware.VimAutomation.Cloud.Views.GatewayInterface
$firewall.Configuration.GatewayInterfaces.GatewayInterface += New-Object VMware.VimAutomation.Cloud.Views.GatewayInterface
$firewall.Configuration.GatewayInterfaces.GatewayInterface[0].DisplayName = "ExNet"
$firewall.Configuration.GatewayInterfaces.GatewayInterface[0].Network = $ExNetExternalNetwork.Href
$firewall.Configuration.GatewayInterfaces.GatewayInterface[0].InterfaceType = "uplink"
$firewall.Configuration.GatewayInterfaces.GatewayInterface[0].UseForDefaultRoute = $true
$firewall.Configuration.GatewayInterfaces.GatewayInterface[0].ApplyRateLimit = $false
$firewall.Configuration.GatewayInterfaces.GatewayInterface[1].DisplayName = "VMNet"
$firewall.Configuration.GatewayInterfaces.GatewayInterface[1].Network = $VMNetExternalNetwork.Href
$firewall.Configuration.GatewayInterfaces.GatewayInterface[1].InterfaceType = "uplink"
$firewall.Configuration.GatewayInterfaces.GatewayInterface[1].UseForDefaultRoute = $false
$firewall.Configuration.GatewayInterfaces.GatewayInterface[1].ApplyRateLimit = $false
$ExNetexternalSubnet = New-Object VMware.VimAutomation.Cloud.Views.SubnetParticipation
$ExNetexternalSubnet.Gateway = $ExNetExternalNetwork.Gateway
$ExNetexternalSubnet.Netmask = $ExNetExternalNetwork.Netmask
$ExNetexternalSubnet.IpAddress = $ExNetExternalBlock[0]
$ExNetexternalSubnet.IpRanges = New-Object VMware.VimAutomation.Cloud.Views.IpRanges
$ExNetexternalSubnet.IpRanges.IpRange = New-Object VMware.VimAutomation.Cloud.Views.IpRange
$ExNetexternalSubnet.IpRanges.IpRange[0].StartAddress = $ExNetexternalSubnet.IpAddress # ### $firstExternalIP
$ExNetexternalSubnet.IpRanges.IpRange[0].EndAddress = $ExNetexternalSubnet.IpAddress # ### $lastExternalIP

$VMNetexternalSubnet = New-Object VMware.VimAutomation.Cloud.Views.SubnetParticipation
$VMNetexternalSubnet.Gateway = $VMNetExternalNetwork.Gateway
$VMNetexternalSubnet.Netmask = $VMNetExternalNetwork.Netmask
$VMNetexternalSubnet.IpAddress = $VMNetExTernalBlock[0]
$VMNetexternalSubnet.IpRanges = New-Object VMware.VimAutomation.Cloud.Views.IpRanges
$VMNetexternalSubnet.IpRanges.IpRange = New-Object VMware.VimAutomation.Cloud.Views.IpRange
$VMNetexternalSubnet.IpRanges.IpRange += New-Object VMware.VimAutomation.Cloud.Views.IpRange
$VMNetexternalSubnet.IpRanges.IpRange += New-Object VMware.VimAutomation.Cloud.Views.IpRange
$VMNetexternalSubnet.IpRanges.IpRange[0].StartAddress = $VMNetexternalSubnet.IpAddress # ### $firstExternalIP
$VMNetexternalSubnet.IpRanges.IpRange[0].EndAddress = $VMNetexternalSubnet.IpAddress # ### $firstExternalIP
$VMNetexternalSubnet.IpRanges.IpRange[1].StartAddress = $VMNetExTernalBlock[1] # ### $SecondExternalIP
$VMNetexternalSubnet.IpRanges.IpRange[1].EndAddress = $VMNetExTernalBlock[1] # ### $SecondExternalIP
$VMNetexternalSubnet.IpRanges.IpRange[2].StartAddress = $VMNetExTernalBlock[2] # ### $ThirdExternalIP
$VMNetexternalSubnet.IpRanges.IpRange[2].EndAddress = $VMNetExTernalBlock[2] # ### $ThirdExternalIP
$firewall.Configuration.GatewayInterfaces.GatewayInterface[0].SubnetParticipation = $ExNetexternalSubnet
$firewall.Configuration.GatewayInterfaces.GatewayInterface[1].SubnetParticipation = $VMNetexternalSubnet
$orgVdc.ExtensionData.CreateEdgeGateway($firewall)

If you’re looking for reference code on how to deploy Load Balancers, Add Routed Networks, create NAT and Firewall rules stay tuned, I’ll be posting those in the next few days.

DNS Fun with vCloud

For the last 2 days one of our Primary QE labs has been down for the count unable to power on vApps or individual virtual machines. What was really strange was the error messages we were receiving indicated that a NFC connection could not be made between vCloud and the VM we were attempting to power on:

Screen Shot 2015-06-03 at 8.37.24 PM

 

What was maddening was this problem only manifests itself if you had Guest Customization enabled on the individual VM’s. After spending nearly 2 who days with VMware support we tracked down the following log error in the vpxd log which indicated we had a DNS resolution problem on our Windows Virtual Center. Full Credit to Chris Meza over at VMware if anyone has the pleasure of ever working with him.

 

2015-06-03T14:39:21.101-05:00 [01256 info ‘commonvpxLro’ opID=activity=urn:uuid:9036ff98-3bf0-4ab9-be81-425c8d5252a7-17] [VpxLRO] — BEGIN task-internal-88227 —  — vim.ServiceInstance.retrieveContent — 4bda5e15-21e2-1000-f583-ed4db88e6ba9(521b927f-4c9f-c0fa-4980-2de976e0cb86)2015-06-03T14:39:21.101-05:00 [01256 info ‘commonvpxLro’ opID=activity=urn:uuid:9036ff98-3bf0-4ab9-be81-425c8d5252a7-17] [VpxLRO] — FINISH task-internal-88227 —  — vim.ServiceInstance.retrieveContent —

2015-06-03T14:39:21.167-05:00 [10544 info ‘commonvpxLro’ opID=activity=urn:uuid:9036ff98-3bf0-4ab9-be81-425c8d5252a7-f6] [VpxLRO] — BEGIN task-internal-88228 —  — vim.SessionManager.acquireGenericServiceTicket — 4bda5e15-21e2-1000-f583-ed4db88e6ba9(521b927f-4c9f-c0fa-4980-2de976e0cb86)

2015-06-03T14:39:21.169-05:00 [10544 error ‘authvpxdMoSessionManager’ opID=activity=urn:uuid:9036ff98-3bf0-4ab9-be81-425c8d5252a7-f6] [SessionManagerMo::GetHostBySpecInt] url host not found by IP: https://581842-hyp7.mv.rackspace.com/folder*/*/cust*.cab, 10.252.12.244

2015-06-03T14:39:21.169-05:00 [10544 info ‘commonvpxLro’ opID=activity=urn:uuid:9036ff98-3bf0-4ab9-be81-425c8d5252a7-f6] [VpxLRO] — FINISH task-internal-88228 —  — vim.SessionManager.acquireGenericServiceTicket —

2015-06-03T14:39:21.169-05:00 [10544 info ‘Default’ opID=activity=urn:uuid:9036ff98-3bf0-4ab9-be81-425c8d5252a7-f6] [VpxLRO] — ERROR task-internal-88228 —  — vim.SessionManager.acquireGenericServiceTicket: vmodl.fault.InvalidArgument:

 

Now this environment has been up and running for close to 2 years now so to suddenly have DNS issues seemed odd. Then I remembered the server had been Patched Tuesday Morning as usual, only this time something changed. The Interface Binding order on the Windows host flipped and DNS resolution was occurring on a secondary interface rather then the primary (VMNet instead of ExNet as we name them internally.) Prior to updating the Interface binding we received this DNS resolution:


Screen Shot 2015-06-03 at 8.04.24 PM

And after updating the Interface binding:

Screen Shot 2015-06-03 at 8.04.13 PM

This resolved our issues and everything was once again able to power on and customize correctly. In case you are unfamiliar how to update the interface bindings here are your instructions:

  • Open your Network and Sharing Center.
  • Press the ALT key on your keyboard to show the menu bar.
  • Click on the Advanced menu
  • choose Advanced Settings option
  • Adjust your binding order for your NICs to ensure your primary Public Interface is on Top

Screen Shot 2015-06-03 at 8.03.55 PM

Nested ESXi Auto-Deploy

A lot of my work these days revolves around creating labs for various vendors and departments, including VMware ironically. I needed a way to quickly deploy and create Nested ESXi hypervisors via vCloud Director that had a consistent configuration. While just cloning an ESXi installation would work, it often had several catches such as the following:

  1. Storage Devices had the same names
  2. Mac Addresses and UUID’s were the same

This led to quite a bit of re-work once a clone was taken. Taking a queue from this blog: how-to-provision-nested-esxi-hosts I was able to create a local.sh shell script that can be run during the first bootup of a new ESXi hypervisor. One bit that took a bit was guaranteeing that the storage device was unique between all hosts. This code accomplishes it:

In my environment the VMDK was identified by the following: ‘/vmfs/devices/disks/mpx.vmhba1\:C0\:T0\:L0\:3’ So I needed to remove the partition name so the below code would create a unique partition name for each host based on the ComputerName.

	vmkfstools -C vmfs5 -b 1m -S $vCloud_computerName /vmfs/devices/disks/mpx.vmhba1\:C0\:T0\:L0\:3

To prep a host we need to do the following. This will reset the Mac Address of the VMkernel interfaces, reset the System UUID and backup the configuration before rebooting.

esxcli system settings advanced set -o /Net/FollowHardwareMac -i 1
sed -i "/\/system\/uuid/d" /etc/vmware/esx.conf
/sbin/auto-backup.sh

 

 

The result is on each deployment of the ESXi server boots with it’s own variables as passed from vCloud. The below script initializes interfaces, DNS servers, datastore names reboots the system. To prevent a never ending loop one of the last bits I added was to delete the script and reboot, may be a bit blunt but it gets the job done.

#!/bin/sh</code>

# local configuration options

# Note: modify at your own risk! If you do/use anything in this
# script that is not part of a stable API (relying on files to be in
# specific places, specific tools, specific output, etc) there is a
# possibility you will end up with a broken system after patching or
# upgrading. Changes are not supported unless under direction of
# VMware support.
getprops_from_ovfxml()
{

/bin/python - &lt;/tmp/ovf.xml 2&gt;/dev/null
[ -s /tmp/ovf.xml ] || {
log "ERROR: Cannot get OVF parameters through VMware Tools. Exiting ..."
exit 1
}
o=`hostname`
eval `getprops_from_ovfxml /tmp/ovf.xml`
[ "${o%%.*}" == "$vCloud_computerName" ] &amp;&amp;
{
log "Hostname is unchanged. Skipping OVF customizations ..."
sed -i '60,73d' /etc/rc.local.d/local.sh
/sbin/auto-backup.sh
exit 0
}
grep "fqdn.fqdn" /etc/dhclient-vmk0.conf &gt;/dev/null &amp;&amp;
{
log "OVF customization already done. Exiting ..."
exit 0
}
log "Applying OVF customizations ..."
rm -f /tmp/ovf.xml
esxcli system hostname set --host=$vCloud_computerName
esxcli network ip interface ipv4 set -i vmk0 -I $vCloud_ip_0 -N $vCloud_netmask_0 -t static
esxcli network ip route ipv4 add -g $vCloud_gateway_0 -n default
esxcli network ip dns server add --server=$vCloud_dns1_1
esxcli network ip dns server add --server=$vCloud_dns2_1
esxcli network ip interface ipv4 set -i vmk1 -I $vCloud_ip_1 -N $vCloud_netmask_1 -t static
esxcli system hostname set --domain=$vCloud_suffix_1
esxcfg-route -a 10.252.0.0/16 gw $vCloud_gateway_1
esxcfg-route -a 10.12.42.0/24 gw $vCloud_gateway_1
esxcli system maintenanceMode set --enable true --timeout=1
vmkfstools -C vmfs5 -b 1m -S $vCloud_computerName /vmfs/devices/disks/mpx.vmhba1\:C0\:T0\:L0\:3
/sbin/auto-backup.sh
esxcli system shutdown reboot --reason="Updated System UUID"
esxcfg-init --set-boot-progress-text "OVF Settings applied...."
exit 0

vCloud Next Free IP

I’ve been writing a bit of automation these last few weeks and I came across a need to determine the next block of currently unassigned IP’s within vCloud Director. Those of you who use vCD will know that when you deploy an Edge vCD will automatically grab the next available IP, but I found there was no easy way to get this same information from vCD itself. Put together a little powercli script that takes as it’s input variable the name of the external network we want to query and returns an array of unassigned IP’s.

What makes this task a little more difficult is the fact that vCloud has both Assigned IP’s and Gateway IP’s. IP’s can be assigned to a gateway but not be in use (suballocated) so when determining what IP is free next we have to query both assignments and compile a single list.


function Get-FreeExtIPAddress([String]$extnetName){
$extnet = Get-ExternalNetwork -name $extnetName
$ExtNetView = $Extnet | Get-CIView

$allocatedGatewayIPs = $extnetView.Configuration.IpScopes.IpScope[0].SubAllocations.SubAllocation.IpRanges.IpRange

[int]$ThirdStartingIP = [System.Convert]::ToInt32($extnet.StaticIPPool[0].FirstAddress.IPAddressToString.Split(".")[2],10)
[int]$ThirdEndingIP = [System.Convert]::ToInt32($extnet.StaticIPPool[0].LastAddress.IPAddressToString.Split(".")[2],10)
[int]$FourthStartingIP = [System.Convert]::ToInt32($extnet.StaticIPPool[0].FirstAddress.IPAddressToString.Split(".")[3],10)
[int]$FourthEndingIP = [System.Convert]::ToInt32($extnet.StaticIPPool[0].LastAddress.IPAddressToString.Split(".")[3],10)
$octet = $extnet.StaticIPPool[0].FirstAddress.IPAddressToString.split(".")
$3Octet = ($octet[0]+"."+$octet[1]+"."+$octet[2])
$2Octet = ($octet[0]+"."+$octet[1])
$ips = @()

if ($ThirdStartingIP -eq $ThirdEndingIP) {

$ips = $FourthStartingIP..$FourthEndingIP | % {$3Octet+'.'+$_}

} else {

do {

for ($i=$FourthStartingIP; $i -le 255; $i++) {
$ips += ($2Octet + "." + $ThirdStartingIP + "." + $i)
}
$ThirdStartingIP=$ThirdStartingIP + 1

} while ($ThirdEndingIP -ne $ThirdStartingIP)
for ($i=0;$i -le $FourthEndingIP; $i++) {
$ips += ($2Octet + "." + $ThirdStartingIP + "." + $i)

}
}

$allocatedIPs = $ExtNetView.Configuration.IpScopes.IpScope[0].AllocatedIpAddresses.IpAddress

for ($i=0;$i -le $ips.count; $i++) {
for ($j=0; $j -lt $allocatedGatewayIPs.count; $j++) {
if ($ips[$i] -eq $allocatedGatewayIPs[$j].StartAddress) {
$ips = $ips | Where-Object { $_ -ne $ips[$i] }
$i--
}
}
for($z=0;$z -lt $allocatedIPs.count;$z++) {
if ($ips[$i] -eq $allocatedIPs[$z]) {
$ips = $ips | Where-Object { $_ -ne $ips[$i] }
$i--
}
}
}
return $Ips
}

Getting Started

After months and years of swearing I would never put together a blog I finally caved…..In my field it’s inevitable I think that everyone eventually develops a blog if for nothing more than to show what they do on a daily basis. The purpose of this blog is to give back to the VMware community by sharing my day to day experiences working as a Product and Operations Engineer at the largest VMware service provider. Here goes nothing……