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 from here. 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:

    /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'”

    and it will make your changes, then remove itself and reboot the guest.

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.

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.


VMWare vSphere 6.x How to get remote console for your customers without vcenter login

As a hosting provider’s systems engineer, I had the task to give console access to our customer’s virtual machines. Because we built our vSphere network infrastructure to a private network of course, therefore we did not give vCenter access to our customers directly, they have a separated public management server and web interface which connects to this private network. Between the public user interface and private network, we are using the vSphere Perl SDK to manage customer commands. (like deploy vm, poweron, poweroff, …)

I’m pretty sure this scenario is familiar most of you who works in hosting environment, so the only one question is, how to set up the console and give it to the customers? You have plenty of options available, but most of them did not work by the way. 🙂

First and imho the best option was the pre-authenticated console. Lamw has a very good how to about this. I must confess, I have used this solution. The only problem is that this does not work in vCenter 6.0 and above. You can see in the post’s comments, the authentication has been removed by VMWare. and when you try to use pre-authenticated console, it will redirect you back to vCenter login page. I spent many days to find a way to bypass this block, there are some useful information in the VMWare community portal how to get the Jsession ID and use it, but after a lot of trying it leads me to a dead route.

Second option is to use vSphere’s HTML5 console, which can be download via my vmware portal. It is the officially developed console. You can customize it as much as you want, and you can also integrate it into your customer portal… But only in theory… Vittoriop has wrote a how to use this thing, but it did not work for me either. I had plenty of problems with it. First, the console could not have made the connection to my ESXi host, no matter which way and how I try. There was also a lot of javascript errors too which can’t be handled at all, so I realized it is a dead route too.

The third and finally working option for me is the VNC console. The concept to make this work looks like this:

  1. Open some ports for VNC in your ESXi machines
  2. Set up the VNC port, password in your virtual machine
  3. Integrate a web VNC and a proxy (noVNC in my case) into the customer interface code

Okey, let me show you how it works in practice:

First of all, log in to your vCenter server or ESXi hypervisor. Select your ESXi host (hosts and clusters) and under Configure tab, under System box, select Security profile. In the firewall section, select edit, then look for gdbserver and tick the checkbox, then click ok.

This will open the firewall ports from 1000 – 9999 and from 50000 to 50999 which can be used to configure VNC ports in the VM configurations. Optionally, you can set the allowed IP addresses for extra security. Only your customer manager server’s internal IP address need to be allowed.

After you finished it, the firewall ports will opening. Now the virtual machines must be set, to listen for VNC requests. To do this, select one of your VM, be sure it has turned off state.  Select Configure tab, under Settings box, VM Options. Click to edit, drop down to Advanced, then click Edit configuration. You will see the Name and Value boxes in the bottom. Add each of this three name and value pair:

Name: RemoteDisplay.vnc.enabled Value: true
Name: RemoteDisplay.vnc.port Value: 50011
Name: RemoteDisplay.vnc.password Value: yoursecuretpassword

Then click ok to save the settings. Now you can power on your virtual machine.

At this point, you can fire up you VNC client (Tight VNC or anything that you like) and test these settings. Connect to your ESXi server’s IP address and the dedicated port which you set up above in the VM. The VNC client should ask your password, give it. If everything went fine, you will see your VM up and running.

Of course, you can automate this procedure using lamw’s vmAdvSettings.pl script. This script written to vSphere Perl SDK (which I use in unix environtment) but I’m pretty sure you can find example scripts for this task to Java or C# SDK. The script works as any other vSphere Perl SDK script, but I give you some examples for this case:

./vmAdvSettings.pl --username "username@vcenter.server.domain" --password "vCenter password" --server "vcenter.host.domain" --vmname "your-vm-name" --operation "update" --key "RemoteDisplay.vnc.enabled" --value "true"
./vmAdvSettings.pl --username "username@vcenter.server.domain" --password "vCenter password" --server "vcenter.host.domain" --vmname "your-vm-name" --operation "update" --key "RemoteDisplay.vnc.port" --value "50011"
./vmAdvSettings.pl --username "username@vcenter.server.domain" --password "vCenter password" --server "vcenter.host.domain" --vmname "your-vm-name" --operation "update" --key "RemoteDisplay.vnc.password" --value "yoursecretpassword"

Almost done, you just need to download a VNC proxy, which will connect to the VM’s VNC port as you tested it below. Because you need to give something to your customers too, it should be a nice web access VNC coded in HTML5. Good news, noVNC have both in one. Of course, you can use anything else you want, but I made my decision to use noVNC.

In the example, I assume you are using one of the Linux systems (RHEL or Debian based are both good) for your customer manager portal, which has a network access to the public internet where your customers can reach it, and a private network where it can reach you vSphere system. I also assume that your webapp which your customers see via your public domain installed to /var/www/html

First of all, download noVNC from https://github.com/novnc/noVNC/archive/master.zip and unzip it into your webapp dir into a separated folder. (In my example, to: /var/www/html/novnc) noVNC has a websockify proxy which will handle the requests between the HTML5 VNC console and the VM. Start it first:

/var/www/html/novnc/utils/websockify/run -D --web /var/www/html/novnc/ 6011 esxi.host.domain:50011

The last part, connect to the websockify process with noVNC. You need to call the right URL, nothing more: http://customer.manager.public.domain:6011/vnc.html?autoconnect=true&host=customer.manager.public.domain&port=6011&password=yoursecretpassword

That is all, if you see your VM up and running, then you made everything fine.

This solution is tested in 6.0 and 6.5 environments, everything works perfectly. No ticket or jsession id hacks, so I think it is the clearest way to make it.