Getting Started: vRealize Orchestrator Script Environments [CB10098]

  1. Introduction
  2. Prerequisite
  3. Procedure
  4. Calling modules & variables
    1. For Node.js
    2. For Python
    3. For PowerShell
  5. Sample Node.js Script

Introduction

Do you use a lot of Polyglot scripts in vRO? Are you tired of creating bundles every time you work on a Python, Node.js or PowerShell script which uses modules and libraries which are not provided out-of-the-box by vRealize Orchestrator? Probably vRO guys at VMware heard your prayers this time.

vRO 8.8 onwards, you can now add modules and libraries directly as a dependency in your vRO actions and scriptable tasks. How cool is that!

As we know, in earlier versions, you could only add dependencies by adding them as a ZIP package which is not only a tiring additional steps, but also, editing and understanding those scripts becomes a real nightmare. But not any more.

In this post, we will see a detailed procedure on how to setup an script environment in your vRO (>8.8). I am going with Node.js but almost similar process can be followed for other languages as well. We will use an advanced date & time library called MomentJS available at https://momentjs.com/ but you can use any other module or library of your choice for that matter.


Note Similarly to other vRealize Orchestrator objects such as workflows and actions, environments can be exported to other vRealize Orchestrator deployments as part of a package, which means they are also a part of version control.


Prerequisite

  • vRealize Orchestrator 8.8 or greater

Procedure

  • Log in to the vRealize Orchestrator Client.
  • Navigate to Assets > Environments, and click New Environment.
  • Under the General tab, enter a name for your environment.
  • (Optional) Enter a description, version number, tags, and group permissions for the action.
  • Under the Definition tab, Click on Add button under Dependencies.

You can also change the Memory Limit to 128, 512, 1024 etc. depending on the number and size of packages that you will be using. In my personal experience, using PowerShell modules will require more than default.

  • Provide the package name and version that you want to install. For Node.js, passing latest will get you the most recent package.

Tip The package name is same as what you would use with package managers like npm while installing that package.


  • Once you click Create button, you should see Environment successfully created.
  • Under the Download Logs tab, check if the libraries are already installed.

Here, I have installed two modules, moment and moment-timezone as you can see from the logs.

  • In the Environment variables, you can provide a variable that you want to use as a part of this environment.
  • Create an action or a workflow with scriptable item, Select Runtime Environment as the one that you have created. I have selected moment.
  • Play with your script. Don’t forget to call the modules and environment variables.

Calling modules & variables

For Node.js

const myModule = require('moment');
const envVar = process.env.VAR_NAME;

For Python

import myModule
os.environ.get('VAR_NAME')

For PowerShell

Import-Module myModule
$env:VAR_NAME

Sample Node.js Script

exports.handler = (context, inputs, callback) => {
//——————-Don't edit above it————————//
const moment = require('moment'); // **IMPORTANT**
const tz = require('moment-timezone'); // **IMPORTANT**
const indianTimeZone = process.env.TIMEZONE_IN; // import Env variable in Node.js
console.log(moment().format('MMMM Do YYYY, h:mm:ss a'));
console.log(moment().format('dddd'));
console.log(moment().format("MMM Do YY"));
console.log(moment().format('YYYY [escaped] YYYY'));
console.log(moment().format());
var jul = moment("2022-07-20T12:00:00Z");
var dec = moment("2022-12-20T12:00:00Z");
console.log(jul.tz('America/Los_Angeles').format('ha z')); // 5am PDT
console.log(dec.tz(indianTimeZone).format('ha z')); // 4am PST
//——————-Don't edit below it————————//
callback(undefined, {
status: "done"
});
}

That’s it on this post.

Automated Installation of vRO Plugin using Python

If you are looking for a way to quickly install plugins in your vRealize Orchestrator (.dar or .vmoapp files), you can try this python script which uses vRO ControlCenter API at its core.

Prerequisites

{The Script}

# -*- coding: utf-8 -*-
"""
Automated Installation of vRO Plugin 1.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is a python script to allow quick installation of plugins inside vRealize Orchestrator.
"""
__author__ = "Mayank Goyal, Harshit Kesharwani"
import base64
import csv
import email
import json
import os
import re
import smtplib
import time
import requests
import urllib3
from pathlib import Path
from string import Template
urllib3.disable_warnings()
def deployPlugin(vroUrl, username, password, filename):
"""Function to deploy plugin. Calls sub-functions like updateInstallPlugin() & finishInstallPlugin()."""
url = (f"https://{vroUrl}/vco-controlcenter/api/plugins/installation")
print(url)
files = {'file': open(filename, 'rb')}
headers = {'Accept': 'application/json'}
response = requests.post(url, auth=(username, password), headers=headers, files=files, verify=False)
statusCode = response.status_code
if (statusCode == 201):
responseData = response.json()
payloadToUpdate = (responseData)
pluginInstallationID = responseData['id']
pluginName = payloadToUpdate.get("plugins")[0].get("name")
print(f"pluginInstallationID : {pluginInstallationID}")
time.sleep(2)
updateStatus = updateInstallPlugin(vroUrl, username, password, pluginInstallationID, payloadToUpdate)
if updateStatus:
time.sleep(2)
finishStatus = finishInstallPlugin(vroUrl, username, password, pluginInstallationID,pluginName)
return finishStatus
else:
return False
else:
print(f"[ERROR]: Failed to execute Deploy request. Error code : {statusCode}")
return False
def updateInstallPlugin(vroUrl, username, password, pluginInstallationID, payloadToUpdate):
"""Function to update plugin state."""
url = (f"https://{vroUrl}/vco-controlcenter/api/plugins/installation/{pluginInstallationID}")
#payload = "{\"eulaAccepted\":true,\"forceInstall\":true,\"installPluginStates\":[{\"state\":\"NEW_INSTALLED\"}],\"plugins\":[{\"enabled\":true,\"logLevel\":\"DEFAULT\"}]}"
t1 = payloadToUpdate.get("plugins")[0]
t1.__setitem__("enabled", True)
t1.__setitem__("logLevel", "DEFAULT")
payloadToUpdate.__setitem__("plugins", [t1])
t2 = {
"name": str(payloadToUpdate.get("plugins")[0].get("name")),
"newBuild": str(payloadToUpdate.get("plugins")[0].get("buildNumber")),
"newVersion": str(payloadToUpdate.get("plugins")[0].get("version")),
"state": "NEW_INSTALLED"
}
payloadToUpdate.__setitem__("installPluginStates", [t2])
payloadToUpdate.__setitem__("eulaAccepted", True)
payloadToUpdate.__setitem__("forceInstall", True)
payload = json.dumps(payloadToUpdate)
headers = {'Content-Type': 'application/json'}
response = requests.request("POST", url, auth=(username, password), headers=headers, data=payload, verify=False)
statusCode = response.status_code
if (statusCode == 200):
return True
else:
print(f"[ERROR]: Failed to execute Update request. Error code : {statusCode}")
return False
def finishInstallPlugin(vroUrl, username, password, pluginInstallationID, pluginName):
"""Function to finalize the plugin installation."""
url = (f"https://{vroUrl}/vco-controlcenter/api/plugins/installation/{pluginInstallationID}/finish")
headers = {'Content-Type': 'application/json'}
response = requests.request("POST", url, auth=(username, password), headers=headers, verify=False)
statusCode = response.status_code
if (statusCode == 200):
responseData = response.json()
print(f"Enable plugin name {pluginName}")
time.sleep(2)
changePluginState(vroUrl, username, password, pluginName)
return True
else:
print(f"[ERROR]: Failed to execute Finish request. Error code : {statusCode}")
return False
def changePluginState(vroUrl, username, password, pluginName):
"""Function to change set enabled=true which actually completes the installation process."""
url = (f"https://{vroUrl}/vco-controlcenter/api/plugins/state")
payload = json.dumps([{"enabled": True, "name": pluginName}])
headers = {'Content-Type': 'application/json'}
response = requests.request("POST", url, auth=(username, password), headers=headers, data=payload, verify=False)
statusCode = response.status_code
if (statusCode == 200):
return True
else:
print(f"[ERROR]: Failed to execute changePluginState request. Error code : {statusCode}")
return False
def checkPluginInstallation(vroUrl, username, password, pluginInstallationID):
"""Function to check if installation is completed or not."""
url = (f"https://{vroUrl}/vco-controlcenter/api/plugins/installation/{pluginInstallationID}")
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request("GET", url, auth=(username, password), headers=headers, verify=False)
statusCode = response.status_code
print(f"statusCode : {statusCode}")
if (statusCode == 200):
return True
else:
print(f"[ERROR]: Failed to execute checkPluginInstallation request. Error code : {statusCode}")
return False
if __name__ == '__main__':
#User provided data
vroUrl = input("Enter vRO FQDN: [Eg: fqdn.vro.local] ")
username = input("Enter username: [Tip: try root] ")
password = input("Enter password: [Tip: try root password] ")
filename = input("Enter full path of plugin: [Eg: C:/Users/abcd/Downloads/plugin_file.vmoapp] ")
deployPlugin(vroUrl, username, password, filename)

Understand the process

For demo purpose, I will show the very few steps that you need to install a vRO plugin named JsonPath in an automated fashion.

  • Copy the full path of downloaded plugin with filename itself.
    • C:\Users\mayank\Downloads\cloudblogger tutorial\o11nplugin-jsonpath-1.0.2.vmoapp
  • Run the script and provide values to required inputs
  • Reload vRO ControlCenter, the desired plugin will be already installed there.

Subscription received!

Please check your email to confirm your newsletter subscription.

List of all available Python modules in vRO 8.x

List of all Python 3.7 modules that comes preinstalled in vRealize Orchestrator 8.x for quick reference:

__future___warningsgziprunpy
_abc_weakrefhashlibsched
_ast_weakrefsetheapqsecrets
_asyncio_xxtestfuzzhmacselect
_bisectabchtmlselectors
_blake2aifchttpshelve
_bootlocaleantigravityidlelibshlex
_bz2argparseimaplibshutil
_codecsarrayimghdrsignal
_codecs_cnastimpsite
_codecs_hkasynchatimportlibsmtpd
_codecs_iso2022asyncioindexsmtplib
_codecs_jpasyncoreinspectsndhdr
_codecs_kratexitiosocket
_codecs_twaudioopipaddresssocketserver
_collectionsbase64itertoolsspwd
_collections_abcbdbjsonsqlite3
_compat_picklebinasciikeywordsre_compile
_compressionbinhexlib2to3sre_constants
_contextvarsbisectlinecachesre_parse
_cryptbuiltinslocalessl
_csvbz2loggingstat
_ctypescProfilelzmastatistics
_datetimecalendarmacpathstring
_decimalcgimailboxstringprep
_dummy_threadcgitbmailcapstruct
_elementtreechunkmarshalsubprocess
_functoolscmathmathsunau
_hashlibcmdmimetypessymbol
_heapqcodemmapsymtable
_impcodecsmodulefindersys
_iocodeopmultiprocessingsysconfig
_jsoncollectionsnetrcsyslog
_localecolorsysnntplibtabnanny
_lsprofcompileallntpathtarfile
_lzmaconcurrentnturl2pathtelnetlib
_markupbaseconfigparsernumberstempfile
_md5contextlibopcodetermios
_multibytecodeccontextvarsoperatortextwrap
_multiprocessingcopyoptparsethis
_opcodecopyregosthreading
_operatorcryptossaudiodevtime
_osx_supportcsvparsertimeit
_picklectypespathlibtkinter
_posixsubprocessdataclassespdbtoken
_py_abcdatetimepickletokenize
_pydecimaldbmpickletoolstrace
_pyiodecimalpiptraceback
_queuedifflibpipestracemalloc
_randomdispkgutiltty
_sha1distutilsplatformturtle
_sha256doctestplistlibturtledemo
_sha3dummy_threadingpoplibtypes
_sha512emailposixtyping
_signalencodingsposixpathunicodedata
_sitebuiltinsensurepippprintunittest
_socketenumprofileurllib
_sqlite3errnopstatsuu
_srefaulthandlerptvsduuid
_sslfcntlptyvenv
_statfilecmppwdwarnings
_stringfileinputpy_compilewave
_strptimefnmatchpyclbrweakref
_structformatterpydocwebbrowser
_symtablefractionspydoc_datawsgiref
_sysconfigdata_m_linux_x86_64-linux-gnupyexpatxdrlibftplib
_testbufferfunctoolsqueuexml
_testcapigcquoprixmlrpc
_testimportmultiplerandomxxlimitedgenericpath
_testmultiphasegetoptrexxsubtype
_threadgetpassreadlinezipapp
_threading_localgettextreprlibzipfile
_tracemallocglobresourcezipimport
_uuidgrprlcompleterzlib

Tip Run this script in a python-based vRO action to get your own list.

def handler(context, inputs):
	help("modules")
	return None