How to create a custom JS class in vRO [CB10110]

  1. What is a class?
  2. But…wait! vRO doesn’t support ES6
  3. How to create a local class in vRO?
  4. Create a globally callable class in vRO
    1. Steps
    2. It’s time to test it
  5. Advantages
  6. Limitations
  7. References

What is a class?

A class is a template for creating objects. It encapsulates data and functions that manipulate data, grouping data and functionality together.

Classes are based on object-oriented programming concepts. As JavaScript is not an object-oriented programming language at its core, JavaScript classes are considered syntactic sugar.

What this means is classes are there as a visual aid in Javascript. They were introduced in EcmaScript2015 (ES6) to allow developers to follow object-oriented programming patterns in a cleaner way. It’s just one of the many reasons that ES6 is so great.

class Pen {
    constructor(name, color, price){
        this.name = name;
        this.color = color; 
        this.price = price;
    }
    
    showPrice(){
        console.log(`Price of ${this.name} is ${this.price}`);
    }
}
const pen1 = new Pen("Marker", "Blue", "$3");
pen1.showPrice();

But…wait! vRO doesn’t support ES6

Aria Automation Orchestrator (or vRO) doesn’t support ES6. It uses ES5.1 and in ES5.1, there is no such keyword as class. However, we can still use function construct to create a psuedo-class in vRO because a class is technically a function with prototype-based inheritance.

Before classes existed, prototypes were used to emulate classes in JavaScript. A prototype is a default object attached to every JavaScript function and object. Additional properties can be attached to a prototype, which helps us emulate JavaScript classes. We can see that when we transpile a ES6 class to ES5 syntax on Babel.

Transpiling ES6 Class to ES5-style syntax using Babel (loose mode ON)

How to create a local class in vRO?

Let’s see how to create to a class in vRO using similar syntax structure. We can create the same Pen class using function as

function Pen(name, color, price) {
    this.name = name;
    this.color = color;
    this.price = price;
}
Pen.prototype.showPrice = function(){
    System.log("Price of "+ this.name+" is "+this.price);
}
//Calling Pen class locally
const pen1 = new Pen("Marker", "Blue", "$3");
pen1.showPrice();

This will create a class that can be used locally inside a workflow scriptable task or an action. But what if you want to use a class globally in vRO, across actions and workflows, just like any other vRO SDK class. Let’s see how we can create that.

Create a globally callable class in vRO

To create a global class in vRO, we can use the action construct that is easily callable both in Workflows and Actions.

Steps

  • Create a new action module to store your custom classes. eg. in.co.cloudblogger.customclasses
  • Create a new action with class name. eg. Pen
  • Create a function which is basically the pseudo-class very similar to what we did for a local class. But here, we have to return that function. Lets see the example of Pen.
/**
 * @function Pen
 * @param {string} name 
 * @param {string} color 
 * @param {string} price 
 *
 * @return {*} A new Pen instance 
 */
function Pen(name, color, price) {
    this.name = name;
    this.color = color;
    this.price = price;
}

Pen.prototype.showPrice = function(){
    System.log("Price of "+ this.name+" is "+this.price);
}

Pen.prototype.showColor = function(){
    System.log("Color of "+ this.name+" is "+this.color);;
}

return Pen;
  • This class has 3 inputs, so add them as Inputs in action.
  • Set Return type to Any. Or you can also create a Composite Type and set it in Return type.

OR

It’s time to test it

  • Go to a scriptable task or an action where you want to call this Pen class.
  • Call the class action here in the first line.
var Pen = System.getModule("in.co.cloudblogger.customclasses").Pen();
  • Now, instantiate a pen object using the new keyword.
const pen1 = new Pen("Marker", "Blue", "₹30");
  • That’s it. You can call the method/attributes inside the Pen class like any other class.
var Pen = System.getModule("in.co.cloudblogger.customclasses").Pen();

// Pen 1
const pen1 = new Pen("Marker", "Blue", "₹30");
pen1.showPrice();
pen1.showColor();

//Pen 2
const pen2 = new Pen("Roller", "Black", "₹200");
pen2.showPrice();
pen2.showColor();

Advantages

One big advantage of using these global classes is that you can create beautiful and well-organized code for vRO. Other one being the ability to create multiple methods in your class and use them using one object. Ex.

var MathFunctions = {
    sum: function(a, b) {
        return a + b;
    },
    sub: function(a, b) {
        return a - b;
    },
    div: function(a, b) {
        return a / b;
    }

};
return MathFunctions;

var MathFunctions = System.getModule("in.co.cloudblogger.customclasses").MathFunctions();
var sum = MathFunctions.sum(1, 2);
var diff = MathFunctions.sub(10, 2);

Limitations

  • Custom class/Composite type is detected by vRO as a object or Properties. Learn more here.
  • No option to extend classes. I even used Babel to generate a transpiled version of extends
function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function");
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            writable: true,
            configurable: true
        }
    });
    Object.defineProperty(subClass, "prototype", {
        writable: false
    });
    if (superClass) _setPrototypeOf(subClass, superClass);
}

function _setPrototypeOf(o, p) {
    _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
        o.__proto__ = p;
        return o;
    };
    return _setPrototypeOf(o, p);
}

But this throws error InternalError: Changing attributes not supported for Function prototype property

That’s in this post. I hope you like it.

References

  • Babel Transpiler compatible with vRO: You can use to convert any ES6 or TypeScript code to ES5. Don’t forget to change console.log() to System.log().

Trick here is to use loose and forceAllTransforms options in Babel which generates ES5-style code.

https://babeljs.io/docs/babel-preset-env#forcealltransforms

Advertisement

Workflow to run a Workflow over RESTAPI Dynamically [CB10107]

  1. Approach
    1. 1. Trigger WF in same vRO
    2. 2. Trigger WF in Master-Slave setup using Multi-Node Plugin
    3. 3. Trigger WF using Transient REST Host mechanism
  2. Steps
    1. Part 1 Get the Input parameters JSON of the WF that you want to trigger
    2. Part 1 Manually run the WF(to be triggered) just once
    3. Part 2 Time to trigger it remotely

In this post, the idea is to trigger a workflow from a vRO to another vRO over the REST API dynamically (no need to add the remote vRO as Inventory REST Host as we will be using transient hosts, you must have guessed). I have created a WF that you can use to get that functionality. Link to the package here.

Approach

There are multiple scenarios where we have to trigger a vRO workflow from another workflow. And for that, depending on the scope and requirement, We have 3 basic approaches to this.

1. Trigger WF in same vRO

This one is most commonly used through the Workflow editor. What you have to do is to simply add a WF item from the Generic Tab in the WF editor inside another WF. You can then will be able to run the WF synchronously (means the WF will wait for the sub-WF to execute completely and return its status) or asynchronously (that means the WF will run in a different thread and will not return the execution result).

If you want to run a workflow through action, you can also do that using this script in a asynchronous manner. Learn more about it in a post by Umit Demirtas here.

//Auto generated script, cannot be modified !
var workflowToLaunch = Server.getWorkflowWithId("d7c058fb-3f95-4d92-ad17-5d6a856343d4");
if (workflowToLaunch == null) {
	throw "Workflow not found";
}
var workflowParameters = new Properties();
workflowParameters.put("input1",input1Value);
workflowParameters.put("input2",input2Value);
//Add all the inputs needed..//
wfToken = workflowToLaunch.execute(workflowParameters); 

2. Trigger WF in Master-Slave setup using Multi-Node Plugin

The Multi-Node plug-in creates a primary-secondary relation between vRealize Orchestrator servers, which extends in the areas of package management and workflow execution. This plugin comes with vRO out-of-the-box. Learn how to setup Multi-Node plug-in here .

A typical script to trigger a WF in a proxy vRO Server synchronously.

// Id can be viewed in the scripting of the proxy workflows generated for a server
var workflowId = "BD808080808080808080808080808080F0C280800122528313869552e41805bb1";
var tokens = [];
for(var i = 0; i < servers.length; i++) {
	var parameters = new Properties();
	parameters.put("vm", vms[i].id);
	parameters.put("newName", newNames[i]);
	var tmpResult = VCOProxyWorkflowManager.executeSynchronousProxy(servers[i].connectionId, workflowId, parameters);
	tokens.push(tmpResult.get("remoteToken"));
}

Other way would be to trigger them asynchronously. Make sure the proxy workflows exists in local vRO server. Learn more about that here.

VCOProxyWorkflowManager.executeAsynchronousProxies(workflowId, params);

3. Trigger WF using Transient REST Host mechanism

This one is what I would like to share in today’s post. I have created a custom WF through which you can use this approach. Basically, the idea is to utilize the vRO REST API to trigger workflows asynchronously (workflows/{{workflowId}}/executions) and that too using the transient REST host which will not require any configuration to be done earlier. You just need the HTTP-REST plug-in that comes out-of-the-box.

Steps

Part 1 Get the Input parameters JSON of the WF that you want to trigger

Here, in this demo WF, there is one single input input1 with type=string, probably the simplest one. However, head to William Lam’s post on how create a complex input JSON with SDK objects here.

Part 1 Manually run the WF(to be triggered) just once

As you can see above, I have modified the sequence of steps. I have actually created a new action that will prepare the input parameter JSON body by itself. You will find that action (in.co.cloudblogger.customclasses/getWorkflowLastExecutionBody()) in the package itself.

Just 1 thing is needed to be done which is to run the WF to be triggered at least once manually. So that a JSON structure will prepared for the input set of the triggered WF and the action I have created will fetch the last run and automatically prepopulate the “Start WF Execution using REST” WF with the input set of last run.

Part 2 Time to trigger it remotely

  • Download the vRO package from here.
  • Once the package is imported, Go to the Workflow “Start WF Execution using REST” which will be considered as “master wf” here.
  • Provide inputs to this workflow
    • vRO FQDN – Name of the remote vRO where you want to trigger the WF.
    • Username – Username to access remote vRO (User should have permission to Run)
    • Password – Password for the user provided
    • Workflow ID – ID of the Workflow that you want to trigger (find it in your WF URL)
    • Parameter JSON – A structured JSON object with input parameters required to run the remote WF. This will be auto-populated using the new action.
  • Click Run

Critical Values of Certain Datatypes like SecureString or EncryptedString will be hidden in the Payload body. You will have to manually add that missing JSON. For eg. if you see here, the payload has no value field for SecureString.

{
   "parameters":[
      {
         "value":{
            "string":{
               "value":"mayank.goyal"
            }
         },
         "type":"string",
         "name":"username",
         "scope":"local"
      },
      {
         "type":"SecureString",
         "name":"password",
         "scope":"local"
      }
   ]
}

To fix this, you can add something like,

"value":{
            "string":{
               "value":"pa$$w0rd!"
            }
         },

to make the final payload complete to be sent over REST.

{
   "parameters":[
      {
         "value":{
            "string":{
               "value":"mayank.goyal"
            }
         },
         "type":"string",
         "name":"username",
         "scope":"local"
      },
      {
	"value":{
            "string":{
               "value":"Mar#2023"
            }
         },
         "type":"SecureString",
         "name":"password",
         "scope":"local"
      }
   ]
}

  • Once the master WF executed successfully, Login to remote vRO.
  • Go to the WF that was triggered by master WF, click ALL RUNS, you should see the executed run there.
  • In our test run, we passed the Input value as “Triggered over REST by Mayank Goyal” which can be validated here.

You can use this WF inside a Wrapper WF to prepare the inputs or probably inside another WF where you are performing other tasks and that way, you can use it in your automations easily.

That’s it in this post. I hope it will be of some help for you. Thanks for reading. See you on other post. Please subscribe to my newsletter and get latest posts directly in your inbox.

XXE vulnerability affecting VMware vRealize Orchestrator

Source: https://www.vmware.com/security/advisories/VMSA-2023-0005.html


Tip Upgrade your vRO/vRA to version 8.11.1 as soon as possible to overcome this vulnerability.


  1. Impacted Products
  2. Introduction
  3. 3. XML External Entity (XXE) Vulnerability (CVE-2023-20855)
    1. Description
    2. Known Attack Vectors
    3. Resolution
    4. Workarounds
    5. Additional Documentation
    6. Notes
    7. Acknowledgements
    8. Response Matrix
    9. Impacted Product Suites that Deploy Response Matrix Components:
  4. References
  5. Change Log
  6. Contact

Impacted Products

  • VMware vRealize Orchestrator
  • VMware vRealize Automation
  • VMware Cloud Foundation (Cloud Foundation) 

Introduction

An XML External Entity (XXE) vulnerability affecting VMware vRealize Orchestrator was privately reported to VMware. Updates are available to address this vulnerability in affected VMware products.

3. XML External Entity (XXE) Vulnerability (CVE-2023-20855)

Description

VMware vRealize Orchestrator contains an XML External Entity (XXE) vulnerability. VMware has evaluated the severity of this issue to be in the Important severity range with a maximum CVSSv3 base score of 8.8.

Known Attack Vectors

A malicious actor, with non-administrative access to vRealize Orchestrator, may be able to use specially crafted input to bypass XML parsing restrictions leading to access to sensitive information or possible escalation of privileges.

Resolution

To remediate CVE-2023-20855 apply the patches listed in the ‘Fixed Version’ column of the ‘Response Matrix’ below.

Workarounds

None.

Additional Documentation

None.

Notes

VMware vRealize Automation 8.x is affected since it uses embedded vRealize Orchestrator.

Acknowledgements

VMware would like to thank IT.NRW for reporting this issue to us.

Response Matrix

ProductVersionRunning OnCVE IdentifierCVSSv3SeverityFixed VersionWorkaroundsAdditional Documentation
VMware vRealize Orchestrator8.xVirtual ApplianceCVE-2023-208558.8Important 8.11.1NoneNone
VMware vRealize Automation8.xAnyCVE-2023-208558.8Important 8.11.1NoneNone

Impacted Product Suites that Deploy Response Matrix Components:

ProductVersionRunning OnCVE IdentifierCVSSv3SeverityFixed VersionWorkaroundsAdditional Documentation
VMware Cloud Foundation (vRealize Automation)4.xAnyCVE-2023-208558.8Important KB90926NoneNone

References

GitHub Advisory DB: https://github.com/advisories/GHSA-3hq4-5qpg-7776

NIST: https://nvd.nist.gov/vuln/detail/CVE-2023-20855

Hacker News: https://thehackernews.com/2023/02/vmware-patches-critical-vulnerability.html

Securoty Online: https://securityonline.info/vmware-patches-critical-cve-2023-20858-vulnerability-in-carbon-black-app-control/

Cloud Foundation (vRealize Automation) KB90926: https://kb.vmware.com/s/article/90926

Mitre CVE Dictionary Links:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-20855

FIRST CVSSv3 Calculator:
https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Change Log

2023-02-21 VMSA-2023-0005

Initial security advisory. 

Contact

E-mail: security@vmware.com

PGP key at:
https://kb.vmware.com/kb/1055 

VMware Security Advisories
https://www.vmware.com/security/advisories 

VMware Security Response Policy
https://www.vmware.com/support/policies/security_response.html 

VMware Lifecycle Support Phases
https://www.vmware.com/support/policies/lifecycle.html 

VMware Security & Compliance Blog  
https://blogs.vmware.com/security 

Twitter
https://twitter.com/VMwareSRC

How to convert any JavaScript library to work with vRO [CB10105]

vRO doesn’t use a regular JavaScript engine such as the ones that run in the browser or server side Node.js . It uses the Rhino engine, which is based on Java, and as such it has a lot of quirky differences with regular JavaScript.

There are quite a few differences in syntax and behavior compared to regular JS, so it can be expected that a lot of things that you think should work, will not work inside vRO.

#LIMITATIONS

Some of the limitations that vRO JavaScript has:

  • JS feature basically stop at ES5, but some features of ES5 aren’t even implemented.
  • Not all of the API is available inside vRO, and some objects, methods or functions have been replaced with an equivalent (Console.log is equivalent to System.log in vRO)
  • You can’t normally use external JS libraries such as axios, jQuery, lodash, etc.

If you want to use an external library inside VRO, there are a few things to consider, but these are the most important:

  • The JS version that the library is/depends on.
  • The APIs and JS features that the library depends on.

If your library is based on pre-ES5 JavaScript and does not use any special, browser-specific or node.js specific APIs, it should work out of the box inside vRO.

#OPTIONS

If not, then you can try a few things to try to get it to work inside vRO:

  • Use a transpiler (and bundler if you need) (such as Babel+Webpack, SWC, Esbuild, to name just a few) to downgrade the source code of the library you want to use into an older version of JS into a single JS file.
  • You might need to use polyfills if you use some browser or Node.js APIs because they will not work inside VRO even when transpiled and downgraded.
  • Put the resulting JS code into the same vRO workflow/action that you want to use it in and use it directly (I don’t recommend this, as it can become a mess quite fast and is unreadable)
  • Put the resulting JS code into a vRO resource element, then inside your vRO workflow/action , get the content of this resource element (it will be a string at this point) and use the eval() or the Function constructor to parse and evaluate the library code. It will then be available to use inside the rest of the workflow/action. (I recommend this method, since it is the least error prone, takes 1-3 lines of code only and is more readable)
  • You could do the same thing, but additionally split the library code into as many smaller working modules/objects/functions as you want to have better performance and potentially work around vRO’s limitations when working with huge files.

This is what worked for me in general, but I can’t guarantee that it will work in all cases. Because of the bizarre nature of the Rhino engine and limitations of vRO, you could run into other problems or limitations and won’t be able to use the JS library that you want to use. For example, if your library code is too big, vRO will not be able to use it as it will run out of memory, or the workflow/action will crash, or it will just stop evaluating the library code midway and be useless.

#ADVANCEDOPTIONS

There are 2 other ways to use external libraries inside vRO workflows/actions, but they don’t use the normal vRO engine. Just keep in mind that using this way, you cannot directly access all of the vRO APIs such as resource elements, plugins ,etc. So it has some limitations :

Credits to Olivier Fortier for this lucid explanation.

Inside vRO’s JavaScript Engine – Rhino 1.7R4 [CB10102]

  1. What is Rhino Engine?
  2. Released 10 years ago
  3. Compatibility with JavaScript features
  4. ECMAScript 5.1 Specifications
  5. Rhino on GitHub
  6. Rhino Engine Limitations in vRO
  7. Access to additional Java Classes
  8. Javadoc for Rhino 1.7R4
  9. Feature set in JavaScript 1.7
  10. Additional Links

vRealize Orchestrator a.k.a. vRO, which is a drag-and-drop automation tool, is quite an old tool developed and released as early as in 2007 by Dunes Technologies, Switzerland. After VMware acquired Dunes, there were 100’s of releases and updates came year after year. Lots and lots of improvements made over time in the UI, backend technologies, security, multi-language support, etc. However, one thing that remains the same is its JavaScript Engine. vRO uses Mozilla Rhino Engine 1.7R4 which was released in 2012.

In this post, My goal is to provide some insights on this Rhino Engine as it is almost extinct from the internet. However, I am still behind the JavaScript Engine which provides IntelliSense support to vRO 8.x. As you might have noticed and probably be wondering how CTRL+SPACE shows options only available to recent versions of JavaScript. I guess it’s for Node.js runtime.

What is Rhino Engine?

Rhino Engine converts JavaScript scripts into classes. It is intended to be used in desktop or server-side applications, hence there is no built-in support for the Web browser objects that are commonly associated with JavaScript which makes it very suitable for vRO. Rhino works in both compiled and interpreted mode. Rhino Engine got its name from the animal on the cover of the O’Reilly book about JavaScript published many years back.

The Rhino project was started at Netscape in the autumn of 1997. At the time, Netscape was planning to produce a version of Navigator written entirely in Java and so it needed an implementation of JavaScript written in Java. When Netscape stopped work on “Javagator,” as it was called, somehow Rhino escaped the axe (rumor had it that the executives “forgot” it existed). For a time, a couple of major companies (including Sun) licensed Rhino for use in their products and paid Netscape to do so, allowing work on Rhino to continue. Now Rhino is part of Mozilla’s open-source repository.

Released 10 years ago

Released in 2012-06-18, Rhino 1.7R4 is almost prehistoric for today’s standards and that’s been always a point of discussion in the vRO Community.

Release Notes of 1.7R4

Compatibility with JavaScript features

While trying to look deep into its compatibility matrix with ES, I found this Kangax’s Compat-table which gives an excellent and detailed view of all the possible features that Rhino 1.7R4 supports. Click the link to know more.

Rhino Compatibility Matrix with JavaScript

ECMAScript 5.1 Specifications

This document will give you a very in-depth knowledge of the ECMAScript 5.1 that vRO leverages to understand the language better. Learn more at https://262.ecma-international.org/5.1.

You can download this document and read about all the fine details by yourself.

Rhino on GitHub

Currently, on GitHub page of Mozilla, version 1.7R4 is not available. However, you may find some very old scripts that were written at the time of 1.7R4 as I can validate using web-achieve. You can explore their GitHub repo here.

Rhino Engine Limitations in vRO

When writing scripts for workflows, you must consider the following limitations of the Mozilla Rhino implementation in Orchestrator.

  • When a workflow runs, the objects that pass from one workflow element to another are not JavaScript objects. What is passed from one element to the next is the serialization of a Java object that has a JavaScript image. As a consequence, you cannot use the whole JavaScript language, but only the classes that are present in the API Explorer. You cannot pass function objects from one workflow element to another.
  • Orchestrator runs the code in scriptable task elements in a context that is not the Rhino root context. Orchestrator transparently wraps scriptable task elements and actions into JavaScript functions, which it then runs. A scriptable task element that contains System.log(this); does not display the global object this in the same way as a standard Rhino implementation does.
  • You can only call actions that return nonserializable objects from scripting, and not from workflows. To call an action that returns a nonserializable object, you must write a scriptable task element that calls the action by using the System.getModuleModuleName.action() method.
  • Workflow validation does not check whether a workflow attribute type is different from an input type of an action or subworkflow. If you change the type of a workflow input parameter, for example from VIM3:VirtualMachine to VC:VirtualMachine, but you do not update any scriptable tasks or actions that use the original input type, the workflow validates but does not run.

Access to additional Java Classes

By default, vRealize Orchestrator restricts JavaScript access to a limited set of Java classes. If you require JavaScript access to a wider range of Java classes, you must set an vRealize Orchestrator system property.

Allowing the JavaScript engine full access to the Java virtual machine (JVM) presents potential security issues. Malformed or malicious scripts might have access to all the system components to which the user who runs the vRealize Orchestrator server has access. Therefore, by default the vRealize Orchestrator JavaScript engine can access only the classes in the java.util.* package.

If you require JavaScript access to classes outside of the java.util.* package, you can list in a configuration file the Java packages to which to allow JavaScript access. You then set the com.vmware.scripting.rhino-class-shutter-file system property to point to this file.

