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.

Retrieve Custom Properties Using vCAC Entities

This method of retrieving custom properties accesses them directly from the vcac entities (the data sources) by finding custom properties that are ‘linked’ to the virtual machine. This is really useful when you need to use custom properties in your workflows. Note that the Extensibility Lifecycle properties do not affect how this works and you will be able to retrieve all custom properties, including hidden ones.

I have provided Actions in the download package that can be used to retrieve all of the following:

  • Blueprint Id;
  • Blueprint Name;
  • Component Id;
  • Cloned From (the template that was used for the new vm);
  • Compute Resource Name (Host/Cluster);
  • Guest Customization specification used;
  • CPU count, memory size;
  • disk sizes, total disk usage, disk device Id;
  • Attached networks;
  • Guest OS Identifier;
  • Host Name;
  • Storage Cluster Name;
  • vCenter Folder;
  • Virtual Machine UUID;
  • Reservation Policy ID.

Get Custom Properties Set

The following code will accept a vcac entity object as an input and will return a Properties object that contains all the key/value pairs of the custom properties. I find this useful as it allows me to ‘cache’ the properties in my workflow when I need to retrieve multiple values without constantly requested the full payload.

/*global System Properties vcacHost vcacVmEntity*/

/**
 * Gets the custom properties that are associated with the provided vcac virtual machine.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.1.0
 * @function getCustomProperties
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} vcacVmEntity - The vCAC virtual machine entity.
 * @returns {Properties} Returns the custom properties.
 */

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 = "getCustomProperties"; // 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 vmProperties = new Properties();
var vmPropertiesEntities = [];
var propertyName = "";
var propertyValue = "";

try {
    checkParams(vcacHost, vcacVmEntity);
    log.debug("Retrieving custom properties for vcac virtual machine.");
    vmPropertiesEntities = vcacVmEntity.getLink(vcacHost, "VirtualMachineProperties");
    log.debug("The following Custom Properties were found:");
    for (var i = 0; i < vmPropertiesEntities.length; i++) {
        propertyName = vmPropertiesEntities[i].getProperty("PropertyName");
        propertyValue = vmPropertiesEntities[i].getProperty("PropertyValue");
        log.debug(propertyName + ": " + propertyValue);
        vmProperties.put(propertyName, propertyValue);
    }
} catch (e) {
    log.error("Action failed to retrieve custom properties for vcac virtual machine.",e);
}

return vmProperties;

Log output (truncated):

[D] [Action: getCustomProperties] __api.request.callback.service.id: 8596e261-d50d-4139-9de4-0785e65aa56e
[D] [Action: getCustomProperties] __api.request.id: f4c168ec-5ce6-4afb-b985-a4dc2a46fee7
[D] [Action: getCustomProperties] __Cafe.Request.BlueprintType: 1
...
[D] [Action: getCustomProperties] VirtualMachine.Storage.Name: DSC-SITEA-BRONZE-01
[D] [Action: getCustomProperties] VMware.VirtualCenter.OperatingSystem: windows7Server64Guest
[D] [Action: getCustomProperties] Vrm.ProxyAgent.Uri: https://sg1-vrm001.sgroot.local/VMPS2Proxy

Get a Specific Custom Property Value from the Set

The following contains 2 code examples that are used to retrieve a value from a custom property. The first code example is a helper Action, that will do the work of retrieving the value. The helper Action accepts the Custom Properties payload (the Properties object that was created from the code, above) as an input along with a property key. It will then return the value for that property, as a string.

The idea of this action is that is will be used with wrappers for specific custom property lookups. These wrappers will then return the expected data type that is more useful, such as a Number when retrieving the number of cpu’s.

/*global System Properties vmProperties, customPropertyKey*/

/**
 * Looks up the provided Custom Property and returns its value.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.1.0
 * @function getValueFromCustomProperty
 * @param {Properties} vmProperties - The Custom Properties payload.
 * @param {string} customPropertyKey - The Custom Property key to get the value of.
 * @returns {string} Returns the value found for the specified Custom Property.
 */

