Building vCAC Multi Machine Workflows

An important part of provisioning machines with vCAC is creating multi machine blueprints. As such, It is important to understand the flow of these kinds of blueprints when inside a custom workflow. With a regular workflow, things are pretty easy. The “virtualmachineid” parameter is passed into the workflow you are running at the moment (e.g workflow stubs, or any other custom workflows) and vualla everything is accessible with it, and the standard vCAC Designer actions will probably meet your needs.

When we’re running a workflow on a multi machine blueprint, things are a bit different, and some questions arise. Where does the workflow run? when? and how many times? how can I know which machines are inside the multi machine blueprint so I can interact with each separately during my workflow? Well, lets dive in and start answering some of these questions.

First of all lets get some must knowledge on MultiMachine blueprints / vCAC workflows:
– When you apply a custom property to a Multi Machine blueprint, it applies to all component virtual machines as well (Remember that when you apply a custom property or a stub that launches a workflow… yes, the workflow will run the number of N component VMs you have + 1 for the multi machine blueprint object)
– The mgmtContext parameter is in fact a link to the database  at the moment of the workflow. Use LINQ queries to interact with it and manipulate it.

So after this quick preview of things lets get to it.

The first thing you will want to do when running a multi machine workflow, is decide whither you want to run it from a master machine perspective, or for each machine separately. For this decision process we will use a simple “if” flow object. In order to determine what is exactly the machine type. We will start by getting the virtual machine object from the databaase, using a common LINQ query used in vCAC workflows:

[code]
/*This is a long line, please notice*/
mgmtContext.VirtualMachines.Expand(Function(v) v.VirtualMachineProperties).Where(Function(v) v.VirtualMachineID = VirtualMachineId).FirstOrDefault()

[/code]

This query will get us the current VM according to its ‘virtualmachineid’ which we get as a parameter into the workflow. The ‘MasterMachine’ variable is defined of type “DynamicOps.ManagementModel.VirtualMachine”  which is the object type definition for a VM in vCAC. Applying this LINQ query to the ‘MasterMachine’ variable is done with a simple ‘Assign’ workflow action:

Getting vCAC Machine Object

Now, with our Machine variable populated, we can check the following ‘If’ statement:

If Machine is Not a Component

This will essentially tell us whether the VirtualMachineId we’re working on is an actual VM in the MultiMachine BluePrint, or the “Master Machine” itself. meaning, the MultiMachine Blueprint Object itself.

Once we have the MultiMachine object, we can access all of it’s component VMs in a few more steps!

First, we will use a second LINQ query, to get a list of all Component Machines for our MultiMachine Blueprint.

[code]
mgmtContext.AppServiceComponents.Expand(Function(AppServiceComponents) AppServiceComponents.VirtualMachine.VirtualMachineProperties).Where(Function(v) v.AppServiceVirtualMachine.VirtualMachineID=VirtualMachineId).toList()
[/code]

We will create an ‘Assign’ workflow object to Assign this LINQ query to a variable we’ll create, with the name AllChildMachines, of type ‘System.Collections.GenericList’ This is a .Net type for a linked list. Each of the list’s component type should be ‘Dynamicops.ManagementModel.AppServiceComponent’

Gell All child Machines

AllChildMachines Variable Type

Next, we will need to create a ‘Foreach’ workflow object, that is also of type: ‘Dynamicops.ManagementModel.AppServiceComponent’. The Foreach loop will run on each of are associated vCAC VMs with the Master VM, and in at that part of the workflow, we will populate a VirtualMachine variable for that particular VM.

Foreach VM in Master Blueprint

The  LINQ Query used here, is similar to our first query, and is:

[code]
mgmtContext.VirtualMachines.Expand(Function(v) v.VirtualMachineProperties).Where(Function(v) v.VirtualMachineID = item.virtualmachine.virtualmachineid).FirstOrDefault()
[/code]

If your sharp, you’ll notice the logic change here, this time the LINQ Query is grabbing the virtual machine with the same ID as our current ‘item’ in the foreach loop, thus running on each and each VM.

If you’re using the regular vCAC Designer objects, such as “GetVirtualMachineName” you’ll use them like:

GetChildMachineName

From this point of the workflow you can run whatever you want on each ‘childmachine’. For example, apply a certain logic to look at all VMs , read properties, and decide what to do. Act upon each machine separately, or whatever else you might need to do. I recommend using the ‘Flowchart’ object for maximum flexibility (and not the sequence object shown here for easier reading purposes).

