VMWare vSphere Customize linux guest with a shell script

If you read my previous post about guest optimization, you should see how can you customize your Windows or Linux guest with a modified vmclone.pl script. However, it can’t be used for all cases. It is because vmclone.pl will call the guest customization function in the vSphere environment which is not available for all distributions (Debian, for example) and it has some limitations. (like you cannot set the root password for Linux guests)

Fortunately, there is a solution for this case. The point is that you can use a shell script inside your guest template and after the deployment and boot up, you can call that shell script via Perl SDK. For that, you can use a Perl script written by lamw (as usually, he is one of the best in vSphere automatization :)) and it will fire up the shell script which make your desired settings. Let see how it works step by step:

  1. Select your template which you want to be customizable and convert into VM. I assume you know your login information.
  2. Write the shell script and put it into your root folder. Name it customization.sh You can download my example for Debian at the end of this post. Make it executable. (chmod +x /root/customization.sh)
  3. There are five parameters that you need to pass: The guest’s hostname, domain name, IP address, default gateway and the root password. You will need to pass this parameters to the shell script at this order.
  4. Optional, but strongly suggested step: Make a second copy from this VM and try this shell script on there. (Point 9) If it changes these five parameters successfully and removes itself, then you can use it in your live template VM.
  5. Convert back your VM into template.
  6. Download guestOpsManagement.pl from here. This script has written by lamw, so all credits belongs to him. You should read his full documentation about this Perl script’s functions and parameters in his post here.
  7. Put the file into your Perl SDK vm app directory, which is /usr/lib/vmware-vcli/apps/vm for default. Make it executable. (chmod +x /usr/lib/vmware-vcli/apps/vm/guestOpsManagement.pl)
  8. Deploy your template as you did usually, then power it on. Wait few minutes to make sure it is booted up.
  9. Call the guestOpsManagement.pl script which will make your changes, then remove itself and reboot the guest:
/usr/lib/vmware-vcli/apps/vm/guestOpsManagement.pl --username "username@vcenter.server.domain" --password "vCenter password" --server "vcenter.host.domain" --vmname "your-vm-name" --operation startprog --guestusername "root" --guestpassword "CurrentRootPass" --working_dir "/root" --program_path "/root/customization.sh" --program_args "'newhostname' 'newdomain.tld' 'newip' "newdefgw' 'newrootpass'"

That is all. If everything went well, then your new IP settings and root password has been set into the Linux guest. Anyway, here is some tip and trick about the shell script:

  • In line 17, it will change the existing hostname to the new one, so you need to rewrite Debian-template to the hostname that you provided via the template installation. Otherwise your /etc/hosts file will be broken.
  • The guestOpsManagement.pl script will log in to the guest VM as root, hence you need to know your existing root password and provide it to the script. (as you seen in the example command) Root login must also allowed.
  • Beware! In the (quite) new distribution (like Debian 9 and RHEL 7) udevd and systemd assign predictable interface names (like ens160 and eno 192) instead of ethx. You have two options: Disable it somehow in your template or simply modify my shell script. Of course, the second option is easier, just change the interface names in line 27 and 28.
  • The network settings will not work in RHEL distributions, so my script will need a modification. I might update this post with another examples. 🙂
  • Make sure that all of the necessary commands are installed into your guest template. If sed, or anything else is missing, the script will fail.
  • You can make some additional changes in my script, of course. More options, more customizations are available. 🙂

The shell script will work fine in every distribution (read my notices above) and I tested guestOpsManagement.pl in vSphere 6.5 environtment, but I’m pretty sure that this will work from 5.0 and above versions as well.

The customization.sh script example for Debian (and Ubuntu) distributions:

# Debian based script after the VM deployment
# (C) by Mr.Zsolt

# Input variables

# Change hostname
echo $HOSTNAME > /etc/hostname

# Change domain
sed -i '/Debian-template/c\'"$IP"'\t'"$DOMAINSUFFIX"'\t'"$HOSTNAME"'' /etc/hosts

# Make the interfaces file
echo "# This file describes the network interfaces available on your system" > /etc/network/interfaces
echo "# and how to activate them. For more information, see interfaces(5)." >> /etc/network/interfaces
echo "" >> /etc/network/interfaces
echo "# The loopback network interface" >> /etc/network/interfaces
echo "auto lo" >> /etc/network/interfaces
echo "iface lo inet loopback" >> /etc/network/interfaces
echo "" >> /etc/network/interfaces
echo "allow-hotplug eth0" >> /etc/network/interfaces
echo "iface eth0 inet static" >> /etc/network/interfaces
echo "  address $IP" >> /etc/network/interfaces
echo "  netmask" >> /etc/network/interfaces
echo "  gateway $GATEWAY" >> /etc/network/interfaces

# Change root password
usermod --password $(echo $NEWPASS | openssl passwd -1 -stdin) root

# Remove myself
rm -rf /root/customization.sh

# Reboot when done

VMWare vSphere 6.x Customize linux guest IP address via Perl SDK

I must confess that I like the VSphere’s Perl SDK while I set some automatization job, but one of its bottleneck is the purely wrote example scripts. If you would like to deploy a template, you should use vmclone.pl with its functions and you will be done. It is great but what about the VM’s network settings? If you deploy a Windows guest, you can set up the network via vmclone.pl of course, but you need to enter it into a domain. What about deploying a Linux server? you are out of luck, because you cannot set up the networking.

