Reusable Method


#1

I am new to using Cloudforms and have been going over the Mastering Cloudforms Automation book. I have been able to create a few workflows succesfully since starting to look into it last month.

My question is a lot of my workflows are going to be “copy and paste” but only modifying a few fields, The method will connect to a Windows server using winrm and kick off a script.

The only thing that would change in the method are:
-Importing the inputs from the dialog
-The script with the arguments to kick off.

Is there a way to have a “Master Method” that can do this? This would also help because if i had multiple methods, i would have to set the username and password for each that is used to connect to the server using winrm


#2

You could have multiple instances that all execute the same method. The differences would be set as variables of the class (i.e. what script to run). The method would reference the variables from the instance and the dialog to determine what script to run and arguments to pass. As long as the dialog element names are the same between the different dialogs the method would be able to reference them as well regardless of the instance.


#3

You could create your “master method” to read inputs and the script name to be run from $evm.object, and then call the master method using various helper methods that handled the dialog input handling, etc.

These helper methods could call the master method using something like:

$evm.instantiate("/namespace/class/master_method?script=dialog_script&arg1=dialog_arg1&arg2=dialog_arg2")

Your master method would receive these arguments using something like:

script_to_run = $evm.object['script']
arg1 = $evm.object['arg1']
arg2 = $evm.object['arg2']

Chapter 46 of the automation book describes argument passing between methods and instances, and case 3 in this chapter describes argument passing is this way when calling $evm.instantiate.

Hope this helps,
pemcg


#4

I think if we went this route I would have to store the username and password in each instance that we create.

The other main reason for seeing if we could have one main method is so if we have to update the username/password we have on our instance/methods, that we would only have to update it in one place and not for every instance/method.


#5

Thanks for your guys replies (and your work on the Master Cloudforms Automation book).

I need to play around with this some more (I am still learning and trying to get other things figured out - like making a dynamic dropdown be able to be populated by a MSSQL query).

I definitely like the idea of it all being stored in the $evm.object and that ultimately being passed to the final method.

The only “gotcha” I can think of outside of actually getting in there and trying it is if cloudforms freaks out if there are different amount of arguments and how to account for that.

for instance, say i have the “Master Method” and it is alotting for 3 arguments. will things mess up if i run a script with only 2 arguments through it?


#6

We tried this today and we were able to get this to successfully work.

I think it is really nice since if we have to change the way we call things in the “Master method” we only have to change it once and not every place we use it.

Thanks for your guys help on this.


#7

Hi Peter,

Your automation book is excellent
I have one question here…
Calling another instance via instantiating is fine but when I instantiate that instance I would like to save the variable that the script passes on exit like a return value
Is there a way to save the return value ??

Regards
Irshad


#8

@irshad2005

What we have done in a case like this is set $evm.object[‘result’] to the return data in the method which can be read by the caller.


#9

Hi Eric,

Thanks for your response
Can you please give me an example of this as I instantiate to call another script
One parent script that calls child scripts and stores return value from the child scripts
Is there a way of doing inside the automation rather than using the API calls
I tried your $evm.object[‘result’] but that didnt work as well

temp1 script

$evm.instantiate("/Example/Example-Integration/CloudformsInternal/temptest2")
res = $evm.object[‘result’]
$evm.log(“info”,“result is #{res}”)

temp2 script

def test()
t1 = “success”
$evm.log(“info”,“Called from temptest2”)
$evm.object[‘result’] = t1
return t1
end
t2 = test()
$evm.object[‘result’] = t2

Am i doing something wrong over here??

Regards
Irshad


#10

Irshad,

You want to save the returned object of the instantiate call and reference that. $evm.object is used as a reference to “the thing currently running” and not what you instantiated, hence the confusion.

sub_method = $evm.instantiate("/Example/Example-Integration/CloudformsInternal/temptest2")
if sub_method.nil?
  $evm.log("info", "something went wrong with the instantiation")
else
  $evm.log("info","result is #{sub_method['result']}")
end

#11

Is it possible to pass arguments to methods in the UI when filling instances fields? Like with relationships, passing args with this syntax: ?arg1=‘value1’?

In one instance i want to call 3 times a method, but with differents arguments.
If in the schema/instance fields i call 3 time the same method as method type i cannot pass arguments.
So i have to create intermediate instance to call and call it as relationship with arguments.

It is a waste of resources to instanciate a new instance only to call a single method, instead of calling method directly from calling instance, i think.

Is there a better way (without coding in ruby for that of course)?


#12

There is, if your method is defined within the same class: Passing Arguments When Calling a Method in the Same Class


#13

i have already read this, but it does not look what i want.

This example with the update_provision_status is very different:

  • it is a state which calls a method update_provision_status with arguments on the On_entry stage.

That’s a specific case in a specific situation.

I just want the most simple case:

  • my instance is calling all methods filled in the schema/instance UI.
  • i give arguments on the methods (i do not give another method with arguments): like with relationships

#14

For local methods the same syntax works, not only for On Entry values:
localmethod(param1 => 'local1', param2 => 'local2')

You need to define Input Parameters in the inline method:

input_parameters
You can access these parameters via $evm.inputs[]:

$evm.log(:info, "@@@@@@ param1: #{$evm.inputs['param1']}")
$evm.log(:info, "@@@@@@ param2: #{$evm.inputs['param2']}")

Sample call of local method directly, with arguments:

call_local_method_directly

And the passed parameters in captured in automation.log:

Following Relationship [miqaedb:/System/Request/call_instance#create]
Updated namespace [miqaedb:/System/Request/call_instance#create  ManageIQ/System]
Following Relationship [miqaedb:/Call_Method/Directly/Local#create]
Updated namespace [miqaedb:/Call_Method/Directly/Local#create  Test/Call_Method]
Updated namespace [Call_Method/Directly/localmethod  Test/Call_Method]
Invoking [inline] method [/Test/Call_Method/Directly/localmethod] with inputs [{"param1"=>"local1", "param2"=>"local2"}]
<AEMethod [/Test/Call_Method/Directly/localmethod]> Starting
<AEMethod localmethod> @@@@@@ param1: local1
<AEMethod localmethod> @@@@@@ param2: local2
<AEMethod [/Test/Call_Method/Directly/localmethod]> Ending
Method exited with rc=MIQ_OK
Followed  Relationship [miqaedb:/Call_Method/Directly/Local#create]
Followed  Relationship [miqaedb:/System/Request/call_instance#create]

It is also possible to call methods in other classes since PR10089. The syntax is METHOD::/Namespace/ClassName.method but you need to use a field type State instead of Method in your instance:

call_remote_method_directly

The remote method can capture input parameters the same way localmethod did:

$evm.log(:info, "%%%%%% param1: #{$evm.inputs['param1']}")
$evm.log(:info, "%%%%%% param2: #{$evm.inputs['param2']}")

automation.log output:

Following Relationship [miqaedb:/System/Request/call_instance#create]
Updated namespace [miqaedb:/System/Request/call_instance#create  ManageIQ/System]
Following Relationship [miqaedb:/Call_Method/Directly/Remote#create]
Updated namespace [miqaedb:/Call_Method/Directly/Remote#create  Test/Call_Method]
Processing State=[run]
Updated namespace [remote_method/methods/remotemethod  Test/remote_method]
Invoking [inline] method [/Test/Remote_Method/Methods/remotemethod] with inputs [{"param1"=>"remote1", "param2"=>"remote2"}]
<AEMethod [/Test/Remote_Method/Methods/remotemethod]> Starting
<AEMethod remotemethod> %%%%%% param1: remote1
<AEMethod remotemethod> %%%%%% param2: remote2
<AEMethod [/Test/Remote_Method/Methods/remotemethod]> Ending
Method exited with rc=MIQ_OK
Processed State=[run] with Result=[ok]
Processed State=[run]
Next State=[]
Followed  Relationship [miqaedb:/Call_Method/Directly/Remote#create]
Followed  Relationship [miqaedb:/System/Request/call_instance#create]

I hope this is what you’re looking for.