When working with vRealize Automation, monitoring the requests tab on the tenant portal can be really usefull. Knowing when a workflow fails for a tenant and act on this as soon as possible, can raise your tenant happiness. Keeping an eye out for failed requests with one tenant is doable, although tedious. But when your vRealize Automation environment increases and you get more tenant, you will want another way to keep track of the requests.

For this reason I wrote a Python script that will get the requests per tenant and show those failed yesterday and today. The results are then shown on a webpage, as shown in thescreenshot below.

The script is still a work in progress, but I wanted to share the initial piece of the code. There are actually 3 files used, one being the Python script en two HTML files.

Python script:

from flask import Flask
from flask import request
from flask import render_template
import json
import requests
import ssl
import jinja2
from datetime import datetime
import dateutil.parser
import time

app = Flask(__name__)

TenantList = ['TenantA','TenantB']
   
def getTokenTenant (tenant):
   TokenTenant = 0
   tokenURL = 'https://vra.lab.local/identity/api/tokens'
   
   headers = {"Accept": "application/json"}
   headers['Content-Type'] = 'application/json'
   cLoginData = '{"username":"administrator_account","password":"password","tenant":"'+tenant+'"}'

   response = requests.post(tokenURL, headers=headers, params=None, data=cLoginData)
   
   if response.status_code == 200:
	respJSON = response.json()
	TokenTenant = str(respJSON['id'])
   else:
	print "Error retreiving Bearer token"

   return TokenTenant

   
def getRequests ():
   RequestList = []
   
   for tenant in TenantList:
    requestToken = getTokenTenant (tenant)
   
    requestURL = "https://vra.lab.local/catalog-service/api/consumer/requests?%24filter=requestCompletion/requestCompletionState+eq+'FAILED'&%24orderby=requestNumber+desc"

    headers = {"Accept": "application/json"}
    headers['Authorization'] = 'Bearer '+str(requestToken)
   
    response = requests.get(requestURL, headers=headers)
    Temp = response.json()

    RequestList.append (Temp['content'])
    
   return RequestList

def dateTimeFormat(value):
   failuredatedateDay = datetime.strftime(dateutil.parser.parse(value),'%d')
   failuredatedateDay = float(failuredatedateDay)
   failuredatedateMonth = datetime.strftime(dateutil.parser.parse(value),'%m')
   failuredatedateYear = datetime.strftime(dateutil.parser.parse(value),'%Y')
   currentdateDay = time.strftime('%d')
   currentdateDay = float(currentdateDay)
   currentdateMonth = time.strftime('%m')
   currentdateYear = time.strftime('%Y')
   if failuredatedateYear == currentdateYear:
    if failuredatedateMonth == currentdateMonth:
     if failuredatedateDay == currentdateDay or failuredatedateDay == currentdateDay-1 :
      return datetime.strftime(dateutil.parser.parse(value),'%H:%M / %d-%m-%Y')
   return 0  
	
def extractTenantRef(value):
   return value['tenantRef']


@app.route('/')
def index():
	
	jinja2.filters.FILTERS['datetimeformat'] = datetimeformat
	jinja2.filters.FILTERS['extractTenantRef'] = extractTenantRef
	
	TenantRequests = getRequests ()

	return render_template('render.html',TenantRequests=TenantRequests)


if __name__ == '__main__':
   app.run(debug=True, host='0.0.0.0')

As with any python script we start loading the modules and at the bottom of the script we got the index function with the webserver information. Besides those basics there are 4 functions defined:

  1. GetTokenTenant: When making use of the vRealize Automation API you have to request a bearer token. You get this token when you use the right credentials for the specific tenant. The bearer token then allows you to execute API calls for that tenant.
  2. GetRequests: Gets the requests for the tenant and by using a filter we get only the failed ones. And since we want those failed in the last 2 days we sort them in descending order.
  3. DateTimeFormat: The default date description isn’t usefull for our purpose so this function will make it usefull for us.
  4. ExtractTenantRef: The returned object from for the failed requests hold a lot of information. This includes the tenant name aswell, but this in itself is a object to, so I created this small function to retreive the tenant name.