Procedure

  1. Create a text configuration file to store the list of Java packages to which to allow JavaScript access.For example, to allow JavaScript access to all the classes in the java.net package and to the java.lang.Object class, you add the following content to the file.java.net.* java.lang.Object
  2. Enter a name for the configuration file.
  3. Save the configuration file in a subdirectory of /data/vco/usr/lib/vco. The configuration file cannot be saved under another directory.
  4. Log in to Control Center as root.
  5. Click System Properties.
  6. Click New.
  7. In the Key text box, enter com.vmware.scripting.rhino-class-shutter-file.
  8. In the Value text box, enter vco/usr/lib/vco/your_configuration_file_subdirectory.
  9. In the Description text box, enter a description for the system property.
  10. Click Add.
  11. Click Save changes from the pop-up menu.A message indicates that you have saved successfully.
  12. Wait for the vRealize Orchestrator server to restart.

See an implementation example of accessing external Java classes by BlueCat here. Here, the code implements new java.lang.Long(0)

.
.
.
var testConfig = BCNProteusAPI.createAPIEntity(new java.lang.Long(0),configName,"","Configuration" );
var args = new Array( new java.lang.Long(0), testConfig );
configId = new java.lang.Long( BCNProteusAPI.call( profileName,"addEntity",args ));
System.log( "New configuration was created, id=" + configId );
var addTFTPGroupArgs = new Array( configId, "tftpGroupName1", "" );
var tftpGroupId = new java.lang.Long( BCNProteusAPI.call(profileName,"addTFTPGroup", addTFTPGroupArgs ) );
System.log( "New TFTP Group was created, id=" + tftpGroupId );
.
.
.

Javadoc for Rhino 1.7R4

Feature set in JavaScript 1.7

https://contest-server.cs.uchicago.edu/ref/JavaScript/developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1-7.html#New_features_in_JavaScript_1.7

Differences between VMware Aria Automation Orchestrator Forms and VMware Aria Automation Service Broker Forms

Starting with vRealize Automation 8.2, Service Broker is capable of displaying input forms designed in vRealize Orchestrator with the custom forms display engine. However, there are some differences in the forms display engines.

Orchestrator and Service Broker forms

Amongst the differences, the following features supported in vRealize Orchestrator are not yet supported in Service Broker:

  • The inputs presentations developed with the vRealize Orchestrator Legacy Client used in vRealize Orchestrator 7.6 and earlier, are not compatible. vRealize Orchestrator uses a built-in legacy input presentation conversion that is not available from Service Broker yet.
  • The inputs presentation in vRealize Orchestrator has access to all the workflow elements in the workflow. The custom forms have access to the elements exposed to vRealize Automation Service Broker through the VRO-Gateway service, which is a subset of what is available on vRealize Orchestrator.
    • Custom forms can bind workflow inputs to action parameters used to set values in other inputs.
    • Custom forms cannot bind workflows variables to action parameters used to set values in other inputs.

Note You might have noticed VRO-Gateway service when you use WFs as a WBX (Workflow Based Extensibility) in Event Subscriptions where these WFs get triggered by this service.

Basically, It provides a gateway to VMware Realize Orchestrator (vRO) for services running on vRealize Automation. By using the gateway, consumers of the API can access a vRO instance, and initiate workflows or script actions without having to deal directly with the vRO APIs.


It is possible to work around vRealize Automation not having access to workflow variables by one of the following options :

  • Using a custom action returning the variable content.
  • Binding to an input parameter set to not visible instead of a variable.
  • Enabling custom forms and using constants.

The widgets available in vRealize Orchestrator and in vRealize Automation vary for certain types. The following table describes what is supported.

vRAvRO
Input Data TypePossible Form Display TypesAction return type for Default ValueAction return type for Value OptionsPossible Form Display TypesAction return type for Default ValueAction return type for Value Options
StringText, TextField, Text AreaDropdown, Radio GroupStringArray of StringPropertiesArray of Properties (value, label)Text, TextFIeld, Text AreaDropdown, Radio GroupStringArray of String
Array of StringArray Input (vRA 8.2), Dual List, Multi SelectArray of StringPropertiesArray of PropertiesArray of StringDatagrid, Multi Value PickerArray of StringPropertiesArray of PropertiesArray of String
IntegerIntegerNumberArray of NumberNot supportedNot supportedNot supported
Array of IntegerArray Input (vRA 8.2), Datagrid (vRA 8.1)Array of NumberArray of NumberNot supportedNot supportedNot supported
NumberDecimalNumberArray of NumberDecimalNumberArray of Number
Array/NumberArray Input (vRA 8.2), Datagrid (vRA 8.1)Array of NumberArray of NumberDatagridArray of NumberArray of Number
BooleanCheckboxBooleanNot supportedCheckboxBoolean
DateDate TimeDateArray of DateDate TimeDateArray of Date
Array of DateArray Input (vRA 8.2), Datagrid (vRA 8.1)Array of DateArray of DateDatagridArray of DateArray of Date
Composite/ComplexDatagrid, Object Field (vRA 8.3)Composite, Properties, Array/Composite, Array/PropertiesArray of CompositeDatagridComposite(columns…)Array/PropertiesArray of Composite
Array of CompositeDatagrid, Multi Value PickerComposite, Properties, Array/Composite, Array/PropertiesArray of CompositeDatagrid, Multi Value PickerArray/Composite(columns…)Array/PropertiesArray of Composite
Reference / vRO SDK Object typeValue PickerSDK ObjectArray of SDK Object (vRA 8.2)Value PickerSDK ObjectArray of SDK Object
Array of ReferenceMulti Value Picker (vRA 8.3)Array of SDK ObjectArray of SDK Object (vRA 8.3)DatagridArray of SDK ObjectArray of SDK Object
Secure StringPasswordStringNot supportedPasswordStringNot supported
FileNot supportedNot supportedNot supportedFile UploadNot supportedNot supported

For use cases where the widget specified in vRealize Orchestrator is not available from Service Broker, a compatible widget is used.

Because the data being passed to and from the widget might expect different types, formats, and values in the case they are unset, the best practice to develop workflows targeting Service Broker is to:

  1. Develop the vRealize Orchestrator workflow. This can include both the initial development of the workflow or changes of inputs.
  2. Version the workflow manually.
  3. In Cloud Assembly, navigate to Infrastructure > Connections > Integrations and select your vRealize Orchestrator integration.
  4. Start the data collection for the vRealize Orchestrator integration. This step, along with versioning up your workflow, ensure that the VRO-Gateway service used by vRealize Automation has the latest version of the workflow.
  5. Import content into Service Broker. This step generates a new default custom form.
  6. In addition to the input forms designed in vRealize Orchestrator, you can, if needed, develop workflow input forms with the custom forms editor.
  7. If these forms call actions, develop or run these from the vRealize Orchestrator workflow editor.
  8. Test the inputs presentation in Service Broker.
  9. Repeat from step 5 as many times as needed.
  10. Repeat from step 1, in case workflows inputs or forms need to be changed.

Either distribute and maintain the custom forms or alternatively, design vRealize Orchestrator inputs by using the same options or actions as in the custom forms (the above step 1), and then repeat the steps 2 to 8 to validate that the process works.

Using this last option means that:

  • Running the workflow from vRealize Orchestrator can lead to the input presentation not working as expected when started in vRealize Orchestrator.
  • For some cases, you must modify the return type of the actions used for default value or value options so these values can be set from the vRealize Orchestrator workflow editor and, when the workflow is saved, revert the action return types.

Designing the form in the workflow has the following advantages:

  • Form is packaged and delivered as part of the workflow included in a package.
  • Form can be tested in vRealize Orchestrator as long as the compatible widgets are applied.
  • The form can optionally be versioned and synchronized to a Git repository with the workflow.

Designing the custom forms separately has the following advantages:

  • Being able to customize the form without changing the workflow.
  • Being able to import and export the form as a file and reusing it for different workflows.

For example, a common use case is to have a string based drop-down menu.

Returning a Properties type can be used in both the vRealize Orchestrator input form presentation and vRealize Automation custom forms presentation. With the Property type you can display a list of values in the drop-down menu. After being select by the user, these values pass an ID to the parameter (to the workflow and the other input fields that would bind to this parameter). This is very practical to list objects when there is no dedicated plug-in for them as this avoids you having to select object names and having to find object IDs by name.