function checkParams(vmProperties, customPropertyKey) {
    var inputErrors = [];
    var errorMessage;
    if (!vmProperties || !(vmProperties instanceof Properties)) {
        inputErrors.push(" - vmProperties missing or not of type 'Properties'");
    }
    if (!customPropertyKey || typeof customPropertyKey !== "string") {
        inputErrors.push(" - customPropertyKey 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 = "getValueFromCustomProperty"; // 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 customPropertyValue;

try {
    checkParams(vmProperties, customPropertyKey);
    log.debug("Retrieving value for custom property with key: " + customPropertyKey);
    customPropertyValue = vmProperties.get(customPropertyKey);
    if (!customPropertyValue) {
        log.error("No value was found or custom property does not exist.");
    }
    log.debug("Found value: " + customPropertyValue);
} catch (e) {
    log.error("Action failed to retrieve value for custom property.",e);
}

return customPropertyValue;

The next Action is an example of a wrapper that uses the helper, above. As I previously stated, although the return value from the Custom Property is always a string, I will change this in the wrapper to the correct data type. This makes it far cleaner and convenient when I use these Actions in my workflows. This Action also accepts the Custom Properties payload and property key, which it passes through to the helper Action.

/*global System Properties vmProperties*/

/**
 * Looks up the number of CPUs assigned to the virtual machine from the custom properties.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.1.0
 * @function getCpuCountFromCustomProperties
 * @param {Properties} vmProperties - The Custom Properties payload.
 * @returns {number} Returns the number of CPUs.
 */

function checkParams(vmProperties) {
    var inputErrors = [];
    var errorMessage;
    if (!vmProperties || !(vmProperties instanceof Properties)) {
        inputErrors.push(" - vmProperties missing or not of type 'Properties'");
    }
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");
        log.error(errorMessage);
    }
}

var logType = "Action";
var logName = "getCpuCountFromCustomProperties"; // 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 customPropertyKey = "VirtualMachine.CPU.Count";
var customPropertyValue;
var friendlyLabel = "CPU Count";
var cpuCount = 0;

try {
    checkParams(vmProperties);
    log.log("Retrieving " + friendlyLabel + " from custom properties with key: " + customPropertyKey);
    customPropertyValue = System.getModule("com.simplygeek.library.vcac.vm.customproperties").getValueFromCustomProperty(vmProperties,
                                                                                                                         customPropertyKey);
    cpuCount = parseInt(customPropertyValue);
    log.log("Found " + friendlyLabel + ": " + customPropertyValue);
} catch (e) {
    log.error("Action failed to retrieve " + friendlyLabel + " from custom properties.",e);
}

return cpuCount;

Below is what my workflow would look like to retrieve the number of CPUs assigned to the virtual machine taken from the custom properties.

I first get the default vcacHost from the inventory. I then find the virtual machine entity by its entity id. Once I have the virtual machine entity, I get the custom properties payload and then finally extract the number of CPUs from a property that exists in that payload.

Log output:

[] [I] [Action: getVcacHost] Locating vCAC IaaS Host...
[] [I] [Action: getVcacHost] Found vCAC IaaS host: IaaS host for Default [https://web.vra.sgroot.local/]
[] [I] [Action: findVirtualMachineEntityByVirtualMachineId] finding virtual machine entity with entity id: 62751722-b60b-40be-8d6d-e9c6c71a8c56
[] [I] [Action: findVirtualMachineEntityByVirtualMachineId] Found virtual machine entity: SG-BG-Deliv0006 with entity id: 62751722-b60b-40be-8d6d-e9c6c71a8c56
[] [I] [Action: getCpuCountFromCustomProperties] Retrieving CPU Count from custom properties with key: VirtualMachine.CPU.Count
[] [I] [Action: getCpuCountFromCustomProperties] Found CPU Count: 1

Retrieve Custom Properties Using an Event Broker Subscription

When I am working with the event broker, I have an action that will get the custom properties payload. I can then use the Actions that I described above with this payload as an input. I like to maintain compatibility between my Actions. In a future post I will cover the Event Broker in more detail.

/*global System Properties ebsPayload*/

/**
 * Gets the custom properties associated with the virtual machine from the event broker.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.1.0
 * @function getCustomPropertiesFromEbsPayload
 * @param {Properties} ebsPayload - The event broker payload.
 * @returns {Properties} Returns the properties object containing the custom properties.
 */

function checkParams(ebsPayload) {
    var inputErrors = [];
    var errorMessage;
    if (!ebsPayload || !(ebsPayload instanceof Properties)) {
        inputErrors.push(" - ebsPayload missing or not of type 'Properties'");
    }
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");
        log.error(errorMessage);
    }
}

var logType = "Action";
var logName = "getCustomPropertiesFromEbsPayload"; // 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 vmProperties = new Properties();
var propertyValue;
var propertyNames = [];
var propertyName;

try {
    checkParams(ebsPayload);
    log.debug("Getting VM Custom Properties from EBS Payload");
    vmProperties = ebsPayload.machine.get("properties");
    propertyNames = vmProperties.keys;
    for (var i = 0; i < propertyNames.length; i++) {
        propertyName = propertyNames[i];
        propertyValue = vmProperties.get(propertyName);
        log.debug("Found property " + propertyName + ": " + propertyValue);
    }
} catch (e) {
    log.error("Action failed to get VM Custom Properties from EBS payload.",e);
}

return vmProperties;

Add or Update Custom Properties

When adding new custom properties to a virtual machine, or updating existing ones, I again use a helper Action that does the bulk of the work. This Action is designed to be used with a wrapper Action that provides its values.

The helper Action will detect if a custom property exists and if it does not, then the custom property is created, with the specified value. If the custom property already exists then the value is checked against the specified value to update. If the values match then no update is made, otherwise, the custom property is updated with the specified value.

The code below is the helper Action:

/*global System Properties
         vcacHost vcacVmEntity customPropertyKey customPropertyValue
         propertyIsHidden propertyIsRuntime propertyIsEncrypted
*/

/**
 * Adds a new custom property or updates an existing one.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.1.0
 * @function addOrUpdateCustomProperty
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} vcacVmEntity - The vcac virtual machine entity.
 * @param {string} customPropertyKey - The custom property key.
 * @param {string} customPropertyValue - The custom property value.
 * @param {boolean} [propertyIsHidden] - Property 'isHidden' flag [optional].
 * @param {boolean} [propertyIsRuntime] - Property 'isRuntime' flag [optional].
 * @param {boolean} [propertyIsEncrypted] - Property 'isHidden' flag [optional].
 * @returns {vCAC:Entity} Returns the new or updated custom property entity.
 */

function checkParams(vcacHost, vcacVmEntity, customPropertyKey, customPropertyValue) {
    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 (!customPropertyKey || typeof customPropertyKey !== "string") {
        inputErrors.push(" - customPropertyKey missing or not of type 'string'");
    }
    if (!customPropertyValue || typeof customPropertyValue !== "string") {
        inputErrors.push(" - customPropertyValue 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 = "addOrUpdateCustomProperty"; // 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 newOrUpdatedEntity;
var customPropertyExists = false;
var properties = new Properties();
var links = new Properties();
var currentPropertyValue;
var newOrUpdatedPropertyValue;
var customPropertyEntities = [];
var customPropertyEntitiesFiltered = [];
var customPropertyEntity;
var entitySetName = "VirtualMachineProperties";
var isHidden = false;
var isRuntime = false;
var isEncrypted = false;

try {
    checkParams(vcacHost, vcacVmEntity, customPropertyKey, customPropertyValue);
    log.log("Adding or updating custom property '" + customPropertyKey + "' with value '" + customPropertyValue + "'");
    if (propertyIsHidden) {
        isHidden = true;
    }
    if (propertyIsRuntime) {
        isRuntime = true;
    }
    if (propertyIsEncrypted) {
        isEncrypted = true;
    }
    properties.put("PropertyName", customPropertyKey);
    properties.put("PropertyValue", customPropertyValue);
    properties.put("IsHidden", isHidden);
    properties.put("IsRuntime", isRuntime);
    properties.put("IsEncrypted", isEncrypted);
    links.put("VirtualMachine",vcacVmEntity);

    customPropertyEntities = vcacVmEntity.getLink(vcacHost, "VirtualMachineProperties");
    customPropertyEntitiesFiltered = customPropertyEntities.filter(function(x){return x.getProperty("PropertyName") === customPropertyKey;});
    if (customPropertyEntitiesFiltered.length > 0) {
        customPropertyEntity = customPropertyEntitiesFiltered[0];
        customPropertyExists = true;
    }

    if (customPropertyExists) {
        log.log("An existing Custom Property was found and will be updated.");
        currentPropertyValue = customPropertyEntity.getProperty("PropertyValue");
        if (currentPropertyValue === customPropertyValue) {
            log.log("Custom Property '" + customPropertyKey + "' already set to: '" + customPropertyValue + "', no update required.");
        } else {
            newOrUpdatedEntity = System.getModule("com.simplygeek.library.vcac.entities").updatevCACEntity(customPropertyEntity,
                                                                                                           properties,
                                                                                                           links);
            newOrUpdatedPropertyValue = newOrUpdatedEntity.getProperty("PropertyValue");
            if (newOrUpdatedPropertyValue === customPropertyValue) {
                log.log("Successfully updated '" + customPropertyKey + "' to '" + newOrUpdatedPropertyValue + "'");
            } else {
                log.error("Custom Property failed to update.");
            }
        }
    } else {
        log.log("No existing Custom Property was not found and will be created.");
        newOrUpdatedEntity = System.getModule("com.simplygeek.library.vcac.entities").createvCACEntity(vcacHost,
                                                                                                       entitySetName,
                                                                                                       properties,
                                                                                                       links);
        newOrUpdatedPropertyValue = newOrUpdatedEntity.getProperty("PropertyValue");
        if (newOrUpdatedPropertyValue === customPropertyValue) {
            log.log("Successfully created '" + customPropertyKey + "' with value '" + newOrUpdatedPropertyValue + "'");
        } else {
            log.error("Custom property failed to create.");
        }
    }
} catch (e) {
    log.error("Action failed to add or update custom property.",e);
}

As an example, I would use a wrapper Action that will update the Blueprint name that a virtual machine is assigned to, using the helper action above.

/*global System vcacHost, vcacVmEntity, blueprintName*/

/**
 * Updates the blueprint name that the virtual machine is assigned to.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.1.0
 * @function updateBlueprintNameCustomProperty
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} vcacVmEntity - The virtual machine entity.
 * @param {string} blueprintName - The blueprint name to set.
 */

function checkParams(vcacHost, vcacVmEntity, blueprintName) {
    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 (!blueprintName || typeof blueprintName !== "string") {
        inputErrors.push(" - blueprintName 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 = "updateBlueprintNameCustomProperty"; // 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 providerBindingIdKey = "providerBindingId";
var blueprintIdKey = "VirtualMachine.Cafe.Blueprint.Id";
var blueprintNameKey = "VirtualMachine.Cafe.Blueprint.Name";
var friendlyLabel = "Blueprint Name";

try {
    checkParams(vcacHost, vcacVmEntity, blueprintName);
    log.log("Updating custom properties for " + friendlyLabel);
    System.getModule("com.simplygeek.library.vcac.vm.customproperties").addOrUpdateCustomProperty(vcacHost,
                                                                                                  vcacVmEntity,
                                                                                                  providerBindingIdKey,
                                                                                                  blueprintName);
    System.getModule("com.simplygeek.library.vcac.vm.customproperties").addOrUpdateCustomProperty(vcacHost,
                                                                                                  vcacVmEntity,
                                                                                                  blueprintIdKey,
                                                                                                  blueprintName);
    System.getModule("com.simplygeek.library.vcac.vm.customproperties").addOrUpdateCustomProperty(vcacHost,
                                                                                                  vcacVmEntity,
                                                                                                  blueprintNameKey,
                                                                                                  blueprintName);
    log.log("Successfully updated custom properties for " + friendlyLabel);
} catch (e) {
    log.error("Action failed to update custom properties.",e);
}

Below is what my workflow would look like to update the custom properties to change the blueprint name (not that updating the entities blueprintName property is also required).

Log output:

[] [I] [Action: updateBlueprintNameCustomProperty] Updating custom properties for Blueprint Name
[] [I] [Action: addOrUpdateCustomProperty] Adding or updating custom property 'providerBindingId' with value 'Windows2008'
[] [I] [Action: addOrUpdateCustomProperty] An existing Custom Property was found and will be updated.
[] [D] [Action: updatevCACEntity] Updating vCAC entity...
[] [D] [Action: updatevCACEntity] Updating vCAC entity complete.
[] [I] [Action: addOrUpdateCustomProperty] Successfully updated 'providerBindingId' to 'Windows2008'
[] [I] [Action: addOrUpdateCustomProperty] Adding or updating custom property 'VirtualMachine.Cafe.Blueprint.Id' with value 'Windows2008'
[] [I] [Action: addOrUpdateCustomProperty] An existing Custom Property was found and will be updated.
[] [D] [Action: updatevCACEntity] Updating vCAC entity...
[] [D] [Action: updatevCACEntity] Updating vCAC entity complete.
[] [I] [Action: addOrUpdateCustomProperty] Successfully updated 'VirtualMachine.Cafe.Blueprint.Id' to 'Windows2008'
[] [I] [Action: addOrUpdateCustomProperty] Adding or updating custom property 'VirtualMachine.Cafe.Blueprint.Name' with value 'Windows2008'
[] [I] [Action: addOrUpdateCustomProperty] An existing Custom Property was found and will be updated.
[] [D] [Action: updatevCACEntity] Updating vCAC entity...
[] [D] [Action: updatevCACEntity] Updating vCAC entity complete.
[] [I] [Action: addOrUpdateCustomProperty] Successfully updated 'VirtualMachine.Cafe.Blueprint.Name' to 'Windows2008'
[] [I] [Action: updateBlueprintNameCustomProperty] Successfully updated custom properties for Blueprint Name

I hope this has been useful. If you discover bugs with any of my code, require some help or simply need an ad-hoc solution, then please drop me a message via the Drift app.

5 1 vote
Article Rating

Related Posts

Subscribe
Notify of
guest

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
trackback

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

trackback

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

Kelvin Wong
4 years ago

Do you have any powershell version of the add/update customs properties scripts? I can retrieve custom properties but could not figure out how custom properties can be added or updated.

Sorry for double post, the 1st post has the wrong email

dasMonk
dasMonk
3 years ago

Kudos to you Gavin!
With your thorough guides, explanations and examples I’ve found a way to present a list of storage paths for a reservation on a custom form which populates custom property virtualmachine.disk0.StorageReservationPolicy! Great way to end a week trying to figure it out! :)