Tweet This: Tweet
Share on LinkedIn:
By Dana Gertsch, Kovarus Senior Consultant
The following article demonstrates how to use Cloudbase-Init in a VMware vRealize Automation Cloud (vRA Cloud) blueprint.
The customer use case called for the following without using any external orchestration tools (vRO / ABX):
- Add a new user to the local admin group.
- Enable RDP.
- Set a static IP address, subnet, gateway, and DNS settings.
- Automatically format all of the attached disks.
- Set the OS hostname.
- Set the OS time zone.
- Disable IPv6 on the primary interface.
I’ll admit that I tinkered with Cloudbase-Init a few times in the past, generally without success. However, something clicked with this attempt.
First I built a basic Windows 2019 server, installed VMware Tools then followed the directions on this blog article to install and configure cloudbase-init. I used version 1.1.1 for this example.
Then I reconfigured the machine to allow for CD-ROM passthrough, converted it to a template and let vRA Cloud discover it. Then added a new Image Mapping and updated the Flavor Mappings.
I wanted to use PowerShell to meet the customers’ requirements. Looking at userdata in the documentation indicated I could just add #ps1 or #ps1_sysnative to my CloudConfig. Of course, it wasn’t that easy.
Adding #ps1_sysnative under CloudConfig resulted in failures when deploying the machine. Here is a very basic broken example. (Don’t do this!)
cloudConfig: | #cloud-config write_files: content: cloudbase-init test path: c:\test.txt #ps1_sysnative New-NetIpAddress -InterfaceAlias Ethernet0 -IPAddress ${input.ipaddr} -PrefixLength ${input.subnetMask} -DefaultGateway ${input.gateway}
Looking at C:\Program Files\Cloudbase Solutions\Cloudbase-init\log\cloudbase-init.log I found C:\Program Files\Cloudbase Solutions\Cloudbase-init\Python\lib\site-package\cloudbaseinit\plugins\common\userdata.py was throwing errors when parsing userdata.
When in doubt, reverse engineer. So, looking at this script, I found it was looking for either #cloud-config or Content-Type: multipart in the header.
After some digging, I found an old Cloud-Init multipart example. Copying a portion of the sample into my blueprint worked. Now to flesh it out.
After some tinkering and testing, I finally came up with a Cloudbase-Init configuration that met the customer’s requirements.
cloudConfig: | Content-Type: multipart/mixed; boundary="===123456789" MIME-Version: 1.0 --===123456789 Content-Type: text/cloud-config; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="cloud-config" set_timezone: US/Pacific set_hostname: ${input.hostname} --===123456789 Content-Type: text/x-shellscript; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="doPsStuff.ps1" #ps1_sysnative New-NetIpAddress -InterfaceAlias Ethernet0 -IPAddress ${input.ipaddr} -PrefixLength ${input.subnetMask} -DefaultGateway ${input.gateway} Set-DnsClientServerAddress -InterfaceAlias Ethernet0 -ServerAddresses("${input.dnsServer}") Set-DnsClient -InterfaceAlias Ethernet0 -ConnectionSpecificSuffix "${input.dnsSuffix}" Set-DnsClientGlobalSetting -SuffixSearchList @("${input.dnsSuffix}") Get-Disk | Where-Object PartitionStyle -Eq "RAW" | Initialize-Disk -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume Disable-NetAdapterBinding -InterfaceAlias "Ethernet0" -ComponentID ms_tcpip6 Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False Set-Service -Name TermService -StartType Automatic -Status Running Set-Service -Name UmRdpService -Status Running Set-Service -Name SessionEnv -Status Running Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server'-name "fDenyTSConnections" -Value 0 $password = ConvertTo-SecureString ${input.newUserPassword} -AsPlainText -Force $newUser = New-LocalUser -Name "${input.newUser}" -Password $password -FullName "CAS Added Admin User" -Description "CAS Added Admin User" Add-LocalGroupMember -Group "Administrators" -Member "${input.newUser}"
Now to prove it worked. After deploying the machine and logging in as the new admin user (casadminuser) via RDP, you can see the machine name (dg-test1206), assigned IP information (10.44.14.206), and a formatted and mounted data disk (E:).
And that IPv6 has been disabled.
Some notes about this solution.
- The boundary set in the header needs to be prepended with “‐‐” and match the value in the header. Here is used ===123456789. Each part starts with ‐‐===123456789.
- The initial article published by VMware has you set first_logonbehavior to always. This forces you to change the administrator’s password on first boot. The new admin user will need to update the password to protect the console.
- Using a static IP in Cloudbase bypasses the pool assigned to the network in vRA Cloud.
- This is also true if you are using an external IPAM solution.
The working blueprint containing the multipart Cloudbase configuration is available on this GitHub repository.
I hope this provides another building block to help you use vRA Cloud.
Looking to learn more about modernizing and automating IT? We created the Kovarus Proven Solutions Center (KPSC) to let you see what’s possible and learn how we can help you succeed. To learn more about the KPSC go to the KPSC page.
Also, follow Kovarus on LinkedIn for technology updates from our experts along with updates on Kovarus news and events.