Automating vRealize Suite Lifecycle Manager with Ansible – Part 1: Setup and Deploy vIDM and LCM

For many years I have been tasked with building vRealize Automation environments, and one of the biggest pain points, has been the deployment and preparation of the IaaS machines. This has usually required special preparation of a Windows template and a number of scripts to get everything configured, so that vRA plays nice. This is usually an error prone process, especially for the larger enterprise deployments. To tackle this problem, VMware released vRealize Suite Lifecycle Manager, which is on version 2.1, as of this writing.

I decided it was time to try this product and see if it lives up to the claims. I was also more interested in the API functionality, and as with all things automation, I typically turn to Ansible. I wasn’t too surprised to discover, that although the deployment is ‘automated’, depending on your interpretation, there is actually a number of manual steps that are still required. These include ensuring that the IaaS machines and database are already deployed and properly configured. The vRLCM Create Environment process also provides validation and pre-checks, along with scripts that can be used to prepare the machines.

With the preparation of these playbooks, I set out to automate the following:

  • Deployment of a single VMware vIDM appliance;
  • Deployment and initial configuration of a single vRealize Suite Lifecycle Manager appliance;
  • Deployment of vRealize Automation IaaS Servers (Windows VMs), in multiple deployment scenarios.
  • Creation of vRealize Automation environment through LCM.

This post will focus on deploying vRSLCM and vIDM with a follow-up post on the vRA deployments.

However, in my attempts to make this a set of one click processes, I wasn’t able to quite get that far (got pretty close). This was mainly due to some limitations with the vRSLCM API (can’t automate certificates, for example). I will discuss these limitations throughout this post, and if I find workarounds, then I’ll provide an update.

I should also point out that this is quite experimental and although I have done all that I can to make these workflows as idempotent as I can, unfortunately, with the limitations of the LCM API, this has proven to be quite difficult. These playbooks are best used as a one-time only deployment, at least for LCM itself.

Environment Preparation

In my environment I have a dedicated virtual machine that I develop and run my playbooks on (you may call this the Ansible control machine) running on CentOS 7.x.

Environment Overview

CentOS CentOS 7.x
Ansible 2.8.1 (2.8 is a minimum requirement)
Python 3.6 (installed from EPEL Repository)

Prerequisites

The following pre-requisites are required:

  • DNS A/PTR records created for vRSLCM and vIDM appliances.

Prepare Environment

Ensure that the system is up-to-date by running:

sudo yum -y update

Install yum-utils

sudo yum -y install yum-utils

Install Python 3

You will need to ensure that Python 3.6 is installed on your Ansible host. I am using the EPEL repository, but you may decided to use IUS or SCL to install these packages, so the package names may differ. Refer to the relevant documentation for installing Python 3 using these repositories, if required.

sudo yum -y install python36 python36-pip python36-devel

Install GIT

Git will be used to clone my Ansible vRSLCM playbooks repository.

sudo yum -y install git

Create Python Environment

It’s always the best approach to create a python virtual environment so that packages do not conflict with the base system. I have a directory in the root of my home dir called ‘python-env‘ where I maintain a number of different environments. Once you have a virtual environment set up, you just need to install the required packages from the ‘requirements.txt‘ file (provided later in the git repository).

You can follow these steps below to create a virtual environment:

mkdir ~/python-env
cd ~/python-dev
python3.6 -m venv ansible_vrlcm
source ansible_vrlcm/bin/activate

You will notice that the shell will now display the virtual environment that you are using:

It’s also a good idea to ensure the latest version of pip and setuptools is installed.

pip install --upgrade pip setuptools

Read more “Automating vRealize Suite Lifecycle Manager with Ansible – Part 1: Setup and Deploy vIDM and LCM”

IaC for vRealize: Deploying vRealize Build Tools To Allow Infrastructure As Code for vRA and vRO

As any vRealize Orchestrator developer will tell you, managing code outside of the appliance is difficult. I recently wrote a post about Using Visual Studio Code for your vRealize Orchestrator Development, where I highlighted some of the challenges with this. The issue is that we’re not given the freedom to use any IDE we want, easily run unit tests on our code or do continuous integration with tools like Jenkins.

I did mention that a couple of solutions were going to make their way, one of these was internal tooling that VMware’s CoE team currently uses for their vRO development (you can read the article here: https://blogs.vmware.com/management/2018/11/automating-at-scale-with-vro-and-vra.html). It wasn’t possible to get access to these tools without engaging with CoE and forking up a bit of cash.

That is until now, as VMware has released these tools as a new fling. The fling is currently in preview, but you can check it out here: https://labs.vmware.com/flings/vrealize-build-tools. I think this is quite an exciting time for VMware developers as these tools could finally change the way we develop and manage our code and integrate into the wider developer ecosystem.

This is my first blog on this topic but if I find these tools useful, then there will be plenty more to follow. Getting the environment set up to use these tools is not straight forward and has several dependencies. These include deploying supporting infrastructure such as JFrog Artifactory, preparing all the required artifacts that are sourced from the vRO server and getting the workstation set up to create and manage packages.

Deploy and Configure Platform

Before the developer can begin using the vRealize Build Tools, the supporting platform has to be deployed and configured. This consists of setting up an Artifactory server to store Maven artifacts and build dependencies and preparing the artifact repositories.

Deploy Artifactory Server (skip if you already have this deployed)

This section will detail how to set up the Artifactory server and required dependencies. Note that the details below only deploy a single Artifactory node with the database instance running on the same machine. It is recommended that for a production environment to ensure Artificatory is deployed with high availability and connects to external/dedicated database instances.

Install Java Development Kit (JDK)

JFrog Artifactory requires the Java JDK 8 and above to be installed and the JAVA_HOME variable configured. I am using the Open Source version of these tools. Install using the following command:

sudo yum install -y java-1.8.0-openjdk-devel

Add the following lines to ‘/etc/profile‘ to set the ‘JAVA_HOME environment variable and add the Java bin directory to the path.

export JAVA_HOME=$(dirname $(dirname $(readlink $(readlink $(which javac)))))
export PATH=$PATH:$JAVA_HOME/bin

Then source the file and check that the variables have been correctly configured:

source /etc/profile
env | grep JAVA_HOME
env | grep PATH

Read more “IaC for vRealize: Deploying vRealize Build Tools To Allow Infrastructure As Code for vRA and vRO”

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 <gavin.stephens@simplygeek.co.uk>
 * @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");
        log.error(errorMessage);
    }
}

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 = hostReservationToStorages.map(function(x){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,
                                                                                                                entitySetName,
                                                                                                                query);
        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 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 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 (it’s quite possible this is 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 <gavin.stephens@simplygeek.co.uk>
 * @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");
        log.error(errorMessage);
    }
}

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,
                                                                                                                entitySetName,
                                                                                                                query);
    numReservations = reservationEntities.length;
    reservationNames = reservationEntities.map(function(x){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”

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:

__api.request.callback.service.id: 8596e261-d50d-4139-9de4-0785e65aa56e
__api.request.id: 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.ImpersonatingUser: 
__Legacy.Workflow.User: stephensg@sgroot.local
__ovf_use_proxy: False
__ovfAuthNeeded: False
__request_reason: 
__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”

vRA Developer: Part 5 – Working with vCAC Virtual Machine Linked Entities

In my previous post vRA Developer: Part 4 – Working with vCAC Virtual Machine Entities, I demonstrated how you could find vCAC virtual machine entities and retrieve and update their properties. In this post I am going to focus on linked entities.

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

There are additional properties that can be retrieved which are part of other entities that the virtual machine has a relationship with. Here are some examples of information that can be retrieved through linked entities (the code for all of these examples is included in the package link provided at the beginning of this post).

  • Host/Cluster Name
  • Reservation Name
  • Owner Username
  • IPv4 Addresses
  • Snapshots
  • Networks

The virtual machine entity object has a method ‘.getLink(vcacHost, “linkKey_string”)‘ that can be used to get the linked entity objects. The ‘.getProperty(“key_string”)‘ can then be used on these entities to get a specific property value, such as the reservation name.

Get the Host or Cluster Name

The following code can be used to get the host or cluster name that the virtual machine (this is referred to as the compute resource within the vRA portal) is hosted on.

/*global vcacHost vcacVmEntity*/

/**
 * Get the compute resource name for the vcac virtual machine entity.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.1.0
 * @function getComputeResourceNameForVirtualMachineEntity
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} vcacVmEntity - The vCAC virtual machine entity.
 * @returns {string} Returns the compute resource name.
 */

function checkParams(vcacHost, vcacVmEntity) {
    var inputErrors = [];
    var errorMessage;
    if (!vcacHost || System.getObjectType(vcacHost) !== "vCAC:VCACHost") {
        inputErrors.push(" - vcacHost missing or not of type 'vCAC:VCACHost'");
    }
    if (!vcacVmEntity || System.getObjectType(vcacVmEntity) !== "vCAC:Entity") {
        inputErrors.push(" - vcacVmEntity missing or not of type 'vCAC:Entity'");
    }
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");
        log.error(errorMessage);
    }
}

var logType = "Action";
var logName = "getComputeResourceNameForVirtualMachineEntity"; // 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 hostEntities = [];
var hostEntity;
var hostName = "";
var hostId = "";
var vmEntityName = "";
var numHostEntities = 0;

try {
    checkParams(vcacHost, vcacVmEntity);
    vmEntityName = vcacVmEntity.getProperty("VirtualMachineName");
    log.log("Getting compute resource name for virtual machine entity: " + vmEntityName);
    hostEntities = vcacVmEntity.getLink(vcacHost, "Host");
    numHostEntities = hostEntities.length;
    if (numHostEntities > 1 ) {
        log.error("More than one compute resource was found.");
    } else if (numHostEntities > 0) {
        hostEntity = hostEntities[0];
        hostName = hostEntity.getProperty("HostName");
        hostId = hostEntity.getProperty("HostID");
        log.log("Found compute resource '" + hostName + "' with entity id '" + hostId + "'");
    } else {
        log.error("No compute resource was found.");
    }
} catch (e) {
    log.error("Action failed to get compute resource name for virtual machine entity.",e);
}

return hostName;

Log output:

[] [I] [Action: getComputeResourceNameForVirtualMachineEntity] Getting compute resource name for virtual machine entity: SG-BG-Deliv0005
[] [I] [Action: getComputeResourceNameForVirtualMachineEntity] Found compute resource 'SITEA-CLS-CLOUD-01' with entity id '355c617e-f9e0-4726-abcf-81f5748c50db'

Read more “vRA Developer: Part 5 – Working with vCAC Virtual Machine Linked Entities”

vRA Developer: Part 4 – Working with vCAC Virtual Machine Entities

In the first post in this series, vRA Developer: Part 1 – IaaS & Understanding The Entity Framework I detailed how you can view the vCAC entities and their associated properties. In this post I am going to cover how you can find a virtual machine entity using different property references and get/update their properties in your vRO workflows. I had intended to provide a single post for this, but felt it would be useful to provide a number of posts, for each specific vCAC entity type. In this post I am going to be looking at the vCAC virtual machine entities.

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

Finding vCAC Virtual Machine Entities

When I need to find a vCAC virtual machine entity, there are 4 search references that work well for all of my use cases. These are to search by:

  • VirtualMachineID – The entity ID.
  • VirtualMachineName – The VM name. Take caution as it’s possible to have duplicate entities with the same VirtualMachineName.
  • VMUniqueID – The unique identifier for the vm (i.e. vCenter VM instance UUID).
  • ExternalReferenceId – The external reference id (i.e. vCenter VM Id (MoRef)).

I have provided all the Actions below which perform these searches and an example log output for each.

Find Virtual Machine By Entity Id

The following code can be used to get the virtual machine entity by its entity id.

/*global vcacHost virtualMachineId*/

/**
 * Searches for a vcac virtual machine entity by its entity id.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.1.0
 * @function findVirtualMachineEntityByVirtualMachineId
 * @param {vCAC:VCACHost} vcacHost - The vCAC Host.
 * @param {string} virtualMachineId - The virtual machine entity id.
 * @returns {vCAC:Entity} Returns the virtual machine entity.
 */

function checkParams(vcacHost, virtualMachineId) {
    var inputErrors = [];
    var errorMessage;
    if (!vcacHost || System.getObjectType(vcacHost) !== "vCAC:VCACHost") {
        inputErrors.push(" - vcacHost missing or not of type 'vCAC:VCACHost'");
    }
    if (!virtualMachineId || typeof virtualMachineId !== "string") {
        inputErrors.push(" - virtualMachineId missing or not of type 'string'");
    }
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");
        log.error(errorMessage);
    }
}

var logType = "Action";
var logName = "findVirtualMachineEntityByVirtualMachineId"; // 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 properties = new Properties();
var vcacVmEntity;
var vcacEntityFieldName = "VirtualMachineID";
var entitySetName = "VirtualMachines";
var vcacVmName = "";

try {
    checkParams(vcacHost, virtualMachineId);
    log.log("finding virtual machine entity with entity id: " + virtualMachineId);
    properties.put(vcacEntityFieldName, virtualMachineId);
    vcacVmEntity = System.getModule("com.simplygeek.library.vcac.entities").getVcacEntitiyByUniqieId(vcacHost,
                                                                                                     entitySetName,
                                                                                                     properties);
    vcacVmName = vcacVmEntity.getProperty("VirtualMachineName");
    log.log("Found virtual machine entity: " + vcacVmName + " with entity id: " + virtualMachineId);
} catch (e) {
    log.error("Action failed to locate vCAC virtual machine entity.",e);
}

return vcacVmEntity;

Log output:

[] [I] [Action: findVirtualMachineEntityByVirtualMachineId] finding virtual machine entity with entity id: 05b6a7b4-1cd6-4762-85ce-fe427c33496a
[] [I] [Action: findVirtualMachineEntityByVirtualMachineId] Found virtual machine entity: SG-BG-Deliv0005 with entity id: 05b6a7b4-1cd6-4762-85ce-fe427c33496a

Read more “vRA Developer: Part 4 – Working with vCAC Virtual Machine Entities”