Virtual Machine Naming During Provisioning
When we provision a virtual machine using the native provider manager - VMware vSphere or the Red Hat Enterprise Virtualization Manager for example - we must provide the name of the new virtual machine to be created. One of the benefits of a cloud management platform like CloudForms or ManageIQ is that we can partially or fully automate the creation of virtual machine names as part of the provisioning workflow.
CloudForms and ManageIQ have very flexible ways of letting us assign names to virtual machines at provisioning time, in a process known as naming. They allow us to explicitly name the VM (fine for single-VM provisioning operations), or to auto-append a zero-padded number for multi-VM provisioning requests. They also allow us to use or create a custom naming policy whereby VM names are autogenerated based on a number of factors, including a common prefix, tags, or group membership for example.
VM Name-related Provisioning Options
The naming process has several inputs, and usually two outputs. The inputs to the naming process are a number of variables and symbols that are set (and we can customise) during the provisioning dialog, or defined in the naming class schema. The outputs from the naming process are the VM name, and optionally the hostname (i.e. FQDN first part) to be applied to the VM’s operating system.
Inputs to the Naming Process
The following subsections detail the variables and symbols used as inputs to the VM naming logic.
vm_name
vm_name
is given the value from the VM Name box in Provision Virtual Machines → Catalog (see Prompting for the VM name during provisioning).
The symbol is added to the request options hash as:
miq_provision_request.options[:vm_name]
vm_prefix
vm_prefix
can be used to build a custom VM name, and is read from the vm_prefix variable in the naming instance schema (the default is "cfme", but we can define our own if required) (see Defining the vm_prefix value in the default naming instance).
Alternatively we can set a value in the request options hash:
miq_provision_request.options[:vm_prefix]
hostname
hostname
is given the value of the Host Name box in Provision Virtual Machines → Customize (see Prompting for the VM hostname during provisioning).
The symbol is added to the request options hash as:
miq_provision_request.options[:hostname]
linux_host_name
If a VMware Customization Specification for Linux is used, linux_host_name
is the specific name extracted from the template. The naming logic uses this to set the operating system hostname.
The symbol is added to the request options hash as:
miq_provision_request.options[:linux_host_name]
sysprep_computer_name
If a VMware Customization Specification for Windows is used, sysprep_computer_name
is the specific name extracted from the template. ManageIQ naming uses this as input to the sysprep process to set the NetBIOS name.
The symbol is added to the request options hash as:
miq_provision_request.options[:sysprep_computer_name]
miq_force_unique_name
miq_force_unique_name
is used internally when provisioning VMs from a service catalog. When the miq_provision task is created for the catalog item VM provision, its options hash key is set as:
miq_provision.options[:miq_force_unique_name] = [true, 1]
Outputs from the Naming Process
The symbols discussed in the following subsections are derived by the VM naming method and added to the task options hash.
vm_target_name
vm_target_name
represents the new VM name. It is added to the task options hash as:
miq_provision.options[:vm_target_name]
vm_target_hostname
vm_target_hostname
is the VM $(hostname) assigned from the output of the VM naming logic (15 characters for Windows, 63 characters for Linux). It is added to the task options hash as:
miq_provision.options[:vm_target_hostname]
Name Processing
Much of the VM naming logic happens in the Rails code that is not exposed to the Automation Engine. This code does however call the naming instance/method defined in the provisioning group profile (the vmname field), and we can use this to add our own customisations. The profile-defined naming method writes its suggested name into $evm.object['vmname']
, which is propagated back to the internal Rails method via a collect.
If the profile-defined naming method suggests a name that should be numerically suffixed (e.g. #{vm_name}$n{3}
), then the back-end Rails code will allocate the next free number in the sequence and form the VM name accordingly.
The default profile-defined naming method for Infrastructure VMs in ManageIQ Capablanca is /Infrastructure/VM/Provisioning/Naming/vmname. It is a relatively simple method, as follows:
#
# Description: This is the default vmnaming method
# 1. If VM Name was not chosen during dialog processing then use vm_prefix
# from dialog else use model and [:environment] tag to generate name
# 2. Else use VM name chosen in dialog
# 3. Then add 3 digit suffix to vm_name
# 4. Added support for dynamic service naming
#
$evm.log("info", "Detected vmdb_object_type:<#{$evm.root['vmdb_object_type']}>")
prov = $evm.root['miq_provision_request'] || \
$evm.root['miq_provision'] || \
$evm.root['miq_provision_request_template']
vm_name = prov.get_option(:vm_name).to_s.strip
number_of_vms_being_provisioned = prov.get_option(:number_of_vms)
diamethod = prov.get_option(:vm_prefix).to_s.strip
# If no VM name was chosen during dialog
if vm_name.blank? || vm_name == 'changeme'
vm_prefix = nil
vm_prefix ||= $evm.object['vm_prefix']
$evm.log("info", "vm_name from dialog:<#{vm_name.inspect}> \
vm_prefix from dialog:<#{diamethod.inspect}> \
vm_prefix from model:<#{vm_prefix.inspect}>")
# Get Provisioning Tags for VM Name
tags = prov.get_tags
$evm.log("info", "Provisioning Object Tags: #{tags.inspect}")
# Set a Prefix for VM Naming
if diamethod.blank?
vm_name = vm_prefix
else
vm_name = diamethod
end
$evm.log("info", "VM Naming Prefix: <#{vm_name}>")
# Check :environment tag
env = tags[:environment]
# If environment tag is not nil
unless env.nil?
$evm.log("info", "Environment Tag: <#{env}> detected")
# Get the first 3 characters of the :environment tag
env_first = env[0, 3]
vm_name = "#{vm_name}#{env_first}"
$evm.log("info", "Updating VM Name: <#{vm_name}>")
end
derived_name = "#{vm_name}$n{3}"
else
if number_of_vms_being_provisioned == 1
derived_name = "#{vm_name}"
else
derived_name = "#{vm_name}$n{3}"
end
end
$evm.object['vmname'] = derived_name
$evm.log("info", "VM Name: <#{derived_name}>")
If we examine this code we can start to see the logic that the virtual machine naming methods use to determine names. There are two main conditions, as follows.
Provisioning a Single VM or Instance
Provisioning a single VM from either Infrastructure → Virtual Machines → Lifecycle → Provision VMs or from a service catalog will result in the VM being given the value of :vm_name
, unless :vm_name
is blank or has the value "changeme". If :vm_name
is blank or "changeme" then we loop through the logic in the Automation Engine naming method, which assembles a VM name by combining the value of :vm_prefix
with the first 3 characters of the :environment
tag (if it exists), and appending three zero-padded digits.
Provisioning Multiple VMs or Instances in a Single Request
Provisioning multiple servers from a service catalog will result in the symbol :miq_force_unique_name
being set to true for each task. If :vm_name
is not blank or "changeme", then the servers will be named as :vm_name
with "_n{4}" appended, e.g. server_0001, server_0002, etc. according to the logic in the internal Rails class MiqProvision::Naming
. In this scenario the profile-defined naming method is not used.
Provisioning multiple servers from Infrastructure → Virtual Machines → Lifecycle → Provision VMs will not result in :miq_force_unique_name
being set to true, and the VM naming logic in the profile-defined naming method will apply. The servers will be given the value of :vm_name
, appended by three zero-padded digits, for example server001, server002, etc.
Customising the Naming Process
We often wish to customise the naming process to our own requirements. For example we might wish to name all servers using a fixed prefix (:vm_prefix
), followed by the value of the server_role tag, followed by a zero-padded digit extension. We can do this using a slight modification of the profile-defined naming method, in conjunction with tagging the servers that we wish to special-case:
...
prefix = prov.get_option(:vm_prefix).to_s.strip
#
# Special case the any servers tagged with "server_role" - pemcg
#
# Get Provisioning Tags for VM Name
tags = prov.get_tags
#
# Check :server_role tag
#
server_role = tags[:server_role]
unless server_role.nil?
derived_name = "#{prefix}#{server_role}$n{2}"
$evm.object['vmname'] = derived_name
$evm.log("info", "#{@method} - VM Name: <#{derived_name}>") if @debug
#
# Exit method
#
$evm.log("info", "#{@method} - EVM Automate Method Ended")
exit MIQ_OK
end
#
# End of special case for servers tagged with "server_role"
#
...
We can do this by copying the /Infrastructure/VM/Provisioning/Naming/default instance and /Infrastructure/VM/Provisioning/Naming/vmname method into our own domain, and editing the schema or method accordingly.
Summary
As we have seen, the naming process for virtual machines is very flexible, and allows us to create a custom naming scheme for our cloud or virtual infrastructure. The naming logic is called during the processing of the group profile during provisioning, so different user groups can have entirely different VM naming schemes if we wish.
We have also seen that the naming process generates operating system hostnames as well as the virtual machine names. Setting a hostname is an operating system (rather than virtual machine container) function, so we must pass this value to some other process for it to be set.
If we are PXE booting our new Red Hat virtual machines and performing a kickstart installation, then we can inject the hostname value into the kickstart script at run-time. If we are provisioning from fully configured templates then we need to use a VMware customization specification or cloud-init script to perform the hostname injection.