vRealize Automation 7. How to get Deployment Name and Virtual machines from a deployment

In vRealize Automation 7, we have a deployment now that contains all the resources. This is different to how it worked previously. But how do we get information about the deployment, so in a case that we need to update the owner of a deployment if we have deployed a composite blueprint using XaaS?

Here is  snippet of code I use to determine what is what in the deployment.

screen-shot-2016-11-11-at-16-04-36

The key is once you have found the catalogue resource, this line determines whether it is the deployment or virtual machine.

var catResources = vCACCAFEEntitiesFinder.findCatalogResources(cafeHost);
var resourceName = "<deployment name>;
for each (resource in catReosurces){
    if (resource.resourceTypeRef.getLabel() == "Deployment")) +
    resource.getName() == resourceName;
        catalogResource = resource;
break;
}

The getLabel() tells you whether it is a virtual machine or whether its the deployment. Now , once you have the catalogue resource, you can get the deployment and execute a change owner on the deployment.

var operations = catalogResource.getOperations();
var operationName = 'Change Owner';

for each(op in operations){
    System.log(workflow.currentWorkflow.name + ": " + op.getName() +
    " operation is available on this catalog resource");
    if (op.getName() = operationName){
        System.log(workflow.currentWorkflow.name + ": " + op.getName() +
        " operation identified and selected");
        changeOwnerOperation = op;
        break;
    }
}

Now we have the operation of on the deployment, we can pass that in to the requestResourceAction in vRealize Orchestrator and submit the change owner process.

The inputs to the resource action requires the vCACCAFE:ConsumerResourceOperation and the payload for the new user. The payload is a property object. as follows:

ownerProperties = new Properties();
ownerProperties.put("provider-NewOwner", newOwner);

This helps go some way to changing the owner of a deployment. Great is you need to use XaaS to wrap deployments. In future releases, we won’t need to do this as we will have the ability to hide CBP from the catalogue. So we will be able to deploy a catalogue item using the correct owner but the owner won’t see the catalogue item as you can mark it hidden. Hence the logged in user won’t see the catalogue item, but still be entitled to request it.

vRealize Orchestrator – Working with XML and the NSX API

I’ve found that it’s a must to know how to work with XML in vRealize Orchestrator, especially when using the NSX API, and the good news is that it is very simple, once you know a few key commands.

First off, the XML plugin is based on E4X, so searching for help on this XML library is a good start.

Take this XML structure for example, which is for NSX load balance configuration that shows the configuration for pool members:

<loadBalancer>
  <pool>
    <poolId>pool-1</poolId>
    <name>pool-one</name>
    <algorithm>round-robin</algorithm>
    <transparent>false</transparent>
    <member>
      <memberId>member-1</memberId>
      <ipAddress>192.168.0.1</ipAddress>
      <weight>1</weight>
      <monitorPort>80</monitorPort>
      <port>80</port>
      <maxConn>0</maxConn>
      <minConn>0</minConn>
      <condition>enabled</condition>
      <name>member-one</name>
    </member>
    <member>
      <memberId>member-2</memberId>
      <ipAddress>192.168.0.2</ipAddress>
      <weight>1</weight>
      <monitorPort>80</monitorPort>
      <port>80</port>
      <maxConn>0</maxConn>
      <minConn>0</minConn>
      <condition>enabled</condition>
      <name>member-two</name>
    </member>
  </pool>
</loadBalancer>

Notice there are multiple member XML nodes, one for each pool member. That makes sense as you would have mor ethan one pool member in a NSX load balancer.

You can delete nodes by converting the XML into an object and using the delete command in Javascript. So something like this:

var xmlObj = new XML(xml);
delete xmlObj.pool.member[0];

So this would delete the first member node and all the child nodes but what happens if you need to delete a specific node, say the 192.168.0.2 pool member, or any member for that matter.

In order to do this, you need to find the index. Note that E4X is zero based, so the first member node is index 0 , the second member node is at index 1 etc..

So you need to find the index number for 192.168.0.2. Here’s a script to do this.

// Convert the XML to a XML document object
var document = XMLManager.fromString(xml);

//Search for member element by tag name
var members = document.getElementsByTagName("member");

// Set a marker so we can break in the loop
var memberFound = false;
// Now iterate using i and starting from 0 (remember E4X is zero based.
for (i = 0; i < members.length; i++){

// Now get all the child nodes for the first member.
var childNodes = members.item(i).getChildNodes();

// Iterate through the child node.
for (j = 0; j < childNodes.length; j++){

// Search for your IP address.
if (childNodes.item(j).textContent == "192.168.0.2"){

// Now take the value of the iterator for the member iteration, not the member nodes.
// In this case, it is 1.

System.log(childNodes.item(j).textContent + " found at index " + i);

// Set you flag as you've found the IP and do not want to iterate further.
memberFound = true;
break;
}
}
if (memberFound) {break;}
}