After digging into the web, I found vmclone2.pl which seems to be useful, but it was wrote at 2010, and its biggest problem is that will not work on VSphere 6.x environment and it is only useful for Linux VM deploying. As far as I know, you are out of options, so if you would like to customize your Windows (without entering into domain) and Linux guest in the same script, you need to write your own Perl code…

… Until now, because I wrote it already. 🙂 Let me explain how it works. My concept was the same as in vmclone2.pl The Perl script itself (vmclone.pl) only need some little modifications, because it just calls some functions. Hence most of VMUtil.pm functions need to be rewritten. In the original VMUtil.pm the Windows servers has been entered into a domain. I just disabled this function, because in most cases, you will use as a standalone server and you can enter it into domain later. Most of the original values in the schema was also untouched, and I also added some new. Here is the description for all values:

  • Cust-Type (new value): It should be win or lin. It determines the VM type, it is quite obvious. lin for Linux guests, win for Windows guests.
  • Machine-Name (old value): The virtual machine’s hostname.
  • Timezone (old value): Timezone for Windows guests. It must be a timezone code. You can find yours here.
  • Linux-Timezone (new value): Timezone for Linux guests. It must be a valid tz value. You can find yours here.
  • UTC-Clock (new value): It determines that your clock is set to UTC or not. This value should be 0 or 1.
  • Password (old value): The Administrator user’s password. It will be applied in Windows guests, I didn’t find an option to set it as a root password for Linux. (Anyway, is that possible?)
  • Full-Name (old value): The Windows guest owner’s full name.
  • Orgnization-Name (old value): The Windows guest owner’s company.
  • ProductId (old value): The Windows guest’s serial number. Beware! It MUST be a valid product key. If you type something wrong, your VM will not boot up.
  • IP0 (old value): The IP address for the VM.
  • IP0Gateway (old value): The default gateway for the VM.
  • IP0dnsServers (old value): The DNS server (resolver) address(es) for the VM. Separate them with colons, you can set up 1-3 in Linux guests, and 2 in Windows guests.
  • IP0Subnet (old value): The netmask for the VM. CIDR mask cannot be used here!
  • IP0dnsDomain (old value): The DNS suffix for the VM.

Assumed that you installed VSphere Perl SDK in the default place, you should put my VMUtil.pm into /usr/lib/vmware-vcli/apps/AppUtil and vmclone.pl into /usr/lib/vmware-vcli/apps/vm
I have uploaded the Perl scripts as TXT files because of security reasons, you should rename them back as it was originally. Make backup for your files first, then overwrite them with my versions.

The last two things you need to set up is the schema (vmclone.xsd) file and the data (vmclone.xml) file. They are pretty simple, almost looks like the originals.

The schema file (vmclone.xsd)

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- definition of simple elements -->
<xs:element name="Cust-Type" type="xs:string"/>
<xs:element name="UTC-Clock">
<xs:restriction base="xs:integer">
<xs:enumeration value="0"/>
<xs:enumeration value="1"/>
<xs:element name="Machine-Name" type="xs:string"/>
<xs:element name="Timezone" type="xs:integer"/>
<xs:element name="Linux-Timezone" type="xs:string"/>
<xs:element name="Password" type="xs:string"/>
<xs:element name="Full-Name" type="xs:string"/>
<xs:element name="Orgnization-Name" type="xs:string"/>
<xs:element name="ProductId" type="xs:string"/>
<xs:element name="IP0" type="xs:string"/>
<xs:element name="IP0Gateway" type="xs:string"/>
<xs:element name="IP0dnsServers" type="xs:string"/>
<xs:element name="IP0Subnet" type="xs:string"/>
<xs:element name="IP0dnsDomain" type="xs:string"/>
<!-- definition of complex elements -->
<xs:element name="Customization-Spec">
<xs:element ref="Cust-Type"/>
<xs:element ref="Machine-Name"/>
<xs:element ref="Timezone"/>
<xs:element ref="Linux-Timezone"/>
<xs:element ref="UTC-Clock"/>
<xs:element ref="Password"/>
<xs:element ref="Full-Name"/>
<xs:element ref="Orgnization-Name"/>
<xs:element ref="ProductId"/>
<xs:element ref="IP0"/>
<xs:element ref="IP0Gateway"/>
<xs:element ref="IP0dnsServers"/>
<xs:element ref="IP0Subnet"/>
<xs:element ref="IP0dnsDomain"/>
<xs:element name="Specification">
<xs:element ref="Customization-Spec" maxOccurs="1"/>

The data file when we want to deploy a windows guest (vmclone.xml)

<?xml version="1.0"?>
<Full-Name>Owner name</Full-Name>
<Orgnization-Name>Owner company</Orgnization-Name>

The data file when we want to deploy a linux guest (vmclone.xml)

<?xml version="1.0"?>
<Full-Name>Owner name</Full-Name>
<Orgnization-Name>Owner company</Orgnization-Name>

Put these files somewhere, and try to clone a template into VM. The command is the same as that you should use in vmclone:

/usr/lib/vmware-vcli/apps/vm/vmclone.pl --username "vcuser" --password "vcpass" --server "vcenterip" --datastore "clonefromandtohere" --vmhost "clonefromhost" --vmname "clonefromvm" --vmname_destination "clonetovm" --customize_guest yes --filename "vmclone.xml" --schema "vmclone.xsd"

I have tried this in VSphere 6.0 and 6.5 environment and works great as I expected.