Cloud-init – Part 3 – Photon OS

In Part 1 and Part 2 of this series we used Ubuntu as the guest OS of our target instances. In Part 3 we will show how to use VMware’s Photon OS as our guest OS.

The main reason to use Photon OS is that it is open-sourced, it has a small footprint and it is optimised for VMware vSphere.

Some Background

Does this mean that Photon OS is the ideal guest OS for our ‘cattle‘ stations where we want to run our PowerShell scripts?

Not really, the major flaw with Photon OS, imho, is that the available packages are limited and rather infrequently maintained.

In fact, until recently the available PowerShell package was an outdated, not supported anymore version. But the worst part of the deal, it didn’t even allow to perform an Install-Module. Which, again imho, is a basic concept in PowerShell. And which didn’t allow me to install, for example, VMware PowerCLI on a Photon station.

But then recently this happened!

The available PowerShell v6 TDNF package was upgraded to a currently supported version, and more importantly, the Import-Module cmdlet  worked! 

Allowing us to install VMware PowerCLI on a Photon instance.

Is this the end of all the PowerShell woes on Photon OS?

Not really! The PowerShell version in this TDNF package will also run out of support in a not so far future and a PowerShell TDNF package upgrade is (still) not automated and somewhat of a black art.

But for now, let’s be happy with what we have and ‘cloud-init’ our Photon ‘cattle’ station!

Issues and some Solutions

No UserData Property

While the Ubuntu cloud image, as we saw in Part 1 of the series, has the option to pass the user-data to cloud-init via an OVF property, this feature is unfortunately not available in the Photon OVA.

There are some solutions available.

  • Roll your own OVA image
  • Use the NoCloud option, which means creating an ISO containing the user-data and attaching this ISO to the instance before cloud-init runs.

Since I prefer to use the ‘standard’ OVA, I opt for creating such a seed ISO.

The Root Password

This is somewhat of a chicken-and-the-egg dilemma.

In the Photon OVA image, the root account is set to force a password change on first use. But unfortunately, this also disallows setting the root password via the user-data. See Issue#931 for more details.

Again, there are two options available.

  • Roll your own OVA image
  • Use a two-stage process, wherein the first stage we use William Lam‘s Set-VMKeystrokes function. Then in the second stage, we attach the seed ISO and start the instance. And thus kicking off the cloud-init process.

And again, since I prefer to use the ‘standard’ OVA, I opt for the Set-VMKeystrokes solution.

Install-CloudInitVM Revisited



The v1.0 version of this function has already been annotated in Part 1 of this series. Those annotations will not be repeated here.

Line 68-71: To distinguish between the way the user-data is passed, the function now has two mutually exclusive parameters, CloudConfig and CloudConfigIso.

Line 73: Since Photon requires some special actions, the function now has a switch, obviously named Photon, that specifies if the cloud-init deployment is intended for a Photon instance or not.

Line 77-80: When the user-data is provided as a YAML file, the function reads the file.

Line 83-86: A small reminder in the verbose output that the function will handle this as a Photon deployment.

Line 102-110: The Ubuntu and the Photon OVA files have different OVF properties. This If-Then-Else handles the differences.

Line 126-199: This part of the function handles most of the peculiarities of a Photon deployment.

Line 136-175: This part handles the reset of the root password. As mentioned earlier, it uses William’s Set-VMKeystrokes function. I experienced intermittent race conditions in sending the keystrokes. Hence the loop with the retries. As a test, to check if the root password was reset, the command ‘whoami‘ is executed trough Invoke-VMScript on the instance.

Line 179-184: Before attaching the seed ISO, the Photon OS is shutdown gracefully. In a While-loop the script test until the instance is actually powered off.

Line 188-195: The seed ISO is copied to the VM’s folder, and then attached.

Line 198: The VM is started with the seed ISO attached. As a result, cloud-init will now use the YAML files it finds on the CD drive as datasource.

Line 216-221: Since the cloud-init implementation on Photon is not configured to use the power-state module, the test we used on the Ubuntu instance, can not be used for Photon. As a bypass, the function stops/starts the guest OS on the instance.

Line 235-244: The function uses the stop/start sequence to disconnect the seed ISO. To avoid having a question on the VM, the function first runs the ‘eject cdrom‘ command inside the instance.

The Seed ISO

As mentioned earlier, I prefer to use a seed ISO file to solve the issue of not having an OVF property for the user-data.

To create this seed ISO file, we need a Linux station that has the ‘genisoimage‘ command available. In the following sample script, I use an Ubuntu station just for that purpose.


Line 4-7, 16-18: The script converts (copies) the provided YAML files to standard named YAML files. This allows the script to be used with different versions of the data and only needs a change in the $isoFiles hash table.

Line 32: This script uses the latest version of my Invoke-VMScriptPlus function. The reason is twofold: the bash script is multi-line and the script used the InFile/OutFile parameters to copy the YAML files to the Linux box and the ISO file back to the calling station.


The user-data that is used for a Photon based instance is, for now, rather simple and straightforward.

Note the installation of the tdnf PowerShell package (as mentioned earlier in this post) in the runcmd section.


If you plan on deploying multiple instance, just make sure that the instance-id has a unique value.

Sample Run

For a Photon instance the function is called like this.

The result of this, since we used the Verbose switch, looks like this.

Again, don’t give too much importance to the total execution time. This was a run in my lab environment, which has limited resources.

On a side-note, notice how the PowerCLI cmdlets used in the function all show this, imho, annoying ‘Finished execution‘ message.
I would love to be able to suppress these verbose messages from the PowerCLI cmdlets. That is why I launched PowerCLI Idea #225Get rid of the over-eager verbosity on PowerCLI cmdlets“.


Leave a Reply

Your email address will not be published. Required fields are marked *


This site uses Akismet to reduce spam. Learn how your comment data is processed.