Returning an array of Properties types has the same goal as returning Properties but does give control on the ordering of the element. It is done by setting for each property in the array the label and value keys. For example, it is possible to sort ascending or descending properties by label or by keys within the action.

All the workflows included in the “drop down” folder of the sample package include drop down menus created with actions that have array of Properties set as the return type.

Find Object Types in vRealize Orchestrator

Find Object Types in vRealize Orchestrator [CB10100]

Last updated: 16-03-2023

Sometimes, we want to know exactly what type of vRO object we are working on. It could be something that is returning from an action of type Any or a method returning various types of objects or simply about switch cases. In this quick post, we will see what are the options that vRO provides and where to use them.

  1. typeof
    1. Code Examples
    2. Using new operator
    3. use of Parenthesis
  2. System.getObjectType()
    1. Code Examples
  3. System.getObjectClassName()
    1. Code Examples
  4. instanceof
    1. Syntax
    2. Code Examples

typeof

The typeof operator returns a string indicating the type of the operand’s value where the operand is an object or of primitive type.

TypeResult
Undefined"undefined"
Null"object" (reason)
Boolean"boolean"
Number"number"
String"string"
Function"function"
Array"object"
Date"object"
vRO Object types"object"
Composite Types"object"
vRO Object types with new operator"function"

Code Examples

var var1 = new VcCustomizationSpec(); 
System.debug(typeof var1); //function
var var2 = new Object();
System.debug(typeof var2); //object
var var3 = "a";
System.debug(typeof var3); //string
var var4 = 2;
System.debug(typeof var4); //number
var var4 = new Array(1, 2, 3);
System.debug(typeof var4); //object
System.debug(typeof []); //object
System.debug(typeof function () {}); //function
System.debug(typeof /regex/); //object
System.debug(typeof new Date()); //object
System.debug(typeof null); //object
System.debug(typeof undefinedVarible); //undefined

Using new operator

In this example, typeof operator is showing different results when used with new operator for class VC:CustomizationSpecManager. That’s because the new operator is used for creating a user-defined object type instance of one of the built-in object types that has a constructor function. So basically it calls the constructor function of that object type, hence typeof prints function. However, something to note here is that when new operator is used with primitive object type Number, typeof recognizes that as an object.

var num1 = 2;
System.debug(typeof num1); //number

var num2 = Number("123");;
System.debug(typeof (1 + num2)); //number

var num3 = new Number("123");;
System.debug(typeof (num3)); //object

var num4 = new Number("123");;
System.debug(typeof (1 + num4)); //number

use of Parenthesis

// Parentheses can be used for determining the data type of expressions.
const someData = 99;
typeof someData + "cloudblogger"; // "number cloudblogger"
typeof (someData + " cloudblogger"); // "string"

System.getObjectType()

The System.getObjectType() method returns the VS-O ‘type’ for the given operand. This method is more advanced than typeof and is able to detect more complex yet intrinsic object types like Date, Array etc. But, it still cannot figure out the plugin object types like VC:SDKConnection, etc.

TypeResult
Array"Array"
Number"number"
String"string"
vRO Plugin Object Types (with or without new)"null"
Date"Date"
Composite Types"Properties"
SecureString"string"
undefined VariableReference Error

Code Examples


var var1 = new VcCustomizationSpec(); 
System.debug(System.getObjectType(var1)); //null

var var2 = new Object();
System.debug(System.getObjectType(var2)); //Properties

var var3 = "a";
System.debug(System.getObjectType(var3)); //string

var var4 = 2;
System.debug(System.getObjectType(var4)); //number

var var4 = new Array(1, 2, 3);
System.debug(System.getObjectType(var4)); //Array

System.debug(System.getObjectType([])); //Array

System.debug(System.getObjectType(function () {})); //null

System.debug(System.getObjectType(new Date())); //Date

System.debug(System.getObjectType(undefinedVarible)); //FAIL ReferenceError: "undefinedVarible" is not defined.

System.getObjectClassName()

The System.getObjectClassName() method returns the class name of any vRO scripting object that typeof(obj) returns “object”. This works the best with complex vRO object types and surpasses System.getObjectType() in terms of its capability to identify object types.

TypeResult
Array"Array"
Number"Number"
String"String"
vRO Plugin Object Types (eg: VC:SdkConnection)Class Name (eg: VcSdkConnection)
Date"Date"
Composite Types"Properties"
SecureString"String"
undefined VariableReference Error
null objectsError: Cannot get class name from null object

Code Examples

System.debug(System.getObjectClassName(input));  //String

var var1 = new VcCustomizationSpec(); 
System.debug(System.getObjectClassName(var1)); //VcCustomizationSpec

var var2 = new Object();
System.debug(System.getObjectClassName(var2)); //Object

var var3 = "a";
System.debug(System.getObjectClassName(var3)); //String

var var4 = 2;
System.debug(System.getObjectClassName(var4)); //Double

var var4 = new Array(1, 2, 3);
System.debug(System.getObjectClassName(var4)); //Array

System.debug(System.getObjectClassName([])); //Array

System.debug(System.getObjectClassName(function () {})); //Function

System.debug(System.getObjectClassName(new Date())); //Date

instanceof

The instanceof operator tests to see if the prototype property of a constructor appears anywhere in the prototype chain of an object. The return value is a boolean value. This means that instanceof checks if RHS matches the constructor of a class. That’s why it doesn’t work with primitive types like number, string, etc. However, works with variety of complex types available in vRO.

Syntax

object instanceof constructor

Code Examples

var var1 = new VcCustomizationSpec(); 
System.debug(var1 instanceof VcCustomizationSpec); //true

var var1 = new VcCustomizationSpec(); 
System.debug(var1 instanceof Object); //true

var var2 = new Object();
System.debug(var2 instanceof Object); //true

var var3 = "a";
System.debug(var3 instanceof String); //false

var var3 = new String("a");
System.debug(var3 instanceof String); //true

var var3 = "a";
System.debug(var3 instanceof String); //false

var var4 = 2;
System.debug(var4 instanceof Number); //false

var var4 = new Array(1, 2, 3);
System.debug(var4 instanceof Array); //true

System.debug([] instanceof Array); //true

System.debug(function () {} instanceof Function); //true

System.debug(new Date() instanceof Date); //true

System.debug({} instanceof Object); //true

That’s all in this port. I hope you will have a better understanding on how to check vRO Object types. Let me know in the comment if you have any doubt or question. Feel free to share this article. Thank you.

Advanced JavaScript Snippets in vRO [CB10099]

  1. Introduction
  2. Snippets
    1. External Modules
    2. First-class Functions
    3. Ways to add properties to Objects
    4. Custom Class
    5. Private variable
    6. Label
    7. with keyword
    8. Function binding
    9. Prototype Chaining
  3. Recommended Reading

Introduction

vRO JS code is generally plain and basic just enough to get the job done. But I was wondering, how to fancy it? So, I picked some slightly modern JS code (ES5.1+) and tried running it on my vRO 8.3. I found some interesting things which I would like to share in this article.

Snippets

Here are some JS concepts that you can use writing vRO JavaScript code to make it more compelling and beautiful.

External Modules

To utilize modern features, you can use modules like lodash.js for features such as map or filter etc. Other popular module is moment.js for complex Date and Time handling in vRO.

var _ = System.getModule("fr.numaneo.library").lodashLibrary();
var myarr = [1,2,3];
var myarr2 = [4,5,6];
var concatarr = _.concat(myarr, myarr2);
System.log(concatarr); // [1,2,3,4,5,6];

Find more information on how to leverage Lodash.js in vRO here.

First-class Functions

First-class functions are functions that are treated like any other variable. For example, a function can be passed as an argument to other functions, can be returned by another function and can be assigned as a value to a variable.

