Argument Passing and Handling

The way that we pass arguments into automation methods - and receive them from inside the method - varies depending on how we're calling the automation method. We need to consider this if we're writing a method that can be called in several ways, such as from a button and/or from an API call.

Here is an example of calling the same Instance (ObjectWalker) five ways, passing two arguments each time, 'lunch' and 'dinner'. We can use object_walker_reader to show us where the arguments can be read from inside our called method.

Case 1 - Calling from a Button

For this first case we call ObjectWalker (via /System/Process/Request/Call_Instance) from a button. We create a button dialog that prompts for two text box fields:

screenshot

screenshot

We then add the button to a button group anywhere.

If we click on the button, and enter the values 'salad' and 'pasta' into the dialog boxes, we see the dialog values appear in $evm.root in the receiving method, indexed by the key name prefixed by dialog_

~/object_walker_reader.rb | grep -P "lunch|dinner"
    object_walker:  $evm.root['dialog_dinner'] = salad  (type: String)
    object_walker:  $evm.root['dialog_lunch'] = pasta  (type: String)

Case 2 - Calling from the RESTful API

For this use-case we have a Ruby script that calls our internal CloudForms method via the REST API:

url = "https://#{server}"

post_params = {
  :version => '1.1',
  :uri_parts => {
    :namespace => 'Bit63/Discovery',
    :class => 'Methods',
    :instance => 'ObjectWalker'
  },
  :parameters => {
    :lunch => "sandwich",
    :dinner => "steak"
  },
  :requester => {
    :auto_approve => true
  }
}.to_json
query = "/api/automation_requests"

rest_return = RestClient::Request.execute(method: :post, url: url + query, :user => username, \
              :password => password, :headers => {:accept => :json}, :payload => post_params, verify_ssl: false)
result = JSON.parse(rest_return)


In the called method we see the arguments visible in several places; in the task's options hash as the attrs key; under $evm.root because this is the Instance that we launched when entering automation, and under $evm.object because this is also our current object.

~/object_walker_reader.rb | grep -P "lunch|dinner"
    |    object_walker:  $evm.root['automation_task'].options[:attrs] = {:lunch=>"sandwich", :dinner=>"steak", :userid=>"admin"}  (type: Hash)
    object_walker:  $evm.root['dinner'] = steak  (type: String)
    object_walker:  $evm.root['lunch'] = sandwich  (type: String)
    object_walker:  $evm.object['dinner'] = steak  (type: String)
    object_walker:  $evm.object['lunch'] = sandwich  (type: String)

Case 3 - Calling from $evm.instantiate

For this use-case we call ObjectWalker from another running automation method using $evm.instantiate

$evm.instantiate("/Discovery/Methods/ObjectWalker?lunch=salad&dinner=spaghetti")


When called in this way, the called method only receives the arguments from $evm.object (one of our (grand)parent instances is $evm.root, our immediate caller is $evm.parent).

~/object_walker_reader.rb | grep -P "lunch|dinner"
     object_walker:   $evm.object['dinner'] = spaghetti   (type: String)
     object_walker:   $evm.object['lunch'] = salad   (type: String)

Case 4 - Calling from a Stage in a State Machine

Here we've cloned the CatalogItemInitialization instance of the ServiceProvision_Template State Machine into our own Domain, and edited it to call ObjectWalker from the pre1 stage.

screenshot


If we provision a new service, we can again retrieve the arguments in our called method from $evm.object.

~/object_walker_reader.rb | grep -P "lunch|dinner"
     object_walker:   $evm.object['dinner'] = fish   (type: String)
     object_walker:   $evm.object['lunch'] = ciabatta   (type: String)

Case 5 - Passing Arguments via the ws_values Hash During a VM Provision

We can pass our own custom values into the VM provisioning process so that they can be interpreted by any method in the Provision VM from Template State Machine.

The facility to do this is provided by the additional_values field in an /api/provision_requests REST call (additionalValues in the original SOAP EVMProvisionRequestEx call), or from the sixth element in the argument list to an $evm.execute('create_provision_request',...) call (see also Creating Provisioning Requests Programmatically).

For this use case we've edited the Provision VM from Template State Machine to add a few extra stages:

screenshot

These stages could modify the provisioning process if required based on the custom values passed in. An example of this might be to specify the disk size for an additional disk to be added by the AddDisk stage.

For this example we're using a simple automation method to call $evm.execute('create_provision_request',...) to provision a new VM. We specify the custom values in arg6:

# arg1 = version
args = ['1.1']

# arg2 = templateFields
args << "name=rhel7-generic|request_type=template"

# arg3 = vmFields
args << "vm_name=test10|vlan=rhevm"

# arg4 = requester
args << "[email protected]|owner_first_name=Peter|owner_last_name=McGowan"

# arg5 = tags
args << nil

# arg6 = Web Service Values (ws_values)
args << "lunch=soup|dinner=chicken"

# arg7 = emsCustomAttributes
args << nil

# arg8 = miqCustomAttributes
args << nil

request_id = $evm.execute('create_provision_request', *args)


When we call this method and the VM provisioning process begins, we can retrieve the custom values at any stage from the miq_provision options hash using the ws_values key...

~/object_walker_reader.rb | grep -P "lunch|dinner"
object_walker:   $evm.root['miq_provision'].options[:ws_values] = {:lunch=>"soup", :dinner=>"chicken"}   (type: Hash)

Finding Out How We've Been Called

We can use the $evm.root['vmdb_object_type'] value to find out how our method has been called, and retrieve the arguments in the appropriate manner, i.e.

case $evm.root['vmdb_object_type']
  when 'miq_provision'
   # called from a VM Provision, retrieve from $evm.root['miq_provision'].options[:ws_values]
  when 'vm'
    # called from a button on a VM object, retrieve from $evm.object
  when 'automation_task'
  # Called from an API call, retrieve from $evm.root
end

Passing Arguments When Calling a Method in the Same Class

When an Instance (such as a State Machine) calls a method in the same Class as itself, it can pass key/value argument pairs in parentheses as input parameters with the call. We see the VMProvision_VM State Machine do this when it calls update_provision_status:

screenshot

When we create a Method that accepts input parameters in this way, we need to specify the name and data type of each parameter in the Method definition:

screenshot

The Method then reads the parameters from $evm.inputs:

update_provision_status(status => 'pre1',status_state => 'on_entry')

 # Get status from input field status
 status = $evm.inputs['status']

 # Get status_state ['on_entry', 'on_exit', 'on_error'] from input field
 status_state = $evm.inputs['status_state']

results matching ""

    No results matching ""