Now you can delete the member using the iterator value. Note that E4X is zero based, so the member-one node is at index 0, member-two is at index 1 etc..

// Create the xmlObj, although we did set this up above.
var xmlObj = new XML(xml);

// note, you need to have the value for i, which is 1 in this case
delete xmlObj.pool.member[i];

But what happens if you what to append an element with child nodes? Say you want to add this XML to the main xmlObj.

var newMemberXml = "<member>
      <memberId>member-3</memberId>
      <ipAddress>192.168.0.3</ipAddress>
      <weight>1</weight>
      <monitorPort>80</monitorPort>
      <port>80</port>
      <maxConn>0</maxConn>
      <minConn>0</minConn>
      <condition>enabled</condition>
      <name>member-three</name>
    </member>"

We can use the new XMLList() object type. An XML List is a linear sequence of XML nodes.

var xmlNewObj = new XMLList(newMemberXml);

// Create the xmlObj, although we did set this up above.
var xmlObj = new XML(xml);

// create the new xml object you wish to append
var xmlNewObj = new XMLList(newMemberXml);

// Append the xmlNeObj to the xmlObj.pool node
System.log(xmlObj.pool.appendChild(xmlNewObj));

This will add the new member node and its child elements to the main xmlObj.
So using delete and childApend(obj) can get you a long way.

Tip:

I use resource elements to hold XML structure in vRealize Orchestrator. Most structures, say to configure a load balancer or to add a node, have static element nodes.

So in order to change the resource element, you can set placeholders in your XML resource element. For example:

<monitor>
   <monitorId>monitor-1</monitorId>
   <type>http</type>
   <interval>10</interval>
   <timeout>15</timeout>
   <maxRetries>3</maxRetries>
   <method>GET</method>
   <url>{monitor_url}</url>
   <expected>{monitor_expected}</expected>
   <name>http_service_monitor</name>
   <send>{monitor_send}</send>
   <receive>{monitor_receive}</receive>
</monitor>

You can then use the following code to replace the placeholders in the curly brackets with values from vRO attributes or input parameters (addHTTPMonitor is the resource element)

var content = addHTTPMonitor.getContentAsMimeAttachment().content;

var monitorContent = content.replace("{monitor_url}", monitorUrl)
	.replace("{monitor_expected}", monitorExpected)
	.replace("{monitor_send}", monitorSend)
	.replace("{monitor_receive}", monitorReceive)

So once you have your XML structure from the resource element, append this using the childApend(obj) method to add the XML element and node to the main XML structure.

vRealize Orchestrator 7 VAPI vSphere tags workflow

I created a workflow using the VAPI plugin to assign vSphere tags to a VC:VirtualMachine object.

You will need to import the package, then configure VAPI with your vCenter endpoints by following these instructions:

1 – Run the Import VAPI metamodel workflow

2 – Run the Add VAPI endpoint workflow

Both workflows take the same inputs, but you must run the workflows in that order. Screen shot of inputs as follows:

Screen Shot 2016-07-19 at 22.56.04

 

Once you have configured your VAPI endpoints, download the following package from github

com.virtualdevops.tags.package

Import the package and then the following workflows and actions.

Screen Shot 2016-07-19 at 23.02.25

Screen Shot 2016-07-19 at 23.03.11

Run the Add tag to VC vm workflow (highlighted in the package screen shot above), and as long as you have configured VAPI endpoints, you can add vSphere Tags and vSphere Categories to a VC:VirtualMachine object.

10_26_38_40

  • The vCenter Virtual Machine is the VC:VirtualMachine object
  • The VAPI Endpoint drop down list should contain all your VAPI endpoints
  • The Create new Tag Category allows you to create a new Category
  • The Tag Category displays existing tag categories configured on your VAPI Endpoint
  • The Tag Name is the name of the tag you wish to create
  • The Tag description is the description and is optional

Code is more of an example, as I found the OOTB VAPI plugins for tags pretty limited. You can move the input parameters to attributes as desired and pass in values for the tag name using maybe an API call to a SNOW or CMDB to get values for your tag name.

Any issues, send in a comment.

 

vRealize Cloud Client pagesize configuration

When running the vRealize Cloud Client CLI tool, the default page size is set to 25. This means that any command you run will return the 25 items on a page. Sometime you may have more than 25 items, for example for xaas-blueprints

Screen Shot 2016-06-27 at 09.25.14

You can include this parameter to set the pagesize

vra catalog list --pageSize 50

This will return 50 items per page.

However, you can set the default page size in your cloudclient configuration by configuring the cloudclient.config file on the virtual machine you are running cloud client on. For example:

vi ~/.cloudclient/cloudclient.config

And here is an example configuration

Screen Shot 2016-06-27 at 09.29.31

default.page.size can be set to any number you want.

 

 

 

Creating multiple log files using Python logging library

I was looking at the Python logging library as I needed to create 2 log files for different logging purposes. I ended up creating the following Python log functions.

#!/usr/bin/env python
import logging

LOG_FILE_ONE = "/var/log/one.log"
LOG_FILE_TWO = "/var/log/two.log"

def main():

    setup_logger('log_one', LOG_FILE_ONE)
    setup_logger('log_two', LOG_FILE_TWO)

    logger('Logging out to log one...', 'info', 'one')
    logger('Logging out to log two...', 'warning', 'two')

def setup_logger(logger_name, log_file, level=logging.INFO):

    log_setup = logging.getLogger(logger_name)
    formatter = logging.Formatter('%(levelname)s: %(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
    fileHandler = logging.FileHandler(log_file, mode='a')
    fileHandler.setFormatter(formatter)
    streamHandler = logging.StreamHandler()
    streamHandler.setFormatter(formatter)
    log_setup.setLevel(level)
    log_setup.addHandler(fileHandler)
    log_setup.addHandler(streamHandler)

def logger(msg, level, logfile):
 
    if logfile == 'one'   : log = logging.getLogger('log_one')
    if logfile == 'two'   : log = logging.getLogger('log_two') 
    if level == 'info'    : log.info(msg) 
    if level == 'warning' : log.warning(msg)
    if level == 'error'   : log.error(msg)

if __name__ == "__main__":

    main()

In the main() function, we set up a logging instance. We do this for both LOG_FILE_ONE and LOG_FILE_TWO.

    setup_logger('log_one', LOG_FILE_ONE)
    setup_logger('log_two', LOG_FILE_TWO)

This uses standard logging python library. The formatter is important as that is how the log entries look in the log file (below). Here is mine:

formatter = logging.Formatter('%(levelname)s: %(asctime)s %(message)s', 
            datefmt='%m/%d/%Y %I:%M:%S %p')

Have a look at this online doc from Python.org for more info on the formatter method.

https://docs.python.org/2/library/logging.html#formatter-objects

Once we set up the logging instance, including the file streamer and handler, we can then use those instances,  in this case log_one or log_two.

Both have different log file paths /var/log/{one.log,two.log}.

We then call the logging function, telling it what logging instance to use (log_one or log_two) and we also pass in what log level we want (info, warn, debug).

    logger('Logging out to log one...', 'info', 'one')
    logger('Logging out to log two...', 'warn', 'two')

Interesting, we get this output when we run this script.

INFO: 01/01/2016 01:01:01 AM Logging out to log one…

Notice we do not get WARNING being logged.

That is because of this:

def setup_logger(logger_name, log_file, level=logging.INFO):

Change level=logging.WARN, and this happens:

INFO: 01/01/2016 01:01:01 AM Logging out to log one...
WARNING: 01/01/2016 01:01:01 PM Logging out to log two...

So, pretty handy and you can create as many log files as you need…

Updating vRA ASD Service Blueprint workflows

There isn’t an easy way to find out what vRealize Orchestrator workflow is associated to a vRealize Automation Service Blueprint. You can query the vPostgres database to find out the workflow ID as follows:

1 – Log in to vPostgres and connect to the vcac database

2 – Run the following SQL command

vcac=# \x on;
Expanded display is on.
vcac=# select * from asd_serviceblueprint;

This should output something similar to this:

-[ RECORD 1 ]------------------------------------------------
id | 850b9e17-024e-44f7-9831-a5651a5d6e0f
description | This is a workflow description.
name | My XAAS workflow
status | 1
tenant | vsphere.local
workflowid | 1eea8b02-15e8-41b8-992e-3df1cd8e4b99
baseform |
outputparameter | ea001bf4-d43f-4c74-a010-b6027c7ecbdf
catalogrequestinfohidden | t
version | 1.0.0
-----------------------------------------------------------

You can change the vRealize Orchestrator workflow that gets called by a vRealize Automation service blueprint pretty easily, by changing the workflow ID value in the vPostgres database

vcac=# update asd_serviceblueprint 
set workflowid='ad9e2cc2-2efa-44c1-a574-6a02bec2f998'
where id = '9d6510ad-24a6-4f0c-adc8-736cc3e99d77';

This will change what workflow gets executed without redeploying the ASD form. It’s handy when you want to clone the ASD service blueprint and actually change the underlying workflow to test something new, without having to rebuild the ASD form.

You can also run a vRealize Orchestrator workflow using the below javascript to find out what the name is using the workflow ID

wfId = '9d6510ad-24a6-4f0c-adc8-736cc3e99d77'
System.log("Workflow name: " + Server.getWorkflowWithId(wfId).name);

 

All of this can be managed by creating your own service blueprint and publishing as a catalog item..