Don’t forget to set our last variable, “ChildMachine” of type ‘DynamicOps.ManagementModel.VirtualMachine’!

Enjoy, and leave your comments below!


Comments
Harvey Specter
Posted at 2:35 pm November 8, 2013
Leandro
Reply
Author

Hi….very intresting post!!!!
i’m trying this….and i have a doubt…the MasterMachine is a Variable or a Argument? If i create this like a variable, i get and error when the workflow runs, that the MasterMachine must be an argument…..if i define this like an argument…i get “Resource not found for the segment ‘VirtualMachines'”……what i missing?
Regards,
Leandro.

    Harvey Specter
    Posted at 3:23 pm November 8, 2013
    Omer Kushmaro
    Reply
    Author

    Hi Leandro, I’m glad you liked the post!
    “MasterMachine” should be a variable, of type “Dynamicops.ManagementModel.Virtualmachine” (pardon if this is inaccurate as i’m not in front of a working system at the moment)

    did you set it as this kind of type? Also don’t forget to put in the full linq query (as mentioned in the post) into the assign operations

      Harvey Specter
      Posted at 3:46 pm November 8, 2013
      Leandro
      Reply
      Author

      Hi….Thanks for you rapid reply!

      I checked and i put the assign correctly.

      If i define the MasterMachine as a variable, i get…” The values provided for the root activity’s arguments did not satisfy the root activity’s requirements: ‘DynamicActivity’: The following keys from the input dictionary do not map to arguments and must be removed: MasterMachine. Please note that argument names are case sensitive. Parameter name: rootArgumentValues”

        Harvey Specter
        Posted at 4:10 pm November 8, 2013
        Omer Kushmaro
        Reply
        Author

        I do not know that specific error, but it to me it look likes you probably changed something in the argument section and it went wrong? for the argument section you should only have “VirtualMachineId” as an argument ( you have it by default, nothing should be set for this to work)
        Did you try reverting the workflow a couple of versions back and re-trying this? even without any “multi machine workflow” querying this linq query to populate a “dynamicops.Managementmodel.virtualmachine” typed variable should be fairly straight forward.
        Try to get only the variable + query to work without any other of the things mentioned in the post

Harvey Specter
Posted at 12:06 pm November 27, 2013
Raanan Ikar
Reply
Author

Hi, This is indeed a very interesting and useful post. How did you know what API method, and object types to use, and formulate your LINQ queries? For example, inside vCO , there is an extensive API explorer, decent documentation on the product, extensibility for adding one’s own libraries or creating plug-ins, and plenty of scripting examples in the provided workflows and action libraries that all of these help one to create a fully extended workflow inside vCO, however in vCAC when you go to assign a variable and choose its type this seems to be the only place where one browses types, and is exposed to APIs that could help one extend their vCAC workflows. There are plenty of examples of how to invoke a PowerShell , and map custom properties, or the name of a VM into the args of a powerShell script, … but what if I needed the VM’s IP address, or I want some other info about the storage that was provisioned with the VM, how do I enumerate /access this data? Any references or advice you have on learning more about the vCAC APIs to help advance or further extend the basic workflows would be greatly appreciated.

    Harvey Specter
    Posted at 12:08 am November 28, 2013
    Omer Kushmaro
    Reply
    Author

    Hi Raanan, well, currently the vCAC ODATA API is not documented externally, as it is actually being re-written with full documentation.
    Specifically, most of the use cases are covered by custom properties for you to use. For example, a VMs IP address can be easily obtained by using VirtualMachine.Network0.Address custom property. If you want to research the API you can connect via LINQPad and see what is exposed if i’m not mistaken.

    I’ll mention the fact, that I was able to get to this information by myself , with some reverse engineering actually.

      Harvey Specter
      Posted at 1:07 am November 28, 2013
      Raanan Ikar
      Reply
      Author

      Omer, thank you. Your response is excellent. I will certainly prepare a vCAC CDK env, and investigate the API library further with LINQPad. I figured there was a way to fetch a wider range of data. Do you also know by any chance what a ExecuteSSHScript would entail? In Powershell, I know that when we wish to invoke the PS from vCAC, we must replace in our script any $args[…] that our script would expect from standard in, with hard variables $machineName , and assign these vCAC properties variables. When imported into vCAC repository , these PS scripts then run properly and take the inputs from vCAC. Do we do this for Linux-based bash scripts too? E.g. upload a Bash script that also has $1, $2,etc stdin variables replaced with variables referencing the vCAC properties?

Leave a Reply

Navigation