// we send in the function as an argument to be
// executed from inside the calling function
function performOperation(a, b, cb) {
    var c = a + b;
    cb(c);
}

performOperation(2, 3, function(result) {
    // prints out 5
    System.log("The result of the operation is " + result);
})

Ways to add properties to Objects

There are 4 ways to add a property to an object in vRO.

// supported since ES3
// the dot notation
instance.key = "A key's value";

// the square brackets notation
instance["key"] = "A key's value";

// supported since ES5
// setting a single property using Object.defineProperty
Object.defineProperty(instance, "key", {
    value: "A key's value",
    writable: true,
    enumerable: true,
    configurable: true
});

// setting multiple properties using Object.defineProperties
Object.defineProperties(instance, {
    "firstKey": {
        value: "First key's value",
        writable: true
    },
    "secondKey": {
        value: "Second key's value",
        writable: false
    }
});

Custom Class

You can create your own custom classes in vRO using the function keyword and extend that function’s prototype.

// we define a constructor for Person objects
function Person(name, age, isDeveloper) {
    this.name = name;
    this.age = age;
    this.isDeveloper = isDeveloper || false;
}

// we extend the function's prototype
Person.prototype.writesCode = function() {
    System.log(this.isDeveloper? "This person does write code" : "This person does not write code");
}

// creates a Person instance with properties name: Bob, age: 38, isDeveloper: true and a method writesCode
var person1 = new Person("Bob", 38, true);
// creates a Person instance with properties name: Alice, age: 32, isDeveloper: false and a method writesCode
var person2 = new Person("Alice", 32);

// prints out: This person does write code
person1.writesCode();
// prints out: this person does not write code
person2.writesCode();

Both instances of the Person constructor can access a shared instance of the writesCode() method.

Private variable

A private variable is only visible to the current class. It is not accessible in the global scope or to any of its subclasses. For example, we can do this in Java (and most other programming languages) by using the private keyword when we declare a variable

// we  used an immediately invoked function expression
// to create a private variable, counter
var counterIncrementer = (function() {
    var counter = 0;

    return function() {
        return ++counter;
    };
})();

// prints out 1
System.log(counterIncrementer());
// prints out 2
System.log(counterIncrementer());
// prints out 3
System.log(counterIncrementer());

Label

Labels can be used with break or continue statements. It is prefixing a statement with an identifier which you can refer to.

var str = '';

loop1:
for (var i = 0; i < 5; i++) {
  if (i === 1) {
    continue loop1;
  }
  str = str + i;
}

System.log(str);
// expected output: "0234"

with keyword

The with statement extends the scope chain for a statement. Check the example for better understanding.

var box = {"dimensions": {"width": 2, "height": 3, "length": 4}};
with(box.dimensions){
  var volume = width * height * length;
}
System.log(volume); //24

// vs

var box = {"dimensions": {"width": 2, "height": 3, "length": 4}};
var boxDimensions = box.dimensions;
var volume2 = boxDimensions.width * boxDimensions.height * boxDimensions.length;
System.log(volume2); //24

Function binding

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

const module = {
  x: 42,
  getX: function() {
    return this.x;
  }
};

const unboundGetX = module.getX;
System.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined

const boundGetX = unboundGetX.bind(module);
System.log(boundGetX());
// expected output: 42

Prototype Chaining

const o = {
  a: 1,
  b: 2,
  // __proto__ sets the [[Prototype]]. It's specified here
  // as another object literal.
  __proto__: {
    b: 3,
    c: 4,
  },
};

// o.[[Prototype]] has properties b and c.
// o.[[Prototype]].[[Prototype]] is Object.prototype (we will explain
// what that means later).
// Finally, o.[[Prototype]].[[Prototype]].[[Prototype]] is null.
// This is the end of the prototype chain, as null,
// by definition, has no [[Prototype]].
// Thus, the full prototype chain looks like:
// { a: 1, b: 2 } ---> { b: 3, c: 4 } ---> Object.prototype ---> null

System.log(o.a); // 1
// Is there an 'a' own property on o? Yes, and its value is 1.

System.log(o.b); // 2
// Is there a 'b' own property on o? Yes, and its value is 2.
// The prototype also has a 'b' property, but it's not visited.
// This is called Property Shadowing

System.log(o.c); // 4
// Is there a 'c' own property on o? No, check its prototype.
// Is there a 'c' own property on o.[[Prototype]]? Yes, its value is 4.

System.log(o.d); // undefined
// Is there a 'd' own property on o? No, check its prototype.
// Is there a 'd' own property on o.[[Prototype]]? No, check its prototype.
// o.[[Prototype]].[[Prototype]] is Object.prototype and
// there is no 'd' property by default, check its prototype.
// o.[[Prototype]].[[Prototype]].[[Prototype]] is null, stop searching,
// no property found, return undefined.

official-vmware-guides-for-vro-and-vra-8.x

Official VMware Guides for vRO and vRA 8.x

  1. Introduction
  2. Guides for vRA
    1. Architecture
    2. Cloud Assembly
    3. Code Stream
    4. Service Broker
    5. Transition Guide
    6. Migration
    7. Cloud Transition (SaaS only)
    8. Integration with ServiceNow
    9. Load Balancing
    10. NSX-T Migration
    11. SaltStack Config
  3. Guides for vRO
    1. Installation
    2. User Interface
    3. Developer’s Guide
    4. Migration
    5. Plug-in Development
    6. Plug-in Guide

Introduction

This blogpost is simply about giving a consolidated view on all the official guides that VMware provides for vRealize Automation and vRealize Orchestrator. These guides can help Automation Engineers & Developers, Solution Architects, vRealize Admins, etc and can be used as a reference for developing vRO Code, vRA Templates and various other tasks. You can download them from the provided links for offline access.

Guides for vRA

Architecture

Cloud Assembly

Code Stream

Service Broker

Transition Guide

Migration

Cloud Transition (SaaS only)

Download: https://docs.vmware.com/en/vRealize-Automation/services/vrealize-automation-cloud-transition-guide.pdf

Integration with ServiceNow

Load Balancing

NSX-T Migration

SaltStack Config

Guides for vRO

Installation

User Interface

Download: https://docs.vmware.com/en/vRealize-Orchestrator/8.8/vrealize-orchestrator-88-using-client-guide.pdf

Developer’s Guide

Migration

Plug-in Development

Plug-in Guide

I will try to update this list over time. Hope this list of guides will help you in understanding things a little better. Feel free to share.

Advertisements

Free vRealize Automation 8.3 Enterprise Course by VMware

Disclaimer Turned out that this course is not freely available for everyone. I would suggest you give it a try and see if you’re lucky enough.

If you are looking for a course on vRealize Automation (vRA) and vRealize Orchestrator (vRO) which is officially developed by VMware, is enterprise-level, not just the basic one and most importantly FREE, then you should go for this course. It has 41 lessons, more than 70,000 views and is a ELS (Enterprise) course and talks on vRA architecture, installation, Cloud templates, integration with NSX-T, Kubernetes, Public Clouds, SaltStack, vRO Workflows and extensibility and a lot more. I personally went through this course after I completed the Udemy’s Getting started with VMware vRealize Automation 8.1 and while Udemy’s push start your journey in vRA 8.x, this VMware course will take it to another level. Recommended for someone who is in VMware Automation, coming from vRA 7.x, Looking for migrating from 7.x to 8.x, deployment of vRA etc. In this post, I have shared some basic steps on how to get to that course and get yourself started.

Bonus Tip

VMware will accept this course as prerequisite for Cloud Management and Automation 2022 (VCP-CMA 2022) certification.

How to enroll?

  • Scroll down and search for vrealize automation.
  • Open the course, enroll yourself and get started.
  • Once you start the course, Bharath N will take over as your course instructor.

Course Content

Let’s see what you will find in the course content.

Feel free to share this article to your team members and connections.

vRO JavaScript Style Guide [CB10096]

  1. Introduction
  2. JavaScript Language Rules
    1. var
    2. Constants
    3. Semicolons
    4. Nested functions
    5. Function Declarations Within Blocks
    6. Exceptions
    7. Custom exceptions
    8. Standards features
    9. Wrapper objects for primitive types
    10. delete
    11. JSON.parse()
    12. with() {}
    13. this
    14. for-in loop
    15. Multiline string literals
    16. Array and Object literals
    17. Modifying prototypes of built-in objects
  3. JavaScript Style Rules
    1. Naming
    2. Deferred initialization
    3. Code formatting
    4. Parentheses
    5. Strings
    6. Comments
    7. Tips and Tricks
  4. vRO Element Naming Rules
    1. Actions
    2. Workflows
    3. Action Modules
    4. Resource Elements and Configuration Elements
    5. Attributes inside Configuration Elements

Introduction

If you are new to vRealize Orchestrator and want to look for some code style references, this post can help you with some basic guidelines to write the perfect JavaScript code in your vRO Workflows and Actions. These are industry standards are preferred by almost every industry. Keep in mind that this guide won’t help you with writing your first vRO code, instead can be used as style reference while writing your vRO JavaScript code. In short, helps you to achieve 7 things:

  1. Code that’s easier to read
  2. Provide clear guidelines when writing code
  3. Predictable variable and function names
  4. Improve team’s efficiency to collaborate
  5. Saves time and makes communication between teams more efficient
  6. Reduces redundant work
  7. Enables each team member to share the same clear messaging with potential customers

vRealize Orchestrator uses JavaScript 1.7 as its classic language of choice for all the automation tasks that gets executed inside Mozilla Rhino 1.7R4 Engine along with some limitations listed here. This style guide is a list of dos and don’ts for JavaScript programs that you write inside your vRO. Let’s have a look.

JavaScript Language Rules

var

Always declare variables with var, unless it’s a const.

Constants

  • Use NAMES_LIKE_THIS for constant values, that start with const keyword.

Semicolons

Always use semicolons.

Why?

JavaScript requires statements to end with a semicolon, except when it thinks it can safely infer their existence. In each of these examples, a function declaration or object or array literal is used inside a statement. The closing brackets are not enough to signal the end of the statement. JavaScript never ends a statement if the next token is an infix or bracket operator.

This has really surprised people, so make sure your assignments end with semicolons.

Clarification: Semicolons and functions

Semicolons should be included at the end of function expressions, but not at the end of function declarations. The distinction is best illustrated with an example:

var foo = function() {
  return true;
};  // semicolon here.

function foo() {
  return true;
}  // no semicolon here.

Nested functions

Yes

Nested functions can be very useful, for example in the creation of continuations and for the task of hiding helper functions. Feel free to use them.

Function Declarations Within Blocks

No

Do not do this:

if (x) {
  function foo() {}
}

ECMAScript only allows for Function Declarations in the root statement list of a script or function. Instead use a variable initialized with a Function Expression to define a function within a block:

if (x) {
  var foo = function() {};
}

Exceptions

Yes

You basically can’t avoid exceptions. Go for it.

Custom exceptions

Yes

Sometimes, It becomes really hard to troubleshoot inside vRealize Orchestrator. But, custom exceptions can certainly help you there. Feel free to use custom exceptions when appropriate and throw them using System.error() for soft errors or throw "" for hard errors.

Standards features

Always preferred over non-standards features

