Configuring vRO to send emails for gmail

Overview

Google allows you to relay up to 2000 emails per rolling 24 hour period, which can be useful for development of workflows via vRO. The steps below are written for standard gmail accounts. If you have a G Suite account then the steps are subtly different in that the SMTP host name is ‘smtp-relay.gmail.com’ and not ‘smtp.gmail.com’. The message per day limit is also increased when using a G Suite account is that you can send up to 10000 messages per rolling 24 hour period. Lastly, when using vRO with a G Suite account security needs to be relaxed within G Suite to permit sending emails from less secure apps.

Required Steps

  1. Start vRO control center service – The service is disabled by default
  2. /etc/init.d/vco-configurator start
  3. Browse to the vRO control center
  4. https://vro-server-hostname:8283/vco-controlcenter/#/
  5. Go to Manage > CertificatesScreen Shot 2018-05-02 at 22.18.10
  6. Click Import > Import from URLScreen Shot 2018-05-02 at 22.20.15
  7. Enter the URL as ‘smtp.gmail.com:587’ or ‘smtp-relay.gmail.com:587’Screen Shot 2018-05-02 at 22.21.53
  8. Review the certificate and then click ImportScreen Shot 2018-05-02 at 22.22.12
  9. Once the certificate is imported you can use the OOTB workflow called ‘Send notification’. The settings used will be as follows:
Input Name Value
smtpHost smtp.gmail.com
smtpPort 587
username gmail email address
password gmail password
useSsl No
useStartTls Yes

 

 

vRealize Orchestrator: Get VM by Name in Large environments

The Challenge

In very large environments, the standard (out of the box methods) of retrieving a specific  virtual machine object by name in vRealize Orchestrator are not particularly efficient and can take a long time to retrieve a particular object. This is of particular concern when using a vRO action to retrieve an external value in a vRA XaaS form. The default timeout for value retrieval is 30 seconds, and although this can be extended (see https://kb.vmware.com/s/article/2144872), the aim should be to retrieve all values in the fastest time possible as opposed to increasing the timeout to a large value.

So, the challenge was set, design a method of retrieval of any VM object within the vRA timeout.

The Options

Out of the box, vRO provides a method of retrieving all virtual machine:

allVMs = VcPlugin.getAllVirtualMachines()

This can be looped through until a specific virtual machine name is found. In small environments this method is absolutely fine as the response time will not be an issue

This can be extended (and made faster) either via including a name:

allVMs = VcPlugin.getAllVirtualMachines(null, vmname)

or by using xpath:

allVMs = VcPlugin.getAllVirtualMachines(null, "xpath:name=\'" + vmname + "\'")

The latter method has issues with case sensitive queries, and using an xpath translation is really slow!

In the environment I was working the former query took many minutes to return data, the latter two took between 45-60 seconds, which was much better, but not quick enough to return the VM object to vRA in less than 30 seconds which was the ultimate goal.

So an alternative solution had to be found…

The Solution

The aim was to get to a situation whereby the smallest possible number of VMs could be retrieved by vRO, which could then be used to search for the exact VM object. In this way the query made to vCenter is much smaller, resulting in a significantly faster response time. Although this information can itself be queried from vCenter, in environments with more than one vCenter this would still be an iterative process which may result in lengthy delays in returning information.

GetVMbyNameviavROps

Fortunately there is a database in many vSphere environments that contains a combined view of the world; vRealize Operations Manager. Each virtual machine object has a number of properties that allow the parent objects of the virtual machine to be readily identified:

  • summary|parentCluster
  • summary|parentHost

vROps also has an API that can be used to retrieve these properties once the internal vROps ID of the object has been determined. The API calls used are:

  • https://hostname/suite-api/api/resources?name&resourceKind=virtualmachine –  the object identifier is included in the response
  • https://hostname/suite-api/api/resource/objectid/properties – the response is queried for the value of the specified property

Unfortunately this only gets us half way. Although we now have the cluster and host that the virtual machine is running on, we need to convert those names into objects that vRO can use.

To speed things up, a cache was created that contains all of the vSphere Clusters in the various vCenter environments. This cache is queried to match the name of the cluster to the cluster object. The cache is updated via a scheduled workflow.

The host object is now retrieved by querying the hosts in the cluster looking for a match for the host retrieved from vROps. This part could be skipped altogether by using a cache containing all ESXi hosts. This was not done in the environment I was working in as the number of hosts would have been very large (> 5000) and the impact of having that many attributes in a configuration element was felt to be excessive.

The final stage is to match the virtual machines of the identified host with the name originally entered. The result is the virtual machine object.

The vRO Package

The package below includes all of the elements needed. Once the package has been imported there is a little bit of configuration that needs to be done:

  1. Add vROps host(s) as REST endpoints (Library > Configuration > Add a REST host). The name given to the REST host will be the one used in the ‘Get VM by Name via vROps’ workflow that can be used to test the action. Use basic authentication and configure certificate handling as appropriate
  2. Edit the resource configuration ‘GetVMbyName/vROpsHosts’. Edit the ‘vROpsHosts’ attribute and add each configured vROps host into the arrayScreen Shot 2018-05-01 at 20.45.25
  3. Edit the resource configuration ‘GetVMbyName/allVCSDKConnections’. Edit the ‘vcSDKConnections’ attribute and add each vCenter SDK connection as appropriateScreen Shot 2018-05-01 at 20.46.47
  4. Run the ‘Create Cluster Cache’ workflow and then validate that the ‘GetVMyName/ClusterCache’ resource configuration has all expected clustersScreen Shot 2018-05-01 at 20.50.01

The ‘Get VM by Name via vROps’ workflow can now be run. Enter the name of the virtual machine to search for and the name of the vROps host to use

Screen Shot 2018-05-01 at 20.55.15

The output can be viewed either via the log:

Screen Shot 2018-05-01 at 20.56.21

Or by viewing the variables. A positive result will include a virtual machine object in the ‘vm’ variable

Screen Shot 2018-05-01 at 20.58.30

The test workflow requires a REST host name to be inputted, although this could set via a field on a vRA form, or additional code written to choose the REST host based on some condition.

Download Package:

GetVMbyNameviavROps

Parsing of XML with vRealize Orchestrator

Parsing of XML is fairly straightforward with vRO, however there is one major gotcha you should be aware of; namespaces.

Depending on the XML content that vRO is trying to parse it may not return any values if certain namespaces are used. One way around this is to do a string.replace on the xml prior to parsing it.

An example of how to parse XML is shown below:

The code below is based on the following XML

<?xml version="1.0" encoding="UTF-8"?>

<CreateITDCIResponse xmlns="http://www.ibm.com/maximo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" creationDateTime="2016-06-22T13:07:11+00:00" transLanguage="EN" baseLanguage="EN" messageID="1466600831635951728" maximoVersion="7 1 20110105-1024 V7118-37"><ITDCISet>
<CI>
<CHANGEBY>Someuser</CHANGEBY>
<CHANGEDATE>2016-06-22T13:07:11+00:00</CHANGEDATE>
<CIID>123456</CIID>
<CINAME>CINAMETEST</CINAME>
<CINUM>CITEST</CINUM>
<ITDCIMANAGEDBY>TBD</ITDCIMANAGEDBY>
<ITDCIOPERATINGENV>TBD</ITDCIOPERATINGENV>
<ITDSERVCONTPLAN>0</ITDSERVCONTPLAN>
<STATUS>VERIFY</STATUS>
<STATUSDATE>2016-06-22T13:07:11+00:00</STATUSDATE>
</CI>
</ITDCISet>
</CreateITDCIResponse>

And this is the vRO code used to extract a specific field, in this case the CIID

// Strip out the namespace definition as vRO doesn't handle the definitions very well

var modifiedXMLString = xmlString.replace('xmlns="http://www.ibm.com/maximo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"',"");


var parsedXML = new XML(modifiedXMLString)

// Check to see whether we have any content

if (!parsedXML) {
 var errorCode = "Invalid XML Document";
 throw "Invalid XML document";
}

// Validate that only 1 CI has been returned

if (parsedXML.ITDCISet.CI.length() != 1) {
 var errorCode = "Invalid number of CIs returned";
 throw "Invalid number of CIs returned";
}

else {
 for each (CI in parsedXML.ITDCISet.CI) {
 System.log("The CI number is: " + CI.CIID);
 }
 }