Configuration domains in CloudForms/ManageIQ – part deux

In the last post on this topic I discussed a technique of separating your configuration from your code in CloudForms’ Automation Engine. The technique relied on creating class overrides in a higher priority domain, enabling attributes on those higher priority classes to be passed down.

It works but it’s…clunky, and it requires a duplicate of every class in a higher domain. Not the most scalable technique!

Below I present two other methods – one that uses $evm.instance_get, and another that loads the config directly onto the root object.

Version 1: instance_get

$evm.instance_get has the following syntax:

$evm.instance_get(path)

Where path is the full path, including the domain, of the class you wish to fetch. The return value of instance_get is a hash containing the attributes of that class.

In short, using this method enables you to fetch the attributes of any class, at runtime, and return them to your automation method. Using this we can store our configuration in the attributes of one or more classes in a higher domain, then fetch it when it’s required.

Here’s my configuration class, under /Config/Common/SSO/SSO:

And here’s a basic automation method, called from a button, that fetches the configuration class and prints out the configuration options:

fields = $evm.instance_get('/Config/Common/SSO/SSO')
fields.each do |k,v|
  $evm.log(:info, "#{k}=#{v}")
end

And the output?

[----] I, [2018-09-17T10:37:18.711039 #11725:814e58]  INFO -- : <AEMethod add_options> sso_host=keycloak.home.ajg.id.au
[----] I, [2018-09-17T10:37:18.711516 #11725:814e58]  INFO -- : <AEMethod add_options> sso_user=admin
[----] I, [2018-09-17T10:37:18.711894 #11725:814e58]  INFO -- : <AEMethod add_options> sso_pass=v2:{fuiIHaMchRDD4G2xGAvqwg==}
[----] I, [2018-09-17T10:37:18.712249 #11725:814e58]  INFO -- : <AEMethod add_options> sso_realm=master

Something to note: the password is printed as a v2 encrypted string. That means you can’t simply call decrypt() to decrypt it into its plain text form. You need to apply a workaround as documented here.

Version 2: something more automatic

I like instance_get, but I don’t like having to fetch configuration options in every method I call. It would be nice to simply fetch all of the configuration at once and place it somewhere accessible.

We could have an automate method, called from a relationship, that loads all of our configuration options onto the $evm.rootobject. Since it’s on $evm.root, it’s available from anywhere inside that automate invocation.

Here’s what the configuration class looks like now – note the addition of the ‘load’ method:

Here’s the code that does the loading:

$evm.object.attributes.each do |k,v|
  $evm.root[k] = v
end

Now I add a relationship link to /Config/Common/SSO/SSO from another class elsewhere in Automate – in this case, it’s a class executed upon clicking a Button. Here’s how that relationship looks:

Once I click my button, the Button’s class is executed. The relationship /Config/Common/SSO/SSO will be followed first. When entering my Config class, my load method (shown above) will be executed and will load all of my configuration data into $evm.root.

This method works best when you place the relationship to your Configuration class only at the point where you enter Automate (e.g. /System/Request/CallInstance, the entry point class for all your buttons, or schedules, or API entrypoints, etc). Doing it this way allows you to load configuration data once and have it available within $evm.root for as long as that Automate workspace exists. That includes persisting the configuration during retries of any state machines that execute within that workspace.

The Verdict?

For me, I prefer option 2. One large Config class, I load it once onto $evm.root at the entry point into Automate, and it’s automatically available everywhere until that Automate invocation is done. This also prevents me from having to do some MiqPassword magic to decrypt passwords (remember that instance_get returns the v2-encrypted string!), potentially leaving them in $evm.root in plaintext for accidental printing to the console.

If you want to separate config from code – and you should! – both of these methods will go a very long way to getting you there.

Happy automating!

Leave a Reply

Your email address will not be published. Required fields are marked *