For maximum portability and compatibility, always prefer standards features over non-standards features (e.g., string.charAt(3) over string[3].

Wrapper objects for primitive types

No

There’s no reason to use wrapper objects for primitive types, plus they’re dangerous:

var x = new Boolean(false);
if (x) {
  alert('hi');  // Shows 'hi'.
}

Don’t do it!

However type casting is fine.

var x = Boolean(0);
if (x) {
  alert('hi');  // This will never be alerted.
}
typeof Boolean(0) == 'boolean';
typeof new Boolean(0) == 'object';

This is very useful for casting things to numberstring and boolean.

delete

Prefer this.foo = null.

var dispose = function() {
  this.property_ = null;
};

Instead of:

var dispose = function() {
  delete this.property_;
};

Changing the number of properties on an object is much slower than reassigning the values. The delete keyword should be avoided except when it is necessary to remove a property from an object’s iterated list of keys, or to change the result of if (key in obj).

JSON.parse()

You can always use JSON and read the result using JSON.parse().

var userInfo = JSON.parse(feed);
var email = userInfo['email'];

With JSON.parse, invalid JSON will cause an exception to be thrown.

with() {}

No

Using with clouds the semantics of your program. Because the object of the with can have properties that collide with local variables, it can drastically change the meaning of your program. For example, what does this do?

with (foo) {
  var x = 3;
  return x;
}

Answer: anything. The local variable x could be clobbered by a property of foo and perhaps it even has a setter, in which case assigning 3 could cause lots of other code to execute. Don’t use with.

this

Only in object constructors, methods, and in setting up closures

The semantics of this can be tricky. At times it refers to the global object (in most places), the scope of the caller (in eval), a newly created object (in a constructor), or some other object (if function was call()ed or apply()ed).

Because this is so easy to get wrong, limit its use to those places where it is required:

  • in constructors
  • in methods of objects (including in the creation of closures)

for-in loop

Only for iterating over keys in an object/map/hash

for-in loops are often incorrectly used to loop over the elements in an Array. This is however very error prone because it does not loop from 0 to length - 1 but over all the present keys in the object and its prototype chain. Here are a few cases where it fails:

function printArray(arr) {
  for (var key in arr) {
    print(arr[key]);
  }
}

printArray([0,1,2,3]);  // This works.

var a = new Array(10);
printArray(a);  // This is wrong.

a = [0,1,2,3];
a.buhu = 'wine';
printArray(a);  // This is wrong again.

a = new Array;
a[3] = 3;
printArray(a);  // This is wrong again.

Always use normal for loops when using arrays.

function printArray(arr) {
  var l = arr.length;
  for (var i = 0; i < l; i++) {
    print(arr[i]);
  }
}

Multiline string literals

No

Do not do this:

var myString = 'A rather long string of English text, an error message \
                actually that just keeps going and going -- an error \
                message to make the Energizer bunny blush (right through \
                those Schwarzenegger shades)! Where was I? Oh yes, \
                you\'ve got an error and all the extraneous whitespace is \
                just gravy.  Have a nice day.';

The whitespace at the beginning of each line can’t be safely stripped at compile time; whitespace after the slash will result in tricky errors.

Use string concatenation instead:

var myString = 'A rather long string of English text, an error message ' +
    'actually that just keeps going and going -- an error ' +
    'message to make the Energizer bunny blush (right through ' +
    'those Schwarzenegger shades)! Where was I? Oh yes, ' +
    'you\'ve got an error and all the extraneous whitespace is ' +
    'just gravy.  Have a nice day.';

Array and Object literals

Yes

Use Array and Object literals instead of Array and Object constructors.

Array constructors are error-prone due to their arguments.

// Length is 3.
var a1 = new Array(x1, x2, x3);

// Length is 2.
var a2 = new Array(x1, x2);

// If x1 is a number and it is a natural number the length will be x1.
// If x1 is a number but not a natural number this will throw an exception.
// Otherwise the array will have one element with x1 as its value.
var a3 = new Array(x1);

// Length is 0.
var a4 = new Array();

Because of this, if someone changes the code to pass 1 argument instead of 2 arguments, the array might not have the expected length.

To avoid these kinds of weird cases, always use the more readable array literal.

var a = [x1, x2, x3];
var a2 = [x1, x2];
var a3 = [x1];
var a4 = [];

Object constructors don’t have the same problems, but for readability and consistency object literals should be used.

var o = new Object();

var o2 = new Object();
o2.a = 0;
o2.b = 1;
o2.c = 2;
o2['strange key'] = 3;

Should be written as:

var o = {};

var o2 = {
  a: 0,
  b: 1,
  c: 2,
  'strange key': 3
};

Modifying prototypes of built-in objects

Modifying builtins like Object.prototype and Array.prototype are strictly forbidden in vRO. Doing so will result in an error.

JavaScript Style Rules

Naming

In general, use functionNamesLikeThisvariableNamesLikeThisEnumNamesLikeThisCONSTANT_VALUES_LIKE_THIS.

Method and function parameter

Optional function arguments start with opt_.

Getters and Setters

EcmaScript 5 getters and setters for properties are discouraged. However, if they are used, then getters must not change observable state.

/**
 * WRONG -- Do NOT do this.
 */
var foo = { get next() { return this.nextId++; } };

Accessor functions

Getters and setters methods for properties are not required. However, if they are used, then getters must be named getFoo() and setters must be named setFoo(value). (For boolean getters, isFoo() is also acceptable, and often sounds more natural.)

Deferred initialization

OK

It isn’t always possible to initialize variables at the point of declaration, so deferred initialization is fine.

Code formatting

Curly Braces

Because of implicit semicolon insertion, always start your curly braces on the same line as whatever they’re opening. For example:

if (something) {
  // ...
} else {
  // ...
}

Array and Object Initializers

Single-line array and object initializers are allowed when they fit on a line:

var arr = [1, 2, 3];  // No space after [ or before ].
var obj = {a: 1, b: 2, c: 3};  // No space after { or before }.

Multiline array initializers and object initializers are indented 2 spaces, with the braces on their own line, just like blocks.

Indenting wrapped lines

Except for array literals, object literals, and anonymous functions, all wrapped lines should be indented either left-aligned to a sibling expression above, or four spaces (not two spaces) deeper than a parent expression (where “sibling” and “parent” refer to parenthesis nesting level).

someWonderfulHtml = '' +
                    getEvenMoreHtml(someReallyInterestingValues, moreValues,
                                    evenMoreParams, 'a duck', true, 72,
                                    slightlyMoreMonkeys(0xfff)) +
                    '';

thisIsAVeryLongVariableName =
    hereIsAnEvenLongerOtherFunctionNameThatWillNotFitOnPrevLine();

thisIsAVeryLongVariableName = siblingOne + siblingTwo + siblingThree +
    siblingFour + siblingFive + siblingSix + siblingSeven +
    moreSiblingExpressions + allAtTheSameIndentationLevel;

thisIsAVeryLongVariableName = operandOne + operandTwo + operandThree +
    operandFour + operandFive * (
        aNestedChildExpression + shouldBeIndentedMore);

someValue = this.foo(
    shortArg,
    'Some really long string arg - this is a pretty common case, actually.',
    shorty2,
    this.bar());

if (searchableCollection(allYourStuff).contains(theStuffYouWant) &&
    !ambientNotification.isActive() && (client.isAmbientSupported() ||
                                        client.alwaysTryAmbientAnyways())) {
  ambientNotification.activate();
}

Blank lines

Use newlines to group logically related pieces of code. For example:

doSomethingTo(x);
doSomethingElseTo(x);
andThen(x);

nowDoSomethingWith(y);

andNowWith(z);

Binary and Ternary Operators

Always put the operator on the preceding line. Otherwise, line breaks and indentation follow the same rules as in other Google style guides. This operator placement was initially agreed upon out of concerns about automatic semicolon insertion. In fact, semicolon insertion cannot happen before a binary operator, but new code should stick to this style for consistency.

var x = a ? b : c;  // All on one line if it will fit.

// Indentation +4 is OK.
var y = a ?
    longButSimpleOperandB : longButSimpleOperandC;

// Indenting to the line position of the first operand is also OK.
var z = a ?
        moreComplicatedB :
        moreComplicatedC;

This includes the dot operator.

var x = foo.bar().
    doSomething().
    doSomethingElse();

Parentheses

Only where required

Use sparingly and in general only where required by the syntax and semantics.

Never use parentheses for unary operators such as deletetypeof and void or after keywords such as returnthrow as well as others (casein or new).

Strings

For consistency single-quotes (‘) are preferred to double-quotes (“). This is helpful when creating strings that include HTML:

var msg = 'This is some message';

Comments

Use JSDoc if you want.

Tips and Tricks

JavaScript tidbits

True and False Boolean Expressions

The following are all false in boolean expressions:

  • null
  • undefined
  • '' the empty string
  • 0 the number

But be careful, because these are all true:

  • '0' the string
  • [] the empty array
  • {} the empty object

This means that instead of this:

while (x != null) {

you can write this shorter code (as long as you don’t expect x to be 0, or the empty string, or false):

while (x) {

And if you want to check a string to see if it is null or empty, you could do this:

if (y != null && y != '') {

But this is shorter and nicer:

if (y) {

Caution: There are many unintuitive things about boolean expressions. Here are some of them:

  • Boolean('0') == true
    '0' != true
  • 0 != null
    0 == []
    0 == false
  • Boolean(null) == false
    null != true
    null != false
  • Boolean(undefined) == false
    undefined != true
    undefined != false
  • Boolean([]) == true
    [] != true
    [] == false
  • Boolean({}) == true
    {} != true
    {} != false

Conditional (Ternary) Operator (?:)

Instead of this:

if (val) {
  return foo();
} else {
  return bar();
}

you can write this:

return val ? foo() : bar();

&& and ||

These binary boolean operators are short-circuited, and evaluate to the last evaluated term.

“||” has been called the ‘default’ operator, because instead of writing this:

function foo(opt_win) {
  var win;
  if (opt_win) {
    win = opt_win;
  } else {
    win = window;
  }
  // ...
}

you can write this:

function foo(opt_win) {
  var win = opt_win || window;
  // ...
}

“&&” is also useful for shortening code. For instance, instead of this:

if (node) {
  if (node.kids) {
    if (node.kids[index]) {
      foo(node.kids[index]);
    }
  }
}

you could do this:

if (node && node.kids && node.kids[index]) {
  foo(node.kids[index]);
}

or this:

var kid = node && node.kids && node.kids[index];
if (kid) {
  foo(kid);
}

vRO Element Naming Rules

Actions

should be named like actionNameLikeThis and must start with a verb like get, create, set, delete, fetch, put, call, and so forth. Then, describe what the action is doing.

Workflows

should be a short statement which briefly tells what the Workflow is doing.

Action Modules

naming should be similar to com.[company].library.[component].[interface].[parent group].[child group]

Where

[company] = company name as a single word

library – Optional

[component] = Examples are: NSX, vCAC, Infoblox, Activedirectory, Zerto.

[interface] – Optional – Examples are: REST, SOAP, PS. Omit this if you are using the vcenter or vcac plugins.

[parent group] – Optional – Parent group i.e. Edges, Entities, Networks, vm.

[child group] – Optional – A group containing collections of child actions that relate to the parent group.

Resource Elements and Configuration Elements

Resource element’s name is actually the filename at time of uploading. It should be clear enough.

Configuration Elements are used for various purposes like Password Containers (Credential store), Environment specific variables, location information, or can be a used as global variables get\set by various workflows. Hence, the name should define its purpose.

Attributes inside Configuration Elements

attribute’s name should have some suffix like DC_ or CONF_. when mapped with variable inside workflow, we should keep that variable’s name same as well. While using it in scripts, pass its value to another variable.

In this example, a attribute DC_EAST_LOCATION inside a Configuration element (named Location Variables) is mapped to a variable DC_EAST_LOCATION in a workflow and this variable is being used in a scriptable task.

//CORRECT WAY
var location = DC_EAST_LOCATION; //pass value to a local variable
System.log("Current location: " + location);

//WRONG WAY
System.log("Current location: " + DC_EAST_LOCATION);