Purpose:
The purpose of this post is to show how to build XaaS services in vRealize Automation (vRA) by using available API’s in vRealize Orchestrator (vRO). Target audience for this post is System Admins, Cloud Admins etc. who are not full fledged developers but has some experience in scripting and build Blueprints in vRA. Also in the process this post will clarify how to use vRO and also how to explore API structure and use them in building custom workflows.
Introduction:
First, a bit of background of this post. Recently, I got a request from a customer to build a custom workflow for the following use case:
Build a catalog item in vRA which when requested will do the following:
- It should have a Form which does the following
- Shows a list of available business groups in tenant. User should be able to select one of the Business Groups
- A list of all available entitlements. User should be able to select one or multiple Entitlements
- Let the user input a user name
- Once the above information is provided and the user finishes the request, provided username should be added to the selected Business group and the entitlements.
Obviously, all of the above tasks are typically done through normal admin tasks in vRA, but giving this workflow will let the user streamline the requests and delegate the tasks. By default, users will be part of a group where they can run this workflow. So, they can run this workflow and make themselves part of the business groups and entitlements. For security reasons there will be approval policies associated with the workflow so that all the requests will be moderated.
There are no out of the box workflows available which we can use to do this. To build the above we will require building a custom workflow in vRO and exporting it as a XaaS item in vRA.
It is very easy to build workflows in vRO using other pre-defined actions or workflows. But it becomes a bit complicated when none of the pre-built workflows or actions will work for you and you need to write own Javascript using the API’s. It seems for normal non-developer community there is not enough documentation available which explains the workings. There are few available blogs explaining things a bit but nothing clears the finer points.
So, this post tries to explain those points while building the above solution step by step.
Few Concepts before we start:
Before I go ahead and dive into building the solution let’s cover some basic concepts:
General programming perspective:
API: Typically, a program has two interfaces, GUI which is mostly used by Human Users and another is API (Application Programming Interface) through which another program or piece of software interact with the program. Using API, we can programmatically communicate with another software.
Class: In Object-Oriented Programming, a Class is what a Blueprint is in vRealize Automation. They define the structure but is not the actual implementation. We use this structure to declare objects.
Object: An Object is the actual representation of a running entity. They are similar to what a running workload is in vRealize Automation. Actual workloads are the implementation and Blueprint in the structure. So, Class is like Blueprint but Object is the deployed workload from the Blueprint.
Method: These are the pre-defined tasks that can be performed on the Objects. Taking the similar analogy, methods are tasks that can be performed on the workloads. For example, “Power On”, “Power Off”, “Suspend” are the tasks that can be performed on a deployed VM in vRA, similarly, length() is a defined method in a string object.
Attribute: These are the properties of an Object. For example, name, amount of RAM etc. of a VM, are the properties of that VM. Attribute is similar properties of an object.
vRealize Orchestrator – (vRO) Perspective:
Action: Actions are small unit of program which can take multiple inputs but always return a single value. They can be perceived as a Function which when called does certain tasks and return a single value (the value may be of void type).
Module: A module is a collection of Actions.
Implementation in vRO:
Decision Making process:
- Requirement: We must show a form where user will provide input.
Process: We will take help of Presentation option in vRO to ask for the input from users. We will build a Form in vRA to show the required information.
- We need to pre-populate the form with Business Group and Entitlement list from current environment.
Process: We will take help of Actions to achieve this
There is no Out of the Box defined workflow or Action which will give us a list of all the Business Groups or Entitlement. So, we will create two custom Actions which when run will return a list of Business Groups which we will use to pre-populate the form.
Actions:
The first custom action is “listBusinessGroups”. This script will return a list of Business Groups in Array of String format. The code regarding this is provided below:
//Defining the variable of array of strings type which will hold the business group names var bgNames = []; // Finding the CAFÉ host and then the Business Groups in that Tenant var cafeHost = Server.findAllForType("vCACCAFE:VCACHost")[0]; var businessGroups = vCACCAFEEntitiesFinder.getBusinessGroups(cafeHost); // Storing the names of all the Business Groups in the variable bgNames for (i=0; i < businessGroups.length; i++) { bgNames.push(businessGroups[i].name); } // returning the variable bgNames return bgNames;
Next action item is “listAllEntitlements”. When run, this script will return a list of available Entitlements. Code regarding this action is provided below
// Defining the variable type of array of strings to hold the entitlement names var entitlements = []; // Finding the CAFÉ host and the entitlements var cafeHost = Server.findAllForType("vCACCAFE:VCACHost")[0]; var entitlementlist = vCACCAFEEntitiesFinder.findEntitlements(cafeHost); // Storing the entitlement names in the variable entitlements for ( i=0; i<entitlementlist.length; i++){ entitlements.push(entitlementlist[i].name) } // returning the variable with entitlements name return entitlements;
Main Workflows:
Next we will write the main Workflow to add the user to selected business group and entitlements. The workflow name is “addUserToBG-Entitlements”. The main workflow will have two scriptable tasks, one for adding user to Business Group and another for adding user to entitlements. Details of this workflow and the scriptable tasks are provided below.
The Inputs:
Name | Type | Description |
bgName | String | Business Group where user needs to be added |
userName | string | User name to be added |
entitlementnames | Array/string | List of entitlement names |
One important point to note here, both the actions which we already defined returns an “Array of Strings” as output, but here bgName is a String whereas entitlementnames is an Array of String. This is because we want user to select a single Business Group, whereas they can select multiple entitlements.
Attributes:
Name | Type | Description |
businessGroups | Array/vCACCAFE:BusinessGroup | List of Business Groups |
finalBG | vCACCAFE:BusinessGroup | Business Group where user needs to be added |
vCACACAFEHost | vCACCAFE:VCACHost | CAFE Host |
entitlement | vCACCAFE:Entitlement | Entitlement Where user to be added |
entitlementslist | Array/vCACCAFE:Entitlement | A list of all the entitlements |
In vRO, attributes are Global variables, we can use these variables from any workflow and they are consistent throughout the lifetime of the main workflows. For more information on different variables please read the wonderful blog at http://www.vvork.info/2015/06/variables-in-vrealize-orchestrator.html.
Schema:
Provided below is the schema presentation of the workflow:
The first and major step is to define the form which will be presented to user at runtime. We can do that using the Presentation Tab. The input variables will automatically be shown in Presentation tab. We need to select the variables and then add parameter for them. For parameter type we will select “Predefined Answer” and for Value we will select OGNL. In OGNL type we will select the action items we defined earlier. Provided below are the screenshots for them.
Note for the values we selected the respective action items.
Next we will focus on the individual Scriptable tasks.
Also provided below is the Visual binding of the parameters for the first scriptable task (Add user to Business Group):
Code for the first scriptable task is provided below:
// Encapsulating the entire script in try - catch statement try { // Getting a list of all business groups businessGroups = vCACCAFEEntitiesFinder.getBusinessGroups(vCACACAFEHost); // Running a for loop to match business group name with the user // provided business group name. Once the match is found get the Business // group object for(i=0; i< businessGroups.length;i++){ if (bgName == businessGroups[i].name){ var finalBG = businessGroups[i]; break; } } // Getting a list of all existing users in the Business Group var userNames = finalBG.getUsers(); var size = 0; if (userNames){ size = userNames.length; } var alreadyExists; alreadyExists = false; if (size){ // Checking to see if the user already exists in the Business group for (var j = 0 ; j < size ; j++ ) { if (userName == userNames[j]) { System.warn("User " + userName + " is already added to the Business Group "+finalBG.getName()+". The user will be skipped."); alreadyExists = true; break; } } } if (!alreadyExists) { // If this is true that means user is not already present in the BG userNames[size] = userName; finalBG.setUsers(userNames); if(!finalBG.activeDirectoryContaier){ finalBG.setActiveDirectoryContainer(""); } System.log("Adding user to business Group " + finalBG.getName() + "..."); // Adding the user to Business Group vCACACAFEHost.createInfrastructureClient().getInfrastructureBusinessGroupsService().update(finalBG); System.log("User added to Business Group " + finalBG.getName()); } } catch(errorCode){ // In case of any error throw the error System.error(errorCode); throw errorCode; }
Visual Binding for the second scriptable task (Add user to Entitlements) is provided below:
Code for the second scriptable task is provided below:
// Encapsulating the entire script block in try - catch statement try { // getting a list of all the entitlements entitlementslist = vCACCAFEEntitiesFinder.findEntitlements(vCACACAFEHost); // Running the loop to get the entitlement which user specified // entitlementnames holds all the entitlement names which user specified // entitlementlist holds the list of all the entitlements. // note entitlementnames is an array of strings while entitlementslist is an array of entitlement object for( i =0; i<entitlementnames.length; i++){ for( j=0; j<entitlementslist.length; j++){ if ( entitlementnames[i] == entitlementslist[j].name){ entitlement = entitlementslist[j]; break; } } // at this stage we found our entitlement object // validating the object System.getModule("com.vmware.library.vcaccafe.util").validateObject(entitlement, "Entitlement"); // Getting the CAFE host object for the entitlement var host = vCACCAFEEntitiesFinder.getHostForEntity(entitlement); // Getting the entitlement service object var client = host.createCatalogClient().getCatalogEntitlementService(); var alreadyExists; alreadyExists = false; // Checking to see if the user already exists in the entitlement for (var j = 0 ; j < entitlement.getPrincipals().length ; j++ ) { if (userName == entitlement.getPrincipals()[j].getRef()) { System.warn("User " + userName + " is already assigned to the entitlement "+entitlement.getName()+". The user will be skipped."); alreadyExists = true; break; } } if (!alreadyExists) { // This means user is not already in Entitlement var principal = new vCACCAFECatalogPrincipal(); principal.setType(vCACCAFEPrincipalType.USER); principal.setRef(userName); principal.setTenantName(host.tenant); System.getModule("com.vmware.library.vcaccafe.util").addElementToList(entitlement, "getPrincipals", principal); System.log("Assigning user to entitlement " + entitlement.getName() + "..."); client.update(entitlement); System.log("User assigned to entitlement " + entitlement.getName()); } } } catch(errorCode){ System.error(errorCode); throw errorCode; }
The explanation for the codes and other detailed discussion points are provided in the video. Mainly, the following points are covered in the video:
- General Modes of vRO
- How to create custom actions and workflows
- How to explore and use API’s
- Details of the above provided codes
- How to build a XaaS item in vRA
- How to build a Form in vRA
- Final result
Provided below is another short video to explain how to explore the API in vRO and use them in Scripts.
Conclusion:
This post explains the API explorer in vRO and how we can use them to write custom scripts and workflows to build XaaS services in vRealize Automation. Do let me know your feedback on this topic or any other topic that you want me to cover.