After we finish the installation process, a directory with a set of files gets created in our installation location. For example, in our VM, a directory called
c:\Program Files\Cloudbase Solutions\Cloudbase-init\ was created, and it has the following set of subdirectories:
bin: The location where some of the binary files are installed, such as
mdir, and so on.
conf: The location of three main configuration files that we’re going to work with, which is discussed a bit later.
LocalScripts: The default location for PowerShell and similar scripts that we want to run post-boot.
Log: The location where we’ll store the
cloudbase-initlog files by default so that we can debug any issues.
Python: The location where local installation of Python is deployed so that we can also use Python for scripting.
Let’s focus on the
conf directory, which contains our configuration files:
The way that
cloudbase-init works is rather simple – it uses the
unattend.xml file during the Windows sysprep phase to execute
cloudbase-init with the
cloudbase-init-unattend.conf configuration file. The default
cloudbase-init-unattend.conf configuration file is easily readable, and we can use the example provided by the
cloudbase-init project with the default configuration file explained step by step:
[DEFAULT] # Name of the user that will get created, group for that user username=Admin groups=Administrators firstlogonbehaviour=no inject_user_password=true # Use password from the metadata (not random).
config_drive_raw_hhd=true config_drive_cdrom=true # Path to tar implementation from Ubuntu. bsdtar_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\bsdtar.exe mtools_path= C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\
We need to configure some settings for logging purposes as well:
# Logging level verbose=true debug=true # Where to store logs logdir=C:\Program Files (x86)\Cloudbase Solutions\Cloudbase-Init\log\ logfile=cloudbase-init-unattend.log default_log_levels=comtypes=INFO,suds=INFO,iso8601=WARN logging_serial_port_settings=
The next part of the configuration file is about networking, so we’ll use DHCP to get all the networking settings in our example:
# Use DHCP to get all network and NTP settings mtu_use_dhcp_config=true ntp_use_dhcp_config=true
We need to configure the location where the scripts are residing, the same scripts that we can use as a part of the
# Location of scripts to be started during the process local_scripts_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\LocalScripts\
The last part of the configuration file is about the services and plugins to be loaded, along with some global settings, such as whether to allow the
cloudbase-init service to reboot the system or not and how we’re going to approach the
cloudbase-init shutdown process (
false=graceful service shutdown):
# Services for loading metadata_services=cloudbaseinit.metadata.services.configdrive.ConfigDriveService, cloudbaseinit.metadata.services.httpservice.HttpService, cloudbaseinit.metadata.services.ec2service.EC2Service, cloudbaseinit.metadata.services.maasservice.MaaSHttpService # Plugins to load plugins=cloudbaseinit.plugins.common.mtu.MTUPlugin, cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin # Miscellaneous. allow_reboot=false # allow the service to reboot the system stop_service_on_exit=false
Let’s just get a couple of things out of the way from the get-go. Default configuration files already contain some settings that were deprecated, as you’re going to find out soon enough. Specifically, settings such as
logfile are already deprecated in this release, as you can see from the following screenshot, where
cloudbase-init is complaining about those very options:
If we want to start sysprepping with
cloudbase-init by using the default configuration files, we are actually going to get a pretty nicely configured VM – it’s going to be sysprepped, it’s going to reset the administrator password and ask us to change it with the first login, and remove the existing administrator user and its directories. So, before we do this, we need to make sure that we save all of our administrator user settings and data (documents, installers, downloads, and so on) someplace safe. Also, the default configuration files will not reboot the VM by default, which might confuse you. We need to do a manual restart of the VM so that the whole process can start.
The easiest way to work with both
cloudbase-init is by writing down a scenario of what needs to be done to the VM as it gets through the initialization process. So, we’ll do just that – pick a load of settings that we want to be configured and create a customization file accordingly. Here are our settings:
- We want our VM to ask us to change the password post-sysprep and after the
- We want our VM to take all of its network settings (the IP address, netmask, gateway, DNS servers, and NTP) from DHCP.
- We want to sysprep the VM so that it’s unique to each scenario and policy.
So, let’s create a
cloudbase-init-unattend.conf config file that will do this for us. The first part of the configuration file was taken from the default config file:
[DEFAULT] username=Admin groups=Administrators inject_user_password=true config_drive_raw_hhd=true config_drive_cdrom=true config_drive_vfat=true bsdtar_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\bsdtar.exe mtools_path= C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\ debug=true default_log_levels=comtypes=INFO,suds=INFO,iso8601=WARN logging_serial_port_settings= mtu_use_dhcp_config=true ntp_use_dhcp_config=true
The rest of the file was also just copied from the default configuration file:
metadata_services=cloudbaseinit.metadata.services.base.EmptyMetadataService plugins=cloudbaseinit.plugins.common.mtu.MTUPlugin, cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin, cloudbaseinit.plugins.common.localscripts.LocalScriptsPlugin,cloudbaseinit.plugins.common.userdata.UserDataPlugin allow_reboot=false stop_service_on_exit=false
As for the
cloudbase-init.conf file, the only change that we made was selecting the correct local script path (reasons to be mentioned shortly), as we will use this path in our next example:
[DEFAULT] username=Admin groups=Administrators inject_user_password=true config_drive_raw_hhd=true config_drive_cdrom=true config_drive_vfat=true
bsdtar_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\bsdtar.exe mtools_path= C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\ debug=true
This part of the config file was also taken from the default config file, and we only changed
local_scripts_path so that it’s set to the directory that we’re using to populate with PowerShell scripts:
first_logon_behaviour=no default_log_levels=comtypes=INFO,suds=INFO,iso8601=WARN logging_serial_port_settings= mtu_use_dhcp_config=true ntp_use_dhcp_config=true local_scripts_path=C:\PS1
Now, let’s take this a step further and complicate things a bit. Let’s say that you want to do the same process, but with additional PowerShell code that should do some additional configuration. Consider the following example:
- It should create another two local users called
packt2, with a predefined password set to
- It should create a new local group called
students, and add
packt2to this group as members.
- It should set the hostname to
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force $password = "Pa$$w0rd" | ConvertTo-SecureString -AsPlainText -Force New-LocalUser -name "packt1" -Password $password New-LocalUser -name "packt2" -Password $password New-LocalGroup -name "Students" Add-LocalGroupMember -group "Students" -Member "packt1","packt2" Rename-Computer -NewName "Server1" -Restart
Taking a look at the script itself, this is what it does:
- Sets the PowerShell execution policy to unrestricted so that our host doesn’t stop our script execution, which it would do by default.
- Creates a password variable from a plaintext string (
Pa$$w0rd), which gets converted to a secure string that we can use with the
New-LocalUserPowerShell cmdlet to create a local user.
New-LocalUseris a PowerShell cmdlet that creates a local user. Mandatory parameters include a username and password, which is why we created a secure string.
New-LocalGroupis a PowerShell cmdlet that creates a local group.
Add-LocalGroupMemberis a PowerShell cmdlet that allows us to create a new local group and add members to it.
Rename-Computeris a PowerShell cmdlet that changes the hostname of a Windows computer.
We also need to call this code from
cloudbase-init somehow, so we need to add this code as script. Most commonly, we’ll use a directory called
LocalScripts in the
cloudbase-init installation folder for that. Let’s call this script
userdata.ps1, save the content mentioned previously to it in the folder, as defined in the
.conf file (
c:\PS1), and add a
cloudbase-init parameter at the top of the file:
# ps1 $password = "Pa$$w0rd" | ConvertTo-SecureString -AsPlainText -Force New-LocalUser -name "packt1" -Password $password New-LocalUser -name "packt2" -Password $password New-LocalGroup -name "Students" Add-LocalGroupMember -group "Students" -Member "packt1","packt2" Rename-Computer -NewName "Server1" –Restart
After starting the
cloudbase-init procedure again, which can be achieved by starting the
We can clearly see that the
packt2 users were created, along with a group called
Students. We can then see that the
Students group has two members –
packt2. Also, in terms of setting the server name, we have the following:
cloudbase-init really isn’t simple, and requires a bit of investment in terms of time and tinkering. But afterward, it will make our job much easier – not being forced to do pedestrian tasks such as these over and over again should be a reward enough, which is why we need to talk a little bit about troubleshooting. We’re sure that you’ll run into these issues as you ramp up your
It will gives you output similar to below:
It will gives you output similar to below:
It will gives you output similar to below: