Set Mime Type for Resource Element in vRealize Orchestrator

A resource element allows for the use of external objects as attributes in workflows created independently of vRealize Orchestrator. For example, items such as JSON templates.  By importing the external object as a resource element allows for changes to the object and for those changes to be propagated to all workflows that use the resource elements.

When importing the external object as a resource element, the mime type is set from the content of the external object. In some instances, the mime type maybe incorrectly set during the initial import of the external object as a resource. So how do you we update this to be the correct type?

Unfortunately this is not available from vRealize Orchestrator UI, so for my use case I created a module action that will allow for the mime type to updated and set to the correct type. The module action requires for the resource element and the mime type to be specified as input parameters. For a valid list of mime types, refer to Basics of HTTP – Mime Types

// Retrieves the resource element as a mime attachment from the specified input parameter (resourceElement).
var content = resourceElement.getContentAsMimeAttachment();
System.debug('The resource element ' + + ' has been returned with the mime type ' + content.mimeType)
content.mimeType = mime;
// Sets the mime attachement to the type specifed from the input parameter (mime).
System.log('The resource element ' + + ' mime type type has been set to ' + mime)

In this instance I am going to run the workflow that executes the module action, to set an existing resource element that has been previously imported named ‘Test Resource Element.json’ which has the mime type set to ‘application/octect-stream’ to a mime type of ‘text/plain’.

Following successful execution of the workflow, we can confirm that the mime type of the resource element has now been updated to ‘text/plain’ as per the console log output from the mime type of the resource element.

[2017-09-13 17:19:21.130] [D] The resource element Test Resource Element.json has been returned with the mime type application/octet-stream
[2017-09-13 17:19:21.156] [I] The resource element Test Resource Element.json mime type type has been set to text/plain

The package which contains the module action and workflow item is available at com.deangrant.library.vro

Return REST host by name from vRO HTTP-REST Plug-in

The HTTP-REST Plug-in allows for the interaction between vRealize Orchestrator (vRO) and REST hosts by defining services and their operations as inventory objects. When creating a workflow to remove the requirement to specify the REST:RESTHost type object as input parameter, I prefer to discover and return the type object by name this is particularly useful when executing a workflow to which the inventory object is determined by decision logic. The actual name of the inventory object in this example may be enumerated from a resource element or from a call to the configuration management database (CMDB).

The HTTP-REST plug-in exposes Javascript API classes related to REST object management and contains methods related to CRUD operations for REST hosts. In order to return a specified REST:RESTHost from the RESTHostManagerClass, the method ‘getHost(String):RESTHost’ allows for a REST:RESTHost to be returned from the plug-in’s inventory.

The following module action requires the name of the REST:RESTHost object specified as an input parameter. A collection of REST:RESTHost objects will be returned from the RESTHostManager class from the plugin’s inventory and return the REST:RESTHost type object from the associated object identifier as a string, a match will then be performed on the specified name from the input parameter and if true return the REST:RESTHost type.

The package which contains the module action and workflow item is available at

// Returns a collection of REST:RESTHost object types from the inventory service plugin
var getHosts = RESTHostManager.getHosts()
// Iterates the collection to return the REST:RESTHost object type and perform a match on the name attribute provided as an input parameter and returns the REST:RESTHost type if true.
for(var restHostId in getHosts){
var restHost = RESTHostManager.getHost(getHosts[restHostId])
if( == name){
return restHost
} // if( == name)
} // var restHost = RESTHostManager.getHost(getHosts[restHostId])

view raw
hosted with ❤ by GitHub

Identifying orphoned virtual machines and hard disks in vSphere

Connect to the shell of the ESXi host system and browse to location of the datastore (/vmfs/volumes/{datastore name}) to which you want to identity orphoned virtual machine hard disks and invoke the following command. This will return all virtual machine hard disks to which the modified date is seven days in the past (-mtime +7) and return the filename pattern match (find -name “*flat.vmdk*) with the modified date timestamp (-exec stat -c “%n %y” {} \;).

find -iname "*flat.vmdk" -mtime +7 -exec stat -c "%n %y" {} \;

This approach assumes that if the virtual machine hard disk has not been touched in the specified timespan the virtual machine hard disk is orphoned. This may not be accurate, as the virtual machine may be in a powered off state for a period that exceeds the timespan and the virtual machine may be valid. The output should be similar to the below:

./vmfs/volumes/424b26ec-4294ea41/ubuntu-01/ubuntu-01-flat.vmdk 2017-01-29 10:52:03.000000000
./vmfs/volumes/424b26ec-4294ea41/ubuntu-02/ubuntu-02-flat.vmdk 2017-01-29 10:17:46.000000000
./vmfs/volumes/424b26ec-4294ea41/ubuntu03/ubuntu03-flat.vmdk 2017-01-29 11:04:18.000000000
./vmfs/volumes/424b26ec-4294ea41/ubuntu04/ubuntu04-flat.vmdk 2017-01-29 10:17:49.000000000
./vmfs/volumes/424b26ec-4294ea41/ubuntu05/ubuntu05-flat.vmdk 2017-01-29 10:52:03.000000000

An alternative method, is using RVTools which can identify orphoned virtual machines and hard disks (categorised as ‘zombie’) from the inventory scan of a vCenter Server System or ESXi Host System. On completion of the inventory scan, the vHealth tab will display any virtual machines and hard disks identified and may be exported for reference.

Creating new address in a subnet using {php}IPAM REST API

In previous posts I have discussed phpIPAM which is an open-source IP address management application (IPAM). In this blog, I will discuss interacting with the REST API (version 2.0) to programatically create new IP addresses for a specific subnet.

For the purpose of this article, I will be using the Postman REST client to submit requests and interact with the API and the following variables reference values you will need to replace for your environment if you are replicating the process:

Variable Description Example
{appId} API application identifier dean
{subnet} Subnet in CIDR format
{subnetId} Id of subnet address 3

In order to use the API you will need to authenticate (required for none and SSL) with the username and password and use the HTTP authentication header.

If authentication is successful, you will receive the token to include in the token header for subsequent requests to the API. Also, you will receive the expiry of the token which is set to six hours by default. For each subsequent request to the API the expiration time for the token is reset.

POST api/{appId}/user/

By specifying the authorization type as ‘Basic Authentication’ and specifying a username and password this will generate the required Authorization header for the request by encoding the values to a base64 encoded string.


A status code of ‘200’ will be returned if the authentication attempt is successful, the required token value will also be returned in the response body with the expiration date.

  "code": 200,
  "success": true,
  "data": {
    "token": ".Cy9kljLjG=WIt9i.gmA%tUY",
    "expires": "2016-12-03 13:13:06"
  "time": 5.036

Once the token has been received the cool stuff can now begin and we can start to interact with the API. In the next example, I am going to use a common use case for phpIPAM. I need to request the next available free IP address for a specified subnet and allocate this to a host.

So, lets look at the method we need to use to create a new address from a specified subnet from the addresses section of the documentation

POST  /api/{appId}/addresses/first_free/{subnetId}/

An alternative GET method exists, however whilst this will return the next available IP address it will not create the object for the new IP address in the database.

GET /api/{appId}/addresses/first_free/subnet

From the POST method we need to provide the Id of the subnet we require to create an IP address, therefore prior to invoking the request we need to return this value, by referencing the subnets section of the documentation, the following can be used by providing the subnet in CIDR format.

GET /api/{appId}/subnets/cidr/{subnet}/

In this example I am searching for the subnet containing the CIDR format From the below response body we can retrieve the subnet Id from the data[0].id element and in this example, the subnet Id for the subnet is ‘3’. As you can see from the headers section, I am now specifying the ‘token’ header previously returned from the successful authorization.


  "code": 200,
  "success": true,
  "data": [
      "id": "3",
      "subnet": "",
      "mask": "24",
      "sectionId": "1",
      "description": "Customer 1",
      "linked_subnet": null,
      "firewallAddressObject": null,
      "vrfId": "0",
      "masterSubnetId": "2",
      "allowRequests": "1",
      "vlanId": "0",
      "showName": "1",
      "device": "0",
      "permissions": "{\"3\":\"1\",\"2\":\"2\"}",
      "pingSubnet": "0",
      "discoverSubnet": "0",
      "DNSrecursive": "0",
      "DNSrecords": "0",
      "nameserverId": "0",
      "scanAgent": null,
      "isFolder": "0",
      "isFull": "0",
      "tag": "2",
      "threshold": "0",
      "location": null,
      "editDate": null,
      "links": [
          "rel": "self",
          "href": "/api/dean/subnets/3/"
  "time": 0.002

Now, lets return to creating a new address in the specified subnet with the below request to create a new address in the subnet from the POST method. From the response body, the data element contains the IP address ‘’ created for the subnet.

POST  /api/{appId}/addresses/first_free/3/


  "code": 201,
  "success": true,
  "message": "Address created",
  "id": "34",
  "data": "",
  "time": 0.015

We can also include a request body in the POST method to include information for creating the new IP address in the subnet. The supported parameters are listed for the address controller in the addresses section. In this example, I have included the hostname, description and owner values for the request.


As you can see if you have read the provided API documentation, I am only touching the surface of what is possible by programmatically interacting with the API and how you can leverage this in your automation and orchestration practices.

Getting started with DevStack as OpenStack playground environment on Ubuntu

I was recently looking to deploy a minimal installation of OpenStack to use as a development environment and to minimise the complexity of installing a complete OpenStack environment where I can build and tear down the environment with minimal effort. This is where DevStack comes into play, as to quote:

DevStack is a series of extensible scripts used to quickly bring up a complete OpenStack environment based on the latest versions of everything from git master. It is used interactively as a development environment and as the basis for much of the OpenStack project’s functional testing.

For my minimal installation of DevStack I am using new installation of Ubuntu Server 16.10 (clean installation and isolated instance recommended due to significant changes to the system). In terms of hardware configuration, the following recommendations are provided. However, this will all be dependant on your use case for DevStack and what you require to achieve and DevStack may also be installed without satisfying the below criteria but you may experience performance/stability issues.

  • Processor – at least 2 cores
  • Memory – at least 8GB
  • Hard Drive – at least 60GB

First of all we will create a user account named ‘stack’ to install DevStack and grant the user sudo privileges with the no password parameter. It is important in this step that we do not complete the installation as the root user.

sudo adduser stack 
echo "stack ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

Now log out as the current user and reconnect as the ‘stack’ user created in the previous step and clone the repository to the current directory, in this example i am changing the directory to ‘/var’ to create my local copy.

cd /var 
sudo git clone git://

We will now need to create a configuration file (/var/local.conf) to specify user configuration variables to use when the installation script (/var/devstack/ is executed in a subsequent step. The installation will complete without

The below example, contains only password variables so that you are not required to input the values at installation. For a more detailed configuration file containing additional parameters, check out the sample from the respoistory.

cd /var/devstack
sudo vi local.conf 

Once the configuration file has been created, we can now execute the installation script ( The installation process will take approximately 15-20 minutes to complete to which will receive console output. Once the installation has completed you will receive an installation summary, URLs, accounts and passwords.


Once the installation has completed successfully you should be able to browse to the Horizon dashboard and authenticate with the admin credentials configured during installation, at http://{ip address}/dashboard.


If you need to remove the installation of DevStack there is a script included in the repository (./ which will remove the installation of DevStack and dependancies and then cleanup the directories touched by the installation. For a detailed list of impacted files and directories during the installation refer to this link.

cd /var/devstack
rm -rf /opt/stack
rm -rf /usr/local/bin

From my initial attempt at installation, I encountered a number of issues which appear to be permission related I believe this was due to not cloning the repository as the ‘stack’ user account used for the installation. In this case, to resolve you could run the below or alternatively clean-up your installation process and repeat the installation.

sudo chown -R stack:stack /var/devstack 
sudo chmod 770 /var/devstack