Recently we were asked about a use case. It involved using tags from parent objects such as a cluster and applying them to virtual machines, regardless of whether or not the machine was provisioned through CloudForms/MiQ. In order to do this, we need to set up a control policy that uses custom automation. By using the VM Create Complete event, we can make sure the automation runs for all new virtual machines (on a provider with the policy profile), even those created outside of CloudForms.

what we're after

We want a control policy that gets triggered every time a new VM on a given provider is discovered. This policy will trigger an action type of Invoke Custom Automation. The custom automation will take a look at the VM object, figure out its parent cluster, check the appropriate tag for that cluster, and apply that tag to the VM. If the cluster has no tag in the appropriate category, we'll create and apply a "failsafe" tag.

For our example we will use the Environment tag category, with a failsafe tag named "orphan".

the code

Here are the pieces of the puzzle:

  1. A Tag Category
  2. An Instance
  3. A Method
  4. An Action
  5. A Policy
  6. A Policy Profile

A Tag Category

For us this one is easy, since we are using the OOTB Environment tag category. If you're using a custom tag category you'll either have to create it manually or create it in the method as we will do with the failsafe tag in the example below.

An Instance

We need to create an instance that we can call. The Invoke Custom Automation action type can call anything in System/Request. Alternatively, we could put the instance elsewhere and use System/Request/Call_Instance, but we will use System/Request today.

  1. Copy the ManageIQ/System/Request class to the domain of your choice.
  2. Highlight the class and select Configuration/Add a New Instance.
  3. Name the Instance ApplyHierarchicalTags.
  4. Under the "meth1" give a value of apply_hierarchical_tags and a message of create.
    It should look something like this:

A Method

This is the most important piece, and there are many ways to go about achieving it. Feel free to use this code as an example and play around with it, but keep in mind that there are many other, probably more elegant, ways of achieving this and things like this.

  1. Go to your new Request class and highlight the methods tab on the right.
  2. Select Configuration/Add a New Method.
  3. Select "inline" for method type.
  4. Name the method apply_hierarchical_tags.

The first thing we're going to do is to define a tag category and a "tag failsafe". The tag failsafe is a tag that will be used in the event that the cluster has no tag of the relevant category. We'll define those like this:

tag_category = "environment"
tag_failsafe = "orphan"

Obviously we'll need the VM object to work with, so we'll define that next:

vm = $evm.root['vm']

Next we'll use the failsafe tag. In the event the cluster in question is missing the correct tag, which in our case is the Environment tag, we can create a failsafe tag to apply to the VM. Once you repent for not tagging all the things, your penance can be to go back and correct everything with the failsafe tag. The next code block will check if the failsafe tag exists, and if not, create it.

$evm.execute('tag_create', tag_category, :name=> tag_failsafe, :description => tag_failsafe) unless $evm.execute('tag_exists?', tag_category, tag_failsafe)

Next we want to check the tag of the relevant category for the cluster. The tags method for ems_cluster takes a symbol, something like:

environment_tag = vm.ems_cluster.tags(:environment).first

We have our tag category defined as a string, so we can use the Ruby to_sym method to save some time.

cluster_tag = vm.ems_cluster.tags(tag_category.to_sym).first

Almost there. Now we need to take the VM object and apply the relevant cluster tag if it exists, otherwise apply the failsafe tag. There are many ways to do this but here we're going to use a ternary operator.

cluster_tag ? vm.tag_assign("#{tag_category}/#{cluster_tag}") : vm.tag_assign("#{tag_category}/#{tag_failsafe}")

That's the heavy lifting. You can check out an example of all of this put together here.
Once you type all your code don't forget to validate and save the method by clicking Add. Now you should have an instance and a method that looks something like this:

An Action

We need to create the action that we're going to use for the policy.

  1. Navigate to Control/Explorer
  2. Go to Actions/All Actions and select Configuration/Add a New Action
  3. Give it a description of apply_hierarchical_tags
  4. Select “Invoke a Custom Automation” for the action type
  5. Define the message as “create”
  6. Define the Request as “Apply_Hierarchical_Tags”
  7. Click Save
    Something like this:

A Policy

Next we'll create a policy.

  1. Navigate to Control/Explorer
  2. Go to Policies/All Policies/Control Policies/VM Control Policies/ and select Configuration/Add a new VM and Instance Control Policy
  3. Give it a description of env_inheritance_policy
  4. Click add

We need to assign an event to the policy so it knows when to trigger.

  1. Select your new policy
  2. Go to Configure/Edit this policy's event assignments
  3. Select "VM Create Complete" (it's under VM Configuration)
  4. Click save

Now we need to connect it to our new action:

  1. Select the new policy event
  2. Select Edit Actions for this policy Event
  3. Under Order of Actions if all conditions are true, highlight apply_hierarchical_tags
  4. Move it to the selected actions box
  5. Click save

A Policy Profile

Lastly, we need to tie everything together in a policy profile and apply it to our provider:

  1. Under Control/Explorer, expand policy profiles
  2. Select Configuration/add new policy profile
  3. Give it a description of EnvInheritancePolicyProfile
  4. Under Policy Selection, highlight VM and Instance Control: env_inheritance_policy
  5. Move the policy to the Profile Policies Box
  6. Click Add

The profile in its entirety should look like this:

Navigate to the provider where you want to apply the policy profile:

  1. Select Policy/manage policies (at the top)
  2. Under Select Policy Profiles, check the box next to EnvInheritancePolicyProfile
  3. Click Save

You're done. The next time a VM hosted on that provider is discovered, the Environment tag that is assigned to the cluster will be assigned to the VM, and if there is no cluster tag, the code will create and assign the failsafe tag.

some other things