Using Visual Studio Code for your vRealize Orchestrator Development

Please note that this post was created before VMware released the vRealize Build Tools fling. I have a new series which covers using these tools and in effect, supersedes this post. Please check out my new series on IaC for vRealize: Deploying vRealize Build Tools To Allow Infrastructure As Code for vRA and vRO

When you are developing in a vRealize Orchestrator environment, one of the biggest frustrations is being limited to the vRO IDE. The vRO IDE is very simple, in that it does not provide any of the features that you would expect from an IDE, such as IntelliSense and quality of life extensions/addons, and only provides basic syntax checking.

There is no integration with source control management systems such as GIT (it has an internal system which isn’t great), moving code can be difficult and unit testing in the true sense of development, doesn’t exist. A connection to the vRO IDE uses a JAVA client and also requires a constant connection to the vRO server, so developing on the move or offline isn’t possible.

Anyone that has developed on this platform will have experienced the same issues and can only dream of the day when this is no longer the case.

You can use an IDE called Visual Studio Code, that can help make your development life easier. Admittedly, this alone doesn’t solve all of the discussed problems, but it does allow you to leverage the power of this IDE to assist in code development. There are still restrictions, such as lack of integration with vRO itself, which requires the code to be manually copied to the vRO server (yes, annoying). The good news, however, is that solutions are starting to become available to provide that integration. I am going to expand more on this at the end of this post.

If you haven’t heard of Visual Studio Code, it is a lightweight and features rich IDE created by Microsoft. The Visual Studio Code website describes it as:

Visual Studio Code combines the simplicity of a source code editor with powerful developer tooling, like IntelliSense code completion and debugging.

First and foremost, it is an editor that gets out of your way. The delightfully frictionless edit-build-debug cycle means less time fiddling with your environment, and more time executing on your ideas.

Visual Studio Code supports macOS, Linux, and Windows – so you can hit the ground running, no matter the platform.

I do almost all of my vRO development using Visual Studio Code, which gives me access to useful extensions and most importantly, keeps me in the mindset of how a developer should work.

In this post, I am going to cover how to set up a Visual Studio Code environment in Windows, install some useful extensions that I like to use and the installation of GIT and other required software components.

Setting Up Your Development Environment

The first thing that you will want to do, is download and install Visual Studio Code from here. When you launch this for the very first time, you’ll get an immediate good impression, from how quickly it loads and how lightweight it feels. The default dark theme is also quite nice.

Read more “Using Visual Studio Code for your vRealize Orchestrator Development”

vRA Developer: Part 8 – Working with vCAC Reservation Storage

In my previous post, I covered working with vcac reservations and provided examples of how you can retrieve property values and also linked entities, such as networks and virtual machines. In this post I am going to cover reserved storage. I planned to include this in the previous post, but the content was becoming too large, so I decided to split them.

The Actions provided here should be useful if you ever need to work with storage outside of vRA (for example, when adding or resizing a virtual hard disk directly in vCenter) and can be used to query reservation information first. This can prevent cases where storage can exceed that which is allocated/reserved for the tenant.

Here is how the reserved storage looks for the reservation that I will be working with:

All code that I have provided or talked about in this post can be downloaded as a vRO package for your consumption here.

I have also included a number of workflows in the package, which provide examples of these actions being used.

You can find these under ‘Simplygeek -> Library -> Common Workflows -> vRealize Automation -> Examples -> Reservations

Get Reserved Storage Information

The following sections provide vRO Actions that can be used to get information about storage that has been reserved in a reservation or get details of physical capacity.

Get Storage Reserved Capacity for a Reservation

The following action accepts a storage path and the reservation entity and will return the total amount of storage that has been reserved for the reservation.

/*global System vcacHost reservationEntity storagePath*/

 * Gets the reserved storage capacity total for the storage path in the reservation.
 * @author Gavin Stephens <>
 * @version 1.0.0
 * @function getReservedStorageCapacityTotalForReservation
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} reservationEntity - The vCAC reservation entity.
 * @param {string} storagePath - The storage path.
 * @returns {number} Returns the reserved storage capacity in GB.

function checkParams(vcacHost, reservationEntity, storagePath) {
    var inputErrors = [];
    var errorMessage;

    if (!vcacHost || System.getObjectType(vcacHost) !== "vCAC:VCACHost") {
        inputErrors.push(" - vcacHost missing or not of type 'vCAC:VCACHost'");
    if (!reservationEntity || System.getObjectType(reservationEntity) !== "vCAC:Entity") {
        inputErrors.push(" - reservationEntity missing or not of type 'vCAC:Entity'");
    if (!storagePath || typeof storagePath !== "string") {
        inputErrors.push(" - storagePath missing or not of type 'string'");
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");

var logType = "Action";
var logName = "getReservedStorageCapacityTotalForReservation"; // This must be set to the name of the action
var Logger = System.getModule("com.simplygeek.library.util").logger(logType, logName);
var log = new Logger(logType, logName);
var reservedCapacityGB = 0;
var reservationName = "";
var hostReservationToStorages = [];
var resStoragePaths = [];
var query = "";
var entitySetName = "HostReservationToStorages";
var storageEntities = [];

try {
    checkParams(vcacHost, reservationEntity, storagePath);
    reservationName = reservationEntity.getProperty("HostReservationName");
    log.log("Getting reserved storage capacity total for '" + storagePath + "' in reservation '" + reservationName + "'");
    hostReservationToStorages = reservationEntity.getLink(vcacHost, "HostReservationToStorages");
    resStoragePaths ={return x.getLink(vcacHost, "HostToStorage")[0].getProperty("StoragePath");});
    if (resStoragePaths.indexOf(storagePath) !== -1) {
        query = "HostToStorage/StoragePath eq '" + storagePath + "'";
        storageEntities = System.getModule("com.simplygeek.library.vcac.entities").getVcacEntitiesBySystemQuery(vcacHost,
        reservedCapacityGB = storageEntities[0].getProperty("MaxCapacity");
    } else {
        log.error("Storage path '" + storagePath + "' not found in reservation '" + reservationName + "'");
    log.log("Reserved storage capacity total: " + reservedCapacityGB + " GB");
} catch (e) {
    log.error("Action failed to get reserved storage capacity total for vcac reservation.",e);

return reservedCapacityGB;

Read more “vRA Developer: Part 8 – Working with vCAC Reservation Storage”

vRA Developer: Part 7 – Working with vCAC Reservation Entities

Reservations are created in vRA to allocate memory, storage and network resources to a business group. Business groups can consume these resources by provisioning virtual machines.

In this post, I am going to cover the vCAC Reservation Entities and provide some workflows and actions that can be used to get information about reservations programmatically. This can be useful to gather information about the reservations if you are using custom XaaS processes that would not trigger the standard built-in reservation checks.

All code that I have provided or talked about in this post can be downloaded as a vRO package for your consumption here.

I have also included several workflows in the package, which provide examples of these actions being used.

You can find these under ‘Simplygeek -> Library -> Common Workflows -> vRealize Automation -> Examples -> Reservations

Get a List of Available Reservations or Get a Specific Reservation

The following code can be used to get a list of all reservations that are available for the specified tenant or retrieve a specific reservation based on its name or unique id.

This is specifically the reservation that I will be working with and will appear in the log outputs.

Get List of Available Reservations For a Tenant

The following code will accept a tenant Id and a toggle for retrieving only enabled reservations. A list of reservation string names will be returned. This isn’t as straight forward as you would hope (at least from an entities point of view), because there is no property for the tenant id on the reservation. Instead, I had to inspect the business group that the reservation is assigned to, which does have a tenant id property (this may be how the GUI does it too).

/*global vcacHost tenantId enabledOnly*/

 * Gets a list of reservations that have been created for the
 * specified tenant id.
 * @author Gavin Stephens <>
 * @version 1.0.0
 * @function getListOfReservationNamesForTenant
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {string} tenantId - The tenant id.
 * @param {boolean} [enabledOnly] - Show only Enabled reservations?
 * @returns {string[]} return a list of reservations for the tenant.

function checkParams(vcacHost, tenantId) {
    var inputErrors = [];
    var errorMessage;

    if (!vcacHost || System.getObjectType(vcacHost) !== "vCAC:VCACHost") {
        inputErrors.push(" - vcacHost missing or not of type 'vCAC:VCACHost'");
    if (!tenantId || typeof tenantId !== "string") {
        inputErrors.push(" - tenantId missing or not of type 'string'");
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");

var logType = "Action";
var logName = "getListOfReservationNamesForTenant"; // This must be set to the name of the action
var Logger = System.getModule("com.simplygeek.library.util").logger(logType, logName);
var log = new Logger(logType, logName);
var entitySetName = "HostReservations";
var reservationNames = [];
var numReservations = 0;
var query = "";
var reservationEntities = [];
var enabledReservations = true;

try {
    checkParams(vcacHost, tenantId);
    log.log("Getting a list of reservations for tenant: " + tenantId);
    if (!enabledOnly) {
        enabledReservations = false;
    query = "ProvisioningGroup/TenantID eq '" + tenantId.toLowerCase() + "'";
    if (enabledReservations) {
        query += " and Enabled eq " + enabledReservations;
    reservationEntities = System.getModule("com.simplygeek.library.vcac.entities").getVcacEntitiesBySystemQuery(vcacHost,
    numReservations = reservationEntities.length;
    reservationNames ={return x.getProperty("HostReservationName");});
    for (var i = 0; i < numReservations; i++) {
        var reservationName = reservationEntities[i].getProperty("HostReservationName");
        var reservationId = reservationEntities[i].getProperty("HostReservationID");

        log.log("Found reservation '" + reservationName + "' with id '" + reservationId + "'");
    log.log("Found a total of " + numReservations + " reservation(s).");
} catch (e) {
    log.error("Failed to get a list of reservations for tenant.",e);

return reservationNames;

Log output:

[] [I] [Action: getListOfReservationNamesForTenant] Getting a list of reservations for tenant: sg
[] [I] [Action: getListOfReservationNamesForTenant] Found reservation 'RES-SITEA-vSphere-Resource-01' with id '8e1534f6-c65c-412b-af8b-b4ad8ee3c6cb'
[] [I] [Action: getListOfReservationNamesForTenant] Found a total of 1 reservation(s).

Read more “vRA Developer: Part 7 – Working with vCAC Reservation Entities”

Deploying NSX-T Using Ansible – Part 3: Running The Playbook

In this post, I am going to cover the running of the Ansible NSX-T playbook so that you can get NSX-T deployed in your environment(s). In case you missed them, in my previous posts, I detailed how to set up your Ansible environment and configure the playbook in preparation for deploying NSX-T.

If you arrived here and want to figure it out for yourself, you can download my playbooks here.

Playbook Overview

The main playbook that you will need to run is called ‘nsxt_create_environment.yml‘, which is located in the root of the Ansible-NSXT folder.

## Deploys an NSX-T environment
- hosts: nsxt_managers_controllers
  connection: local
  become: yes
  gather_facts: False
    nsxt_deployment_vcenter: "{{ mgmt_vcenter_server }}"
    nsxt_deployment_vcenter_username: "{{ mgmt_vcenter_admin_username }}"
    nsxt_deployment_vcenter_password: "{{ mgmt_vcenter_admin_password }}"
    nsxt_deployment_datacenter: "{{ mgmt_vcenter_datacenter }}"
    nsxt_deployment_cluster: "{{ mgmt_vcenter_cluster }}"
    nsxt_deployment_datastore: "{{ nsxt_datastore }}"
    nsxt_deployment_portgroup: "{{ nsxt_portgroup }}"
    nsxt_deployment_size: "{{ nsxt_default_deployment_size }}"
    nsxt_role: "{{ nsxt_default_role }}"

    - name: "{{ nsxt_compute_manager_name }}"
      host: "{{ nsxt_compute_manager_host }}"
      transport_clusters: "{{ nsxt_transport_clusters }}"

    - display_name: "{{ nsxt_transport_switch_ip_pool_name }}"
      - allocation_ranges:
        - start: "{{ nsxt_transport_switch_ip_pool_start }}"
          end: "{{ nsxt_transport_switch_ip_pool_end }}"
        cidr: "{{ nsxt_transport_switch_ip_pool_cidr }}"

    - display_name: "{{ nsxt_transport_zone_name }}"
      description: "{{ nsxt_transport_zone_desc }}"
      transport_type: "OVERLAY"
      transport_switch_name: "{{ nsxt_transport_switch_name }}"

    - display_name: "{{ nsxt_transport_switch_uplink_profile_name }}"
        - uplink_name: "{{ nsxt_transport_switch_uplink_1 }}"
          uplink_type: PNIC
        - uplink_name: "{{ nsxt_transport_switch_uplink_2 }}"
          uplink_type: PNIC
        policy: "{{ nsxt_transport_switch_uplink_profile_policy }}"
      transport_vlan: "{{ nsxt_transport_switch_uplink_profile_vlan }}"

    - display_name: "{{ nsxt_transport_node_profile_name }}"
      description: "{{ nsxt_transport_switch_profile_desc }}"
      - host_switch_profiles:
        - name: "{{ nsxt_transport_switch_uplink_profile_name }}"
          type: UplinkHostSwitchProfile
        host_switch_name: "{{ nsxt_transport_switch_name }}"
        - device_name: "{{ nsxt_transport_switch_pnic_1 }}"
          uplink_name: "{{ nsxt_transport_switch_uplink_1 }}"
        - device_name: "{{ nsxt_transport_switch_pnic_2 }}"
          uplink_name: "{{ nsxt_transport_switch_uplink_2 }}"
          resource_type: StaticIpPoolSpec
          ip_pool_name: "{{ nsxt_transport_switch_ip_pool_name }}"
      - transport_zone_name: "{{ nsxt_transport_zone_name }}"
    - nsxt_deploy_ova
    - nsxt_apply_license
    - nsxt_add_compute_managers
    - nsxt_create_ip_pools
    - nsxt_create_transport_zones
    - nsxt_create_uplink_profiles
    - nsxt_create_transport_profiles
    - nsxt_configure_transport_clusters

Read more “Deploying NSX-T Using Ansible – Part 3: Running The Playbook”

Deploying NSX-T Using Ansible – Part 2: Setting Up The Playbook

In my previous post, I covered how to prepare your Ansible environment and install the VMware NSX-T modules. I also provided the details on how to install my Ansible playbooks for deploying NSX-T in your environments.

In this post, I am going to detail how to configure these playbooks to meet your environment/requirements. I have chosen to break out my variables into multiple files. This gives me the flexibility to assign values specific to a group of hosts, inherit values from a parent group and to store usernames, passwords and license information more securely, in their own Ansible Vault encrypted file.

The deployment examples that I will demonstrate include 2 sites, that each includes the following:

  • A management environment at each site. This includes a vCenter Server instance with a single management cluster.
  • A compute resource (CMP) environment at each site. This includes a vCenter Server instance with a single resource cluster.

I will deploy an NSX-T instance at each management cluster. These NSX-T instances will be used to provide SDN capabilities to the compute resource clusters (when I get time I’ll create a diagram!).

An overview of the playbook tree:

├── ansible.cfg
├── nsxt_create_environment.yml
├── nsxt_example_add_compute_manager.yml
├── nsxt_example_apply_license.yml
├── nsxt_example_create_ip_pools.yml
├── nsxt_example_create_transport_profiles.yml
├── nsxt_example_create_transport_zones.yml
├── nsxt_example_create_uplink_profiles.yml
├── nsxt_example_deploy_ova.yml
├── group_vars
│   ├── all
│   ├── nsxt_managers_controllers
│   ├── site_a
│   ├── site_a_cmp_nsxt
│   ├── site_b
│   └── site_b_cmp_nsxt
├── inventory
│   └── hosts
├── roles
│   ├── nsxt_add_compute_managers
│   ├── nsxt_apply_license
│   ├── nsxt_check_manager_status
│   ├── nsxt_configure_transport_clusters
│   ├── nsxt_create_ip_pools
│   ├── nsxt_create_transport_profiles
│   ├── nsxt_create_transport_zones
│   ├── nsxt_create_uplink_profiles
│   └── nsxt_deploy_ova
├── ssh_config

Read more “Deploying NSX-T Using Ansible – Part 2: Setting Up The Playbook”

Deploying NSX-T Using Ansible – Part 1: Setting Up The Environment

When I saw the release of NSX-T 2.4, I decided that I would upgrade my compute clusters to utilise this new version. Since I manage the compute NSX managers mostly through the API, I figured this would provide me with some good experience and also allow me to understand how this is deployed.

In my lab I run vRealize Automation with a management cluster (CMP stack), 2 nested vCenter Servers and ESXi Clusters (compute) that mimic two geographically dispersed data centres. Until now I had deployed a dedicated NSX-V instance for each of my three vCenter deployments, that provides the logical switching and routing required for my lab.

I didn’t want to create yet another ‘how to’ guide on how to do this using the GUI, so instead, I am going to attempt to accomplish this using Ansible. VMware have handily made available Ansible modules for NSX-T, which are supported for the 2.4 release and above (note that these are still in preview). I will attempt to make use of these modules, but if I discover broken or missing functionality, then I will revert to using the NSX-T Rest API.

Link to the VMware Github repository for Ansible NSX-T:

Link to my Github Ansible NSX-T Deployment Playbooks:

I am going to provide a series of posts that will cover the set up of the Ansible environment, how to install the VMware NSX-T modules and use the playbooks and roles that I have created to deploy NSX-T in your environments. Read more “Deploying NSX-T Using Ansible – Part 1: Setting Up The Environment”

vRealize Automation Virtual Machine is Missing after being Moved or Recovered

Have you ever seen a deployed virtual machine in the vRA portal have its status changed to ‘Missing‘? This can happen for two reasons; The first, obvious reason, is that the source virtual machine has been deleted. Not much you can do about that except re-provision it or restore the vm from backup. The second reason, is because the reference information that vRA holds about the virtual machine is no longer valid (perhaps from an earlier restore).

In this post, I will discuss and provide a solution that will address the latter for a vSphere hosted virtual machine.

When in this state, you will not be able to perform day 2 actions on this virtual machine (apart from destroy).

The following scenarios can explain why vRA has incorrect reference data about the virtual machine:

  • The virtual machine has been recovered from backup and a new instance uuid has been created;
  • The virtual machine has moved to another vCenter Server, maybe during a DR event. I know that Zerto will create a new virtual machine at the DR site which will have a different instance uuid (SRM’s shadow VMs are most likely similar but I can’t confirm);
  • The virtual machine was cloned and the original has been deleted;
  • The instance uuid for the virtual machine has been changed, either manually or by some other process.

Read more “vRealize Automation Virtual Machine is Missing after being Moved or Recovered”

vRA Developer: Part 6 – Working with vCAC Virtual Machine Custom Properties

In part 4 and part 5, I covered a lot of ground on how to work with vcac virtual machine objects, such as getting property values and discovering relationships to other entities. This post will continue exploring vcac virtual machines and will focus on custom properties.

Custom Properties are key/value pairs of data that are associated with the virtual machine. There are many default/built-in custom properties that provide the compute cluster, storage cluster, disk, cpu, network information and much more.

It’s also possible to create your own custom properties and associate these with your virtual machine deployments. This allows great flexibility as you can apply any key/value to your deployments and use this information in your workflows. An example might be to set a site identifier that associates the virtual machine to a specific site.

VMware provides a Custom Properties Reference, which details all the built-in custom properties that are available.

All code that I have provided or talked about in this post can be downloaded as a vRO package for your consumption here.

Retrieving Custom Properties Assigned to a Virtual Machine

There are two main ways to retrieve the custom properties that have been associated with a virtual machine deployment. The first, is during the build process, where an Event Broker Subscription is used to call a vRO workflow, to perform some task. The second, is by reading the custom properties from the vcac database (via the entities) for those that are related to the virtual machine.

Here is an example of a default set of Custom Properties associated with a deployed virtual machine: 8596e261-d50d-4139-9de4-0785e65aa56e f4c168ec-5ce6-4afb-b985-a4dc2a46fee7
__Cafe.Request.BlueprintType: 1
__Cafe.Root.Request.Id: 681db0aa-3a52-47dc-9b62-8a6f5262bd8c
__iaas_request_binding_id: f8832686-273b-491e-bfa5-3a42b7c060d0
__InterfaceType: vSphere
__Legacy.Workflow.User: stephensg@sgroot.local
__ovf_use_proxy: False
__ovfAuthNeeded: False
__reservationPolicyID: 2a539d78-c6a8-446b-b9d7-a72d04fbbdda
__trace_id: CmGY5ZR3
__VirtualMachine.Allocation.InitialMachineState: SubmittingRequest
__VirtualMachine.ProvisioningWorkflowName: BasicVmWorkflow
_number_of_instances: 1
Cafe.Shim.VirtualMachine.TotalStorageSize: 1
trace_id: CmGY5ZR3
VirtualMachine.Admin.AgentID: f8611a42-2d9a-8544-df8e-bf4e5291bd37
VirtualMachine.Admin.Hostname: SITEA-CLS-CLOUD-01
VirtualMachine.Admin.ThinProvision: True
VirtualMachine.Admin.TotalDiskUsage: 1024
VirtualMachine.Admin.UUID: 501a484f-d95c-0cb8-42b6-cf174af3db2d
VirtualMachine.Cafe.Blueprint.Component.Cluster.Index: 0
VirtualMachine.Cafe.Blueprint.Component.Id: vm1
VirtualMachine.Cafe.Blueprint.Component.TypeId: Infrastructure.CatalogItem.Machine.Virtual.vSphere
VirtualMachine.Cafe.Blueprint.Id: VM_NoDisk
VirtualMachine.Cafe.Blueprint.Name: VM_NoDisk
VirtualMachine.CPU.Count: 1
VirtualMachine.Disk0.DeviceID: SCSI (0:0)
VirtualMachine.Disk0.ExternalID: 6000C296-9f11-58ec-31ca-058625b51c19
VirtualMachine.Disk0.IsClone: false
VirtualMachine.Disk0.IsFixed: False
VirtualMachine.Disk0.Name: Hard disk 1
VirtualMachine.Disk0.Size: 1
VirtualMachine.Disk0.Storage: DSC-SITEA-BRONZE-01
VirtualMachine.Disk0.Storage.Cluster.ExternalReferenceId: group-p291
VirtualMachine.Disk0.Storage.Cluster.Name: DSC-SITEA-BRONZE-01
VirtualMachine.Memory.Size: 1024
VirtualMachine.Network0.MacAddress: 00:50:56:9a:3e:5f
VirtualMachine.Network0.Name: vxw-dvs-314-virtualwire-8-sid-5005-SiteA-Transit-South
VirtualMachine.Storage.Cluster.Automation.Behavior: manual
VirtualMachine.Storage.Cluster.Automation.Enabled: True
VirtualMachine.Storage.Cluster.ExternalReferenceId: group-p291
VirtualMachine.Storage.Cluster.Name: DSC-SITEA-BRONZE-01
VirtualMachine.Storage.Name: DSC-SITEA-BRONZE-01
VMware.VirtualCenter.OperatingSystem: windows7Server64Guest
Vrm.ProxyAgent.Uri: https://sg1-vrm001.sgroot.local/VMPS2Proxy

The first set are prefixed with a double underscore (__), which denotes that these are ‘hidden’ properties that are used by the system and provide object references to the reservation and the request (note that these properties will not be referenced in the official VMware Custom Properties Reference).

The remaining properties are the key/values associated with the virtual machine and can provide cpu count, amount of assigned memory, used storage, etc. and any user-defined custom properties that you have created. Unlike the hidden properties. you will find a reference to all of these in the VMware Custom Properties Reference.

One important thing to note, is that when you are working with custom property values, these are always returned as a string, regardless of what data is being stored. I.e. if a custom property has a value of ‘false’, this is the literal string “false” and not Boolean false. Read more “vRA Developer: Part 6 – Working with vCAC Virtual Machine Custom Properties”