Render.html

{% extends "base.html" %}

{% block body %}
<table cellpadding="15">
<!-- ============ HEADER SECTION ============== -->
<tr>
<td width="50%" valign="middle" style="height: 2px" bgcolor="#FFFFFF"><font size="5">&nbsp;<b>Homelab</b><br /></font><font size="3">&nbsp;Homelab</font></td>
<td width="50%" valign="middle" align="right" style="height: 2px" bgcolor="#FFFFFF"><font size="5">&nbsp;<b>Failed workflows vRA Tenants</b></font></td>
</tr>
<tr><td colspan="2" style="height: 1px; padding: 1px" bgcolor="#009900"></td></tr>
</table>


<table cellpadding="15" >
<tr>
<td width="20%" valign="top" align="center"><b> Tenant </b></td>
<td width="20%" valign="top" align="center"><b> Request Number </b></td>
<td width="20%" valign="top" align="center"><b> Requested By </b></td>
<td width="20%" valign="top" align="center"><b> Requested Item </b></td>
<td width="20%" valign="top" align="center"><b> Submitted on </b></td>
</tr>

{% for Tenants in TenantRequests %}
 {% for Request in Tenants %}
  {% if Request["dateSubmitted"]|datetimeformat != 0 %}
  <tr align="center"> 
   <td width="20%" valign="top" bgcolor="#E6E6E6"> {{ Request["organization"]|extractTenantRef }} </td>
   <td width="20%" valign="top" bgcolor="#E6E6E6"> {{ Request["requestNumber"] }} </td>
   <td width="20%" valign="top" bgcolor="#E6E6E6"> {{ Request["requestedBy"] }} </td>
   <td width="20%" valign="top" bgcolor="#E6E6E6"> {{ Request["requestedItemName"] }} </td>
   <td width="20%" valign="top" bgcolor="#E6E6E6"> {{ Request["dateSubmitted"]|datetimeformat }} </td>
  </tr>
   {% endif %}
 {% endfor %} 
{% endfor %}

<!-- ============ FOOTER SECTION ============== -->
<tr><td colspan="5" style="height: 1px; padding: 1px" bgcolor="#009900"></td></tr>
<tr><td colspan="5" align="center" height="20" >Homelab &copy;</td></tr>
</table>

{% endblock %}

The render.html uses the information retreived by the python script and makes it presentable. The style of the page, including the header are footer are all predefined with HTML. The table with actual information is created by a “for each” loop, breaking out to the python script functions 3 and 4.

Base.html

<!doctype html>

<head>
<style type="text/css">
a {text-decoration: none; color: #000000}
body {font-family: Verdana; font-size: 10pt}
table {width: 100%; height: 100%; background-color:#FFFFFF}
.vprtable {font-size:10pt; color:#FFFFFF; width:100%; border-width: 1px; border-color: #9dcc7a; border-collapse: collapse; height: 10px;}
.vprtable th {font-size:10pt; background-color:#009900; border-width:1px; padding:8px; border-style: solid; border-color: #FFFFFF; text-align:left;}
.vprtable tr {background-color:#82C253;}
.vprtable td {font-size:10pt; border-width: 1px; padding: 4px; border-style: solid; border-color: #FFFFFF; color: #000000;}
</style>
<META HTTP-EQUIV="refresh" CONTENT="300; URL=/">
<title>Failed workflows vRA Tenants</title>
</head>

<body>
{% block body %}{% endblock %}
</body>
</html>

Some more layout stuff is being set by the base.html. This file also sets the refresh interval of the site at 300 seconds. So each 5 minutes you get the latest information about possible failed requests.

As mentioned the script isn’t complete yet. For one I want to add a function that will get all tenants automatically, instead of using a static array. Also I want to see if there is an optimized way of processing the “datetimeformat” function.

If you think this script is usefull or have any suggestions or comments, please feel free to share them below :)


Other articles in the series vRealize Automation: