Cohesity and vRealize Automation (vRA) Day 1

February 13, 2017


Adding all instances from vRA catalog request to protection job

By Dana Gertsch, Consultant, Kovarus

In my previous article, I discussed how to use the recently released Cohesity REST API to enable Backup as a Service (BaaS) within VMware vRealize Automation. In this article, I’ll discuss the workflow which adds all the virtual machine instances from a single vRA catalog item request.

I had to make some design decisions along the way. The main one was to either update the protection job every time a machine was ready, or wait until all the machines in a request where ready. One of my goals was to minimize the REST calls, so waiting until the entire request was complete made the most sense.

Here is a screenshot of the workflow. I’ll discuss the elements throughout this article.


My approach was to kill off every workflow run, except the first one. The Sleep element pauses the workflow for up to 10 seconds. Once awake, the workflow will Get properties from the EBS payload. I’m only concerned with the protection job name, and the request ID. They will be used by other elements down the line, and will be assigned to vRealize Orchestrator (vRO) attribute.

// get properties from EBS payload
try {
if (payload == null) { throw "Required workflow input not provided: payload"; }
var machine = payload.get("machine") ;
var vCACVmProperties = machine.get("properties") ;
var protectionJobName = vCACVmProperties.get("KPSC.Cohesity.protectionJobNames");
var rootRequestId = vCACVmProperties.get("__Cafe.Root.Request.Id");
System.log("Protection job name " + protectionJobName);
System.log("Root request ID is  " + rootRequestId);
} catch (err) {
                  throw "Could not get the required properties " + err;

Then it checks to see if a vRO configuration element containing the rootRequestId exists. If it does, then the workflow ends with no other action taken. If the attribute doesn’t exist, it creates the record. Here is the logic to check the configuration element.

try {
// Find the Configuration Element by name, then get the elements
var elements = (Server.getConfigurationElementCategoryWithPath("Cohesity")).configurationElements;
// loop through the elements until we find Pending Requests
for each (var element in elements) {
                  if ( == "Pending Requests") {
                  // System.log("Found the element");
    // attempt to get the attribute by name
                                    var result = element.getAttributeWithKey(rootRequestId);
                                    var ceElement = element;
                                    if (result != null) {
                                                      System.log("The WF trigger for " + rootRequestId + " is already created.");
      // This is not the first machine to complete
                                    var firstRun = false;
                                    } else {
    // create the attribute if it does not exist.  This means this machine will run the protection Job WF
                                                      System.log("The attribute was NOT found, adding it now. Will also create the trigger");
                                                      element.setAttributeWithKey(rootRequestId, "Some value")
                                    var firstRun = true;


} catch(err) {

At this point I should only have a single workflow running. After creating a lock, I find the CatalogItemRequest, which is fed into a workflow which waits until the request is complete.

At this point we are ready to start communicating with Cohesity. They use a bearer token rather than the traditional username and password. The action cohesityGetBearerToken logs in and returns the token and is stored in a vRO attribute.

The element Get Protection Job returns the Cohesity ID for the vCenter managing the new VMs and the protection job Id, assigning them to a vRO attribute.

Refresh protection source is fired to force a Cohesity discovery of the new machines. The workflow then “Sleeps” for 60 seconds to allow the refresh to complete.

Now I’m ready to start the heavy lifting. coheistyGetVMNamesFromRequestResources action makes a REST call to vRA using the vCACCAFERestClient, and returns the names of all the VMs in the request.

try {
System.log("Getting vmNames from Request Resources");
var endpoint = "";
var restClient = vCACCafeHost.createRestClient(endpoint);
// System.log(restClient.getUrl());
var resourceUrl = "/consumer/requests/" + rootRequestId + "/resources?limit=200";
// System.log("resourceUrl " + resourceUrl);
var response = restClient.get(resourceUrl);
// System.log(response.getBodyAsString());
// create an array to hold vmNames
var vmNames = new Array();
var responseJson = response.getBodyAsJson();
// find all the Virtual Machines, then push their names into an array
for each (var item in responseJson.content) {
	// System.log("The type ID is " + item.resourceTypeRef.label);
	if (item.resourceTypeRef.label == "Virtual Machine") {
System.log("We found " + vmNames.length + " Virtual Machines");
return vmNames;
} catch (err) {
	throw "Could not get vmNames from Request Resources " + err;

Next we talk to Cohesity to obtain the name and protection source Id’s for each VM, using cohesityGetProtecionIdForVMsByName . This action returns a vRO Property Object which will be used to add the VMs to the Protection Job, and to update the vRA Entity.

Add VM’s to Protection Group  makes two REST calls. The first get the protection job object which includes array of currently protected VMs (by ID). The new IDs are extracted from the Property Object, and the protection job object is updated (by adding the new machine IDs). The second REST call updates the protection job.

try {
System.log("Add VM's to Protection Group");
// extract newProtectionSourceIds from cohesityVMProperties
var cohesityKeys = cohesityVMProperties.keys;
// array to hold the SourceIds
var newProtectionSourceIds = new Array();
for each (var key in cohesityKeys) {
var restOp = new RESTOperation("Add VM to protection job"); // Define the name of the new operation
restOp.method = "PUT"; // How is data sent to the api when called. POST mean we send data to the api.
restOp.urlTemplate = "/protectionJobs/{protectionJobId}";
restOp.defaultContentType = "application/json";
var jobId = protectionJobId;
var inParametersValues = [protectionJobId];
operation = restHost.addOperation(restOp); // Add defined operation to rest host defined in "restHost" attribute
// System.log(jobId);
// This is the new way, we only want to change the ProtectionSourceId array
// convert contentAsString to an object
var jsonResponse = JSON.parse(contentAsString);
var sourceIds = jsonResponse[0].sourceIds;
System.log("sourceIds = " + sourceIds);
System.log("newSourceIds = " + newProtectionSourceIds);
// Update SourceIds object value
jsonResponse[0].sourceIds = newProtectionSourceIds.concat(jsonResponse[0].sourceIds);
System.log("Updated sourceIds is " + jsonResponse[0].sourceIds);
// convert it back to text so we can use it in the body
// We only need the body from array element 0
var content = JSON.stringify(jsonResponse[0]);
var request = operation.createRequest(inParametersValues, content); // Create request to api
// set the headers, specifically the authorization
request.contentType = "application\/json";
// System.log("Request: " + request);
// System.log("Request URL: " + request.fullUrl);
//Customize the request here
//request.setHeader("headerName", "headerValue");
request.setHeader("Accept", "application/json");
request.setHeader("Authorization", bearerToken);
var response = request.execute(); // Execute request and store returndata in "response"
System.log("Update protection job returned status code: " + response.statusCode);
var contentAsString = response.contentAsString;
System.log("Content as string: " + contentAsString);
// System.log("Response: " + response);
if (response.statusCode != 200) {
	throw "Adding VM's to the protection group did not succeed, with error " + response.contentAsString;

System.log("Status code: " + response.statusCode);

} catch(err) {
	throw "Could not add VM to protection job " + err;

The last significant action cohesityUpdateEntityPropertiesOnCohesityRequest , uses the Property Object we created earlier to add custom properties to each VM. These properties are used by another workflow to remove the machine from the protection job when the machine is disposed.

try {
System.log("Updating properties on requested machines");
// input vmNames, vCAC:VCACHost
var model = "ManagementModelEntities.svc";
var entitySetName = "VirtualMachines";
// will use property keys instead
var vmNames = cohesityProperties.keys;
for each (var name in vmNames) {
var property = new Properties();
// var name = "Npt-vra-0471"; // test machine
var entities = vCACEntityManager.readModelEntitiesByCustomFilter(, model, entitySetName, property, null);
// System.log(entities.length);
// System.log("Name is " + entities[0].getProperty("VirtualMachineName"));
var vCACVmEntity = entities[0];
var jobIdPropertyName = "KPSC.Cohesity.protectionJobId"
var jobIdPropertyValue = protectionJobId.toString();
var sourceIdPropertyName = "KPSC.Cohesity.protectionSourceId";
// get the protectionSourceId from the property
var sourceIdPropertyValue = cohesityProperties.get(name).toString();;
//Auto generated script, cannot be modified !
// Update protectionJobId
var result = System.getModule("com.vmware.library.vcac").addUpdatePropertyFromVirtualMachineEntity(host,vCACVmEntity,jobIdPropertyName,jobIdPropertyValue,false,false,false,false) ;
var result = System.getModule("com.vmware.library.vcac").addUpdatePropertyFromVirtualMachineEntity(host,vCACVmEntity,sourceIdPropertyName,sourceIdPropertyValue,false,false,false,false) ;
return "Successfully updated properties on requested VM's";
} catch(err) {
throw "Could not update properties on requested VM's " + err;

The last two elements remove the configuration element holding the request Id, and releases the vRO lock.

This article covered a lot. The following examples were provided:

Cohesity REST API
Get Virtual Machine data
Force a vCenter data collection
Update a protection job with the new VMs

vRealize Automation
Monitored the Request state, waiting until it was complete
Used vCACCAFERestClient to get information about the resource request
Update the vCAC Entity with the protection job Id, and virtual machine Id

vRealize Orchestrator
Use Configuration Elements to store settings between workflow runs
Set and removed locks

Some additional integrations being finalized include: run protection job on demand, clone virtual machine, restore virtual machine, and add unprotected VM to protection job. The entire package including how to configure vRA should be publically available in the very near future.