request.options[:addr_mode] = ["static", "Static"] (type: Array)
request.options[:cluster_filter] = [nil, nil] (type: Array)
request.options[:cores_per_socket] = [1, "1"] (type: Array)
request.options[:current_tab_key] = customize (type: Symbol)
request.options[:customization_template_script] = nil
request.options[:customize_enabled] = ["disabled"] (type: Array)
request.options[:delivered_on] = 2015-06-05 07:33:20 UTC (type: Time)
request.options[:disk_format] = ["default", "Default"] (type: Array)
request.options[:initial_pass] = true (type: TrueClass)
request.options[:ip_addr] = nil
request.options[:linked_clone] = [nil, nil] (type: Array)
request.options[:mac_address] = nil
request.options[:miqrequestdialog_name] = miq_provision_redhat_dialogs_template
request.options[:network_adapters] = [1, "1"] (type: Array)
request.options[:number_of_sockets] = [1, "1"] (type: Array)
request.options[:number_of_vms] = [1, "1"] (type: Array)
request.options[:owner_email] = [email protected] (type: String)
request.options[:owner_first_name] = Peter (type: String)
request.options[:owner_last_name] = McGowan (type: String)
request.options[:pass] = 1 (type: Fixnum)
request.options[:placement_auto] = [false, 0] (type: Array)
request.options[:placement_cluster_name] = [1000000000001, "Production"]
request.options[:placement_dc_name] = [1000000000002, "Default"] (type: Array)
request.options[:placement_ds_name] = [1000000000001, "Data"] (type: Array)
request.options[:placement_host_name] = [1000000000001, "rhevh12.bit63.net"]
request.options[:provision_type] = ["native_clone", "Native Clone"]
request.options[:retirement] = [0, "Indefinite"] (type: Array)
request.options[:retirement_warn] = [604800, "1 Week"] (type: Array)
request.options[:root_password] = nil
request.options[:schedule_time] = 2015-06-06 00:00:00 UTC (type: Time)
request.options[:schedule_type] = ["immediately", "Immediately on Approval"]
request.options[:src_ems_id] = [1000000000001, "RHEV"] (type: Array)
request.options[:src_vm_id] = [1000000000004, "rhel7-generic"] (type: Array)
request.options[:start_date] = 6/6/2015 (type: String)
request.options[:start_hour] = 00 (type: String)
request.options[:start_min] = 00 (type: String)
request.options[:stateless] = [false, 0] (type: Array)
request.options[:subnet_mask] = nil
request.options[:vlan] = ["public", "public"] (type: Array)
request.options[:vm_auto_start] = [false, 0] (type: Array)
request.options[:vm_description] = nil
request.options[:vm_memory] = ["2048", "2048"] (type: Array)
request.options[:vm_name] = rhel7srv002 (type: String)
request.options[:vm_prefix] = nil
request.options[:vm_tags] = [] (type: Array)
The Options Hash
A user starts the virtual machine provisioning workflow by clicking on the Lifecycle → Provision VMs button in the Virtual Machines toolbar of the WebUI. After selecting a template to provision from, the requesting user completes the provisioning dialog and enters all of the details required to create the virtual machine; the number of CPUs, memory, network to connect to, and hard disk format for example. Somehow this information collected from the WebUI must be added to the Automate provisioning workflow.
Provisioning a virtual machine or instance is a complex operation that as we have just seen, involves an approval stage. We saw in Requests and Tasks, that an automation operation involving an approval stage is split into two parts, the Request and the Task. In the case of a virtual machine provisioning operation the request is represented by an miq_provision_request object, and the task is represented by an miq_provision object.
The inputs and options selected from the provisioning dialog are added to the miq_provision_request object as key/value pairs in a data structure known as the options hash. When we write our custom Ruby methods to interact with the provisioning workflow, we frequently read from and write to the options hash.
If the provisioning request is approved, the options hash from the request object is propagated to the task object, but there are slight differences between the two hashes. We’ll examine these next.
Request Object (miq_provision_request)
The contents of the request object’s options hash varies slightly between provisioning targets (VMware, OpenStack, RHEV etc) and target VM Operating System (Linux, Windows etc.), but a typical hash for a Linux virtual machine provision to a RHEV provider is:
Correlation with the Provisioning Dialog
The key/value pairs that make up the options hash initially come from the provisioning dialog (see The Provisioning Dialog). For example if we look at an extract from one of the provisioning dialog YAML files, we see the definition for the number_of_sockets option:
:number_of_sockets: :values: 1: '1' 2: '2' 4: '4' 8: '8' :description: Number of Sockets :required: false :display: :edit :default: 1 :data_type: :integer
In the options hash this corresponds to:
request.options[:number_of_sockets]
We can also see that the options hash values for many of these keys are two-element lists, for example:
request.options[:cores_per_socket] = [1, "1"]
This list corresponds to one of the value: 'display name' pairs listed under the :values: subsection in the provisioning dialog YAML file, like so:
:cores_per_socket: :values: 1: '1' ...
Some of the options hash value lists contain object IDs, for example:
request.options[:placement_host_name] = [1000000000001, "rhevh12.bit63.net"]
These options hash keys are generally populated by a dynamic method. For example the provisioning dialog YAML for this key name doesn’t contain a static :values: list, instead it specifies that the values will be dynamically generated by the allowed_hosts
method, as follows:
:placement_host_name: :values_from: :method: :allowed_hosts :auto_select_single: false :description: Name :required: false :display: :edit :data_type: :integer :required_description: Host Name
The allowed_hosts
method filters the list of hosts presented to the user based on previously selected values for cluster, resource pool and folder.
Accessing the Options Hash from an Automation Script
When we work with our own methods that interact with the VM provisioning process, we often need to get and set values in the options hash.
Reading Values
We can read any of the options hash values using the get_option
method, like so:
request = $evm.root['miq_provision_request']
memory_in_request = request.get_option(:vm_memory).to_i
For options hash keys whose values are lists, the get_option
method returns the first value in the list (there is a corresponding method get_option_last
that returns the last value in the list).
Setting Values
We can also set most options using the set_option
method, as follows:
request.set_option(:subnet_mask,'255.255.254.0')
When setting options hash keys whose values are normally lists, we generally only need to write a scalar value using set_option
. This can be an integer or string, for example:
request.set_option(:number_of_sockets, '2')
or
request.set_option(:number_of_sockets, 2)
Set Methods
Several options hash keys have their own set
method, listed in the following tables, which we should use in place of set_option
.
Options hash key | set method | argument type |
---|---|---|
|
|
string |
Options hash key | set method | argument type |
---|---|---|
|
|
string |
|
|
string |
|
|
string |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
Options hash key | set method | argument type |
---|---|---|
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
|
|
service model object |
The set methods that take a service model object as an argument, perform a validity check that the value we’re setting is an eligible resource for the provisioning instance. We use one of these methods in the following way:
cloud_network = $evm.vmdb('CloudNetwork').find_by_name('private_3')
unless cloud_network.nil?
prov.set_cloud_network(cloud_network)
...
Tip
|
Use one of the techniques discussed in Investigative Debugging to find out what key/value pairs are in the options hash to manipulate. |
Task Object (miq_provision)
The options hash from the request object is propagated to each task object, where it is subsequently extended by task-specific methods such as those handling VM naming and placement:
miq_provision.options[:dest_cluster] = [1000000000001, "Default"]
miq_provision.options[:dest_host] = [1000000000001, "rhelh03.bit63.net"]
miq_provision.options[:dest_storage] = [1000000000001, "Data"]
miq_provision.options[:vm_target_hostname] = rhel7srv002
miq_provision.options[:vm_target_name] = rhel7srv002
Some options hash keys such as :number_of_vms
have no effect if changed in the task object; they are relevant only for the request.
Adding Network Adapters
There are two additional methods that we can call on an miq_provision
object, to add further network adapters. These are set_network_adapter
and set_nic_settings
.
idx = 1
miq_provision.set_network_adapter(idx,
{
:network => 'VM Network',
:devicetype => 'VirtualVmxnet3',
:is_dvs => false
})
miq_provision.set_nic_settings(idx,
{
:ip_addr => '10.2.1.23',
:subnet_mask => '255.255.255.0',
:addr_mode => ['static', 'Static']
})
Adding Our Own Options: The ws_values Hash
Sometimes we wish to add our own custom key/value pairs to the request or task object, so that they can be used in a subsequent stage in the VM provision state machine for custom processing. An example might be the size and mount point for a secondary disk to be added as part of the provisioning workflow. Although we could add our own key/value pairs directly to the option hash, we risk overwriting a key defined in the core provisioning code (or one added in a later release of ManageIQ).
There is an existing options hash key that is intended to be used for this, called ws_values
. The value of this key is itself a hash, containing our key/value pairs that we wish to save.
miq_provision.options[:ws_values] = {:disk_dize_gb=>100, :mountpoint=>"/opt"}
The ws_values
hash is also used to store custom values that we might supply if we provision a VM programmatically from either the RESTful API, or from create_provision_request
. One of the arguments for a programmatic call to create a VM is a set of key/value pairs called additional_values
(it was originally called additionalValues
in the SOAP call). Any key/value pairs supplied with this argument for the automation call will automatically be added to the ws_options
hash.
By using the ws_options
hash to store our own custom key/value pairs, we make our code compatible with the VM provision request being called programmatically.
Summary
The options hashes in the miq_provision_request and miq_provision objects are some of the most important data structures that we work with. They contain all of the information required to create the new virtual machine or instance, and by setting their key values programmatically we can influence the outcome of the provisioning operation.
As discussed in Requests and Tasks, the challenge is sometimes knowing whether we should access the options hash in the miq_provision_request or miq_provision objects, particularly when setting values. We need to apply our knowledge of requests and tasks to determine which context we’re working in.
We also need to be aware of which options hash keys have their own 'set' method, as these keys typically require an array formatted in a particular way.