Executing a vRO action via REST API

The ability to execute a vRO workflow or action via API is useful if you are using vRA or vRO as part of an overall CI/CD pipeline. If a vRA catalog item uses vRO actions to filter or set values on a custom form how can this be done if the vRA catalog item will be requested via REST.

In the example below I have a simple action that takes two inputs:

  • firstName – Type:String
  • secondName – Type:String

In order to be able to execute a vRO action you need to submit basic auth credentials. This will require the user account to be a member of the vco-admins group in vRO. This can either be a local user or an Active Directory user if vRA has been configured to integrate with Active Directory

The process for being able to execute the action via REST is a three part step. Part 1 is to determine the ID of the action that you wish to call. Execute the following operation:

GET - https://vro-fqdn/vco/api/actions

The result will be a large array of actions that looks something like this:

{
     "link": [
         {
             "attributes": [
                 {
                     "value": "d7e461f6-b88f-4f63-a2cc-7f3c76d1bd19",
                     "name": "id"
                 },
                 {
                     "value": "isBlocking",
                     "name": "name"
                 },
                 {
                     "name": "description"
                 },
                 {
                     "value": "com.vmware.library.vcaccafe.workflow.subscription/isBlocking",
                     "name": "fqn"
                 },
                 {
                     "value": "0.0.0",
                     "name": "version"
                 }
             ],
             .......

You’ll need to process this array to search for the name of the action that you wish to execute.

Part 2 is to retrieve the inputs for the action which is achieved via the following REST operation:

GET - https://vro-fqdn/vco/api/actions/{actionid}

The result will look something like this:

{

    "href": "https://192.168.1.26:443/vco/api/actions/278a1622-1924-4f37-bb24-0c5d36346ae9/",
    "relations": {
        "link": [
            {
                "href": "https://192.168.1.26:443/vco/api/actions/com.cloudkindergarten.examples/executedByApi/",
                "rel": "alternate"
            },
            {
                "href": "https://192.168.1.26:443/vco/api/actions/278a1622-1924-4f37-bb24-0c5d36346ae9/permissions/",
                "rel": "permissions"
            },
            {
                "href": "https://192.168.1.26:443/vco/api/actions/278a1622-1924-4f37-bb24-0c5d36346ae9/executions/",
                "rel": "executions"
            }
        ]
    },
    "id": "278a1622-1924-4f37-bb24-0c5d36346ae9",
    "output-type": "string",
    "name": "executedByApi",
    "description": "",
    "version": "0.0.0",
    "fqn": "com.cloudkindergarten.examples/executedByApi",
    "script": "var fullName = (firstName + \" \" + secondName);\nreturn fullName;",
    "input-parameters": [
        {
            "description": "",
            "type": "string",
            "name": "firstName"
        },
        {
            "description": "",
            "type": "string",
            "name": "secondName"
        }
    ]
}

From this we can see that action is expecting two input parameters; firstName and secondName both of type string.

Part 3 is to execute this action. We do this by using the following body content

{"parameters":
 [
  {
   "value": {"string":{ "value": "Andy"}},
   "type": "string",
   "name": "firstName",
   "scope": "local"
  },
  {
   "value":{"string":{"value": "Davies"}},
   "type": "string",
   "name": "secondName",
   "scope": "local"
  }
 ]
}

This is then executed with the REST Operation:

POST https://{vro-fqdn}/vco/api/actions/{actionid}/executions/

The response will hopefully be the returned value from the action. In this case the full name of the person:

{
    "value": {
        "string": {
            "value": "Andy Davies"
        }
    },
    "type": "string"
}

Integrating vROps with vRO using webhook shim

Introduction

In an ideal world, running custom vRO workflows as a result of a triggered alert in vROps would be either an out of the box feature or (easily) possible via a vROps management pack.

There have been two incarnations of a vRO management pack for vROps and neither has provided this, the first incarnation did, with a lot of manual changes to the vROps adapter file allow this, and from an initial inspection of the latest vRO management pack this would also be possible – perhaps the subject of another blog post!

So, in the absence of such a (perfect) solution the good news is that there is a solution to the challenge, and there have already been a number of blog posts written on this subject, both from VMware staff and externally. Whilst working with a customer I found that none of these resources captured all of the steps in a single succinct post, that didn’t assume any previous knowledge.

The solution

A couple of years back, John Dias and Steve Flanders wrote a web hook shim that enabled vROps and vRLI to interact not just with vRO but with a number of different endpoints. The web hook shim is a small python application that listens for requests from vROps or vRLI and translates those requests into something that the intended endpoint can understand.

Install Photon OS

As VMware has their  own Linux distribution, this is what I have used for this blog post, especially as it works really well as a container host. There are lots of articles on how to get an instance of Photon OS up and running quickly:

https://vmware.github.io/photon/

The easiest method is to use the OVA image. Although you should note that there has been an issue with the hardware version 13 image, as outlined on William Lam’s blog:

https://www.virtuallyghetto.com/2017/11/workarounds-for-deploying-photonos-2-0-on-vsphere-fusion-workstation.html

Configure Network Settings

Whilst you could leave the VM to use DHCP for network addressing, you’ll most likely want to configure a static IP address. Details on how to do this can be found in the photon OS administration guide:

https://github.com/vmware/photon/blob/master/docs/photon-admin-guide.md#managing-the-network-configuration

I ended up with a network configuration file as shown below:

Screen Shot 2018-07-28 at 13.02.23

Once the networking configuration has been set, run the following command to restart the network daemon:

systemctl restart systemd-networkd

Run the following command to validate that the IP address information has been set correctly

ip a

The result should be something similar to that shown below

Screen Shot 2018-07-28 at 13.07.13

Configure Hostname

To set the hostname of the appliance run the following command:

hostnamectl set-hostname abc

To check that is has been set correctly run the following command:

hostnamectl

The result should be something similar to that shown below:

Screen Shot 2018-07-28 at 13.13.01

Configure Docker

We will be running the web hook shim as a Docker container. Docker is already installed within the Photon OS image, but it is does not configured to run by default. Docker also needs to be configured to start automatically

Start Docker

Start Docker by running the following command:

systemctl start docker

Set Docker to start automatically

Set Docker to start automatically during system start by running the following command:

systemctl enable docker

Start the web hook shim

The web hook shim is available on Docker Hub, so as long as the appliance can access the internet then getting it running is a simple process. Before we can get the link between vROps and vRO working we need to do some configuration of the web hook shim. Run the following command to start the Docker container

docker run -it -p 5001:5001 --name {yourchoice} vmware/webhook-shims bash

This command runs the container interactively, sets the ports that the container will respond on, gives it a memorable name, pulls the container image from Docker hub and provides a bash shell to allow shell access within the container

To check the status of the the container run the following command:

docker ps -a

This will have an output similar to the following:

Screen Shot 2018-07-28 at 13.23.04

Configure the web hook shim

Attach to the container by running the following command:

docker attach vmwareshim

The various translation files for the different endpoints are in a directory called ‘loginsightwebhookdemo’:

cd loginsightwebhookdemo
vi vrealizeowchestrator.py

The first element to change is the hostname of the vRO endpoint to which alert notifications will be sent:

VROHOSTNAME = 'vrohostname'

If running an instance of vRO from a vRA appliance there is no need to include port information. If running the standalone version of vRO then you will need to include port 8281 in this section for example:

VROHOSTNAME = 'myvroserver.mydomain.local:8281'

Information around the various means of authentication can be found within the vrealizeowchestrator.py file. Amend the various components as necessary to achieve the desired authentication mechanism:

USENETRC = True
VROUSER = ''
VROPASS = ''
VROTOKEN = ''
VROHOK = ''

If running in an environment without trusted certificates, the following line needs to be set so that certificate checks are disabled:

VERIFY = False

The shim currently has an issue whereby two instances of the workflow are executed for each alert that is triggered. To fix this issue edit the vrealizeorchestrator.py file and alter the following line:

@app.route("/endpoint/vro/", methods=['PUT', 'POST'])

To:

@app.route("/endpoint/vro/", methods=['POST'])

Save the file and then exit vi.

Using .netrc credentials

Prior to configuring the web hook shim, if .netrc credentials are going to be used it is easier to configure these now, instead of having to exit the shim, creating the credentials and then re-attaching

To use netrc credentials, run the following commands:

cd ~
echo 'machine {vro-host-or-ip} login {vro-login-name} password {vro-password}' > .netrc
chmod 600 .netrc

Start the web hook shim

Once all of the configuration has been done it is time to start the web hook shim:

cd ..
./runserver.py

A couple of information messages will be displayed. To validate that the web hook shim is operating, open a web browser and enter the address as:

webhooksshimiporhostname:5001

You should see the following returned

Screen Shot 2018-07-28 at 13.47.11

Useful commands

To stop the web hook shim enter the following command:

CTRL-C

You can restart the web hook shim later via this command:

./runserver.py

To detach from the Docker container, whilst leaving the web hook shim running, use the following command:

CTRL-P, CTRL-Q

Setup the master workflow in vRO

Before vROps can be configured we need a workflow that will receive the alerts generated. In John Dias’s series of posts he discusses a vRO workflow package that can be imported and used to test the functionality. That package can be found at the following location:

https://github.com/vmw-loginsight/webhook-shims/tree/master/samples

When configuring vROps we are going to specify the ID of a workflow that will be run. This workflow needs to have a single input called ‘alertId’ with a type of ‘string’. For the purposes of this blog post I’m going to keep things really simple and merely prove the ability to run a workflow based on a vROps alert. As a result my workflow is really basic, it has a single input and just outputs that alert to the system log.

The ID of the workflow can be found on its general tab, under ID. Copy this and save it for later.

Screen Shot 2018-07-28 at 14.05.03

vROps configuration

At a high level the configuration steps within vROps consist of the following:

  1. Setup an outbound instance
  2. Configure notification settings
  3. Setup a test alert

Setup an outbound instance

The first step is to create the outbound instance using the OOTB Rest Notification Plugin. You get to the notification settings via the following sequence:

Administration > Management > Notification Settings

Configure the outbound plugin with the following parameters:

Parameter Value
Plugin Type Rest Notification Plugin
Instance Name vmwareshim
Endpoint http://webhookshimip:5001/endpoint/vro/workflowId
Username none
Password none (but you must put something in this box)
Content Type application/json
Certificate Thumbprint none
Connection Timeout 20

To validate the settings, press the test button. The test will fail within vROps with the following error displayed:

Screen Shot 2018-07-28 at 14.19.50

However, you will be able to see that integration is working by looking within the photon OS appliance. If you have an SSH session open and you’re attached to the web hook shim container then you should see the following log output:

screen-shot-2018-07-28-at-14-22-00.png

You can also check within vRO, where there should be a an execution of the workflow specified

Screen Shot 2018-07-28 at 14.40.53

Configure notification settings

vROps can be configured to send notifications to multiple targets and use advanced filtering to determine where different alerts should be sent. For the purposes of this blog post I am going to configure a notification rule to send all alerts to vRO via the web hook shim. Configure the rule by navigating to the following page:

Alerts > Alert Settings > Notification Settings

The rule should look like the following image:

Screen Shot 2018-07-28 at 14.50.29

Setup a test alert

The final step is to have an alert triggered. If you’re performing this in an environment with active ESXi hosts / Virtual Machines, then the likelihood is that you will get alerts triggered anyway. If you are just testing this in a lab, configure an alert with symptoms that have such low thresholds that they will inevitably get triggered.

Screen Shot 2018-07-28 at 14.57.10

Once the alert has been triggered you should be able to see successful executions of your workflow in vRO. In my case I’m just logging the alertId but that is all that you need to be able to extract a lot of information – although there will be multiple REST calls required to vROps in order to get that information.

John Dias included some initial steps that could be used to retrieve information about the affected object. The basic flow is as follows:

  • alertID – retrieving the alert from vROps will also return the alertDefinitionId and the resourceId of the affected object
  • resourceId – can be used to retrieve the name of the object, properties of the object, related object, triggered symptoms
  • alertDefinitionId – can be used to find out more prescriptive information about the alert definition itself and can be used to match the symptoms of the alert definition to the triggered symptoms on the resource

Additional Resources

There are a large number of blog posts around this subject, which may provide additional information and/or context:

https://blogs.vmware.com/management/2017/03/webhook-shims-now-available-on-docker-hub.html

https://blogs.vmware.com/management/2017/02/self-healing-datacenter.html

https://blogs.vmware.com/management/2017/01/vrealize-webhooks-infinite-integrations.html?src=so_5703fb3d92c20&cid=70134000001M5td

vRealize Orchestrator: Get VM by Name in Large environments

The Challenge

In very large environments, the standard (out of the box methods) of retrieving a specific  virtual machine object by name in vRealize Orchestrator are not particularly efficient and can take a long time to retrieve a particular object. This is of particular concern when using a vRO action to retrieve an external value in a vRA XaaS form. The default timeout for value retrieval is 30 seconds, and although this can be extended (see https://kb.vmware.com/s/article/2144872), the aim should be to retrieve all values in the fastest time possible as opposed to increasing the timeout to a large value.

So, the challenge was set, design a method of retrieval of any VM object within the vRA timeout.

The Options

Out of the box, vRO provides a method of retrieving all virtual machine:

allVMs = VcPlugin.getAllVirtualMachines()

This can be looped through until a specific virtual machine name is found. In small environments this method is absolutely fine as the response time will not be an issue

This can be extended (and made faster) either via including a name:

allVMs = VcPlugin.getAllVirtualMachines(null, vmname)

or by using xpath:

allVMs = VcPlugin.getAllVirtualMachines(null, "xpath:name=\'" + vmname + "\'")

The latter method has issues with case sensitive queries, and using an xpath translation is really slow!

In the environment I was working the former query took many minutes to return data, the latter two took between 45-60 seconds, which was much better, but not quick enough to return the VM object to vRA in less than 30 seconds which was the ultimate goal.

So an alternative solution had to be found…

The Solution

The aim was to get to a situation whereby the smallest possible number of VMs could be retrieved by vRO, which could then be used to search for the exact VM object. In this way the query made to vCenter is much smaller, resulting in a significantly faster response time. Although this information can itself be queried from vCenter, in environments with more than one vCenter this would still be an iterative process which may result in lengthy delays in returning information.

GetVMbyNameviavROps

Fortunately there is a database in many vSphere environments that contains a combined view of the world; vRealize Operations Manager. Each virtual machine object has a number of properties that allow the parent objects of the virtual machine to be readily identified:

  • summary|parentCluster
  • summary|parentHost

vROps also has an API that can be used to retrieve these properties once the internal vROps ID of the object has been determined. The API calls used are:

  • https://hostname/suite-api/api/resources?name&resourceKind=virtualmachine –  the object identifier is included in the response
  • https://hostname/suite-api/api/resource/objectid/properties – the response is queried for the value of the specified property

Unfortunately this only gets us half way. Although we now have the cluster and host that the virtual machine is running on, we need to convert those names into objects that vRO can use.

To speed things up, a cache was created that contains all of the vSphere Clusters in the various vCenter environments. This cache is queried to match the name of the cluster to the cluster object. The cache is updated via a scheduled workflow.

The host object is now retrieved by querying the hosts in the cluster looking for a match for the host retrieved from vROps. This part could be skipped altogether by using a cache containing all ESXi hosts. This was not done in the environment I was working in as the number of hosts would have been very large (> 5000) and the impact of having that many attributes in a configuration element was felt to be excessive.

The final stage is to match the virtual machines of the identified host with the name originally entered. The result is the virtual machine object.

The vRO Package

The package below includes all of the elements needed. Once the package has been imported there is a little bit of configuration that needs to be done:

  1. Add vROps host(s) as REST endpoints (Library > Configuration > Add a REST host). The name given to the REST host will be the one used in the ‘Get VM by Name via vROps’ workflow that can be used to test the action. Use basic authentication and configure certificate handling as appropriate
  2. Edit the resource configuration ‘GetVMbyName/vROpsHosts’. Edit the ‘vROpsHosts’ attribute and add each configured vROps host into the arrayScreen Shot 2018-05-01 at 20.45.25
  3. Edit the resource configuration ‘GetVMbyName/allVCSDKConnections’. Edit the ‘vcSDKConnections’ attribute and add each vCenter SDK connection as appropriateScreen Shot 2018-05-01 at 20.46.47
  4. Run the ‘Create Cluster Cache’ workflow and then validate that the ‘GetVMyName/ClusterCache’ resource configuration has all expected clustersScreen Shot 2018-05-01 at 20.50.01

The ‘Get VM by Name via vROps’ workflow can now be run. Enter the name of the virtual machine to search for and the name of the vROps host to use

Screen Shot 2018-05-01 at 20.55.15

The output can be viewed either via the log:

Screen Shot 2018-05-01 at 20.56.21

Or by viewing the variables. A positive result will include a virtual machine object in the ‘vm’ variable

Screen Shot 2018-05-01 at 20.58.30

The test workflow requires a REST host name to be inputted, although this could set via a field on a vRA form, or additional code written to choose the REST host based on some condition.

Download Package:

GetVMbyNameviavROps

Using PowervROps cmdlets (part 3) – Adding metrics and properties to objects

Introduction

In the third part in this series of blog posts we are going to use the cmdlets to add metrics and properties to various objects, these metrics and properties can be used in exactly the same way as those from management packs, although you should be aware that metrics age and are not available on dashboards or for use in super metric calculations after a period of time. For dashboards this appears to be roughly four hours and for super metrics this is after 48 hours.

The functions

There are three functions available within PowervROps for adding properties and metrics:

  1. addProperties
  2. addStats
  3. addStatsforResources

The first and second functions enable properties and stats (metrics) to be added to a single vROps object (multiple properties and metrics can be added in a single command). The third command allows metrics to be added to multiple objects in a single command, which is much more efficient in large environments, although there is a limit of 1000 objects in a single execution. There is no comparable API method to add properties to multiple objects via a single command.

How to use

As discussed in part 1 of this blog series, before any cmdlets can be run a means of authentication needs to be configured. As with previous blog posts the examples shown will use token based authentication, although credentials based is perfectly fine. In all examples shown a variable of $token will be used.

All three functions require body content to be submitted along with the command. The functions will accept both JSON and XML (as the vROps API accepts both). For the purposes of this blog JSON will be used throughout. More information can be found about different request examples via the vROps API document (https://vropsfqdn/suite-api/docs/rest/index.html). The functions within PowervROps match the name shown in the documentation so should be easy to locate.

The addProperties and addStats functions also require an objectid to be submitted along with the request. Examples are shown in part 1 of this blog series

Examples

addProperties

In this example we are going to add a property called ‘CloudKindergarten|Demo|DevicePurpose’ with a value of ‘Active Directory Domain Controller’ to the virtual machine ‘vm-a’

import-module c:\users\taguser\documents\github\powervrops\powervrops.psm1
$resthost = 'vrops-01a.cloudkindergarten.local'
$token = acquiretoken -resthost $resthost -username admin -password VMware1! -authsource local
$object = getresources -resthost $resthost -token $token -name 'vm-a' -resourceKind 'VirtualMachine'
$body = @{
 'property-content' = @( @{
 'statKey' = 'CloudKindergarten|Demo|DevicePurpose'
 'timestamps' = @(getTimeSinceEpoch)
 'values' = @('Active Directory Domain Controller')
 'others' = @()
 'otherAttributes' = @{}
 }
 )
}
addProperties -resthost $resthost -token $token -objectid $object.resourcelist.identifier -body ($body | convertto-json -depth 5) -contenttype 'json'

This example shows a JSON body content. If the body was in XML format then the addProperties command would be altered as below:

addProperties -resthost $resthost -token $token -objectid $object.resourcelist.identifier -body ($body | convertto-json -depth 5) -contenttype 'xml'

We can see below that the property is displayed in the All Metrics page and can be selected in the same way as any other property:

Screen Shot 2018-01-30 at 13.22.34

We can also retrieve this property using the getResourceProperties function:

import-module c:\users\taguser\documents\github\powervrops\powervrops.psm1
$resthost = 'vrops-01a.cloudkindergarten.local'
$token = acquiretoken -resthost $resthost -username admin -password VMware1! -authsource local
$object = getresources -resthost $resthost -token $token -name 'vm-a' -resourceKind 'VirtualMachine'
$resourceproperties = (getresourceproperties -resthost $resthost -token $token -objectid $object.resourcelist.identifier).property | where { $_.name -eq 'CloudKindergarten|Demo|DevicePurpose'}
$resourceproperties

This returns the following:

Screen Shot 2018-01-30 at 13.40.48

addStats

The second example shows adding a single metric to a virtual machine. The metric name is ‘CloudKindergarten|Demo|SingleMetricOne and a random value of between 1 and 100  will be added. The code includes an additional unnecessary line that generates the random number, and this variable is used within the JSON body.

import-module c:\users\taguser\documents\github\powervrops\powervrops.psm1
$resthost = 'vrops-01a.cloudkindergarten.local'
$token = acquiretoken -resthost $resthost -username admin -password VMware1! -authsource local
$object = getresources -resthost $resthost -token $token -name 'vm-b' -resourceKind 'VirtualMachine'
$metricvalue = get-random -Minimum 1 -Maximum 100
$body = @{
'stat-content' = @( @{
'statKey' = 'CloudKindergarten|Demo|SingleMetricOne'
'timestamps' = @(getTimeSinceEpoch)
'data' = @($metricvalue)
'others' = @()
'otherAttributes' = @{}
}
)
}
addStats -token $token -resthost $resthost -objectid $object.resourcelist.identifier -body ($body | convertto-json -depth 5) -contenttype json

In the image below the results of running the command many times in a short space are shown.

Screen Shot 2018-01-30 at 15.56.27

When running this command, it is not limited to single metric, nor a single data point. In the example below values for two different metrics are being added for datapoints at five minute intervals for the last hour.

import-module c:\users\taguser\documents\github\powervrops\powervrops.psm1import-module c:\users\taguser\documents\github\powervrops\powervrops.psm1
$resthost = 'vrops-01a.cloudkindergarten.local'
$token = acquiretoken -resthost $resthost -username admin -password VMware1! -authsource local
$object = getresources -resthost $resthost -token $token -name 'vm-c' -resourceKind 'VirtualMachine'
$metricvaluesone = @()
$metricvaluestwo = @()
$timestamps = @()
for ($i = 0;$i -lt 12;$i++) {
$metricvaluesone += (get-random -Minimum 1 -Maximum 100)
$metricvaluestwo += (get-random -Minimum 1 -Maximum 100)
$timestamps += gettimesinceepoch -date (get-date).AddMinutes(($i*-5))}
$body = @{
'stat-content' = @( @{
'statKey' = 'CloudKindergarten|Demo|SingleMetricOne'
'timestamps' = $timestamps
'data' = $metricvaluesone
'others' = @()
'otherAttributes' = @{}
}
@{
'statKey' = 'CloudKindergarten|Demo|SingleMetricTwo'
'timestamps' = $timestamps
'data' = $metricvaluestwo
'others' = @()
'otherAttributes' = @{}
}
)
}
addStats -token $token -resthost $resthost -objectid $object.resourcelist.identifier -body ($body | convertto-json -depth 5) -contenttype json

The results can be seen in the image below

Screen Shot 2018-01-30 at 16.33.39.png

addStatsforResources

In the last example multiple metrics are going to be added to multiple VMs. Specifically the following metrics are going to be added:

  • CloudKindergarten|Demo|MultiMetricOne – with a random value between 1 and 100
  • CloudKindergarten|Demo|MultiMetricTwo – with a random value between 1 and 100
  • CloudKindergarten|Demo|MultiMetricThree – with a random value between 1 and 100

These metrics are going to be added to the following VMs:

  • vm-a
  • vm-b
  • vm-c
  • vm-d
  • vm-e
    import-module c:\users\taguser\documents\github\powervrops\powervrops.psm1
    $resthost = 'vrops-01a.cloudkindergarten.local'
    $token = acquiretoken -resthost $resthost -username admin -password VMware1! -authsource local
    $metrictime = getTimeSinceEpoch
    $allvms = @('vm-a','vm-b','vm-c','vm-d','vm-e')
    $allvmstatcontent = @()
    foreach ($vm in $allvms) {
    $object = getresources -resthost $resthost -token $token -name $vm -resourceKind 'VirtualMachine'
    $statcontent = @()
    $statcontent += (@{statKey='CloudKindergarten|Demo|MultiMetricOne';timestamps=@($metrictime);data=@((get-random -Minimum 1 -Maximum 100));others=@();otherAttributes=@{};}) 
    $statcontent += (@{statKey='CloudKindergarten|Demo|MultiMetricTwo';timestamps=@($metrictime);data=@((get-random -Minimum 1 -Maximum 100));others=@();otherAttributes=@{};})
    $statcontent += (@{statKey='CloudKindergarten|Demo|MultiMetricThree';timestamps=@($metrictime);data=@((get-random -Minimum 1 -Maximum 100));others=@();otherAttributes=@{};})
    $vmstatdetail = @{
     'id' = $object.resourcelist.identifier
     'stat-contents' = $statcontent
    }
    
    $allvmstatcontent += $vmstatdetail
    
    }
    $vmstatcontent = @{
     'resource-stat-content' = $allvmstatcontent
     }
    
    addstatsforresources -resthost $resthost -token $token -body ($vmstatcontent | convertto-json -depth 10)

The outcome of this can be seen via a view in vROps

Screen Shot 2018-01-30 at 17.00.20

As with the addStats function, multiple data points can be added with the addstatsforresources function:

import-module c:\users\taguser\documents\github\powervrops\powervrops.psm1
$resthost = 'vrops-01a.cloudkindergarten.local'
$token = acquiretoken -resthost $resthost -username admin -password VMware1! -authsource local
$allvms = @('vm-a','vm-b','vm-c','vm-d','vm-e')
$allvmstatcontent = @()
foreach ($vm in $allvms) {
$object = getresources -resthost $resthost -token $token -name $vm -resourceKind 'VirtualMachine'
$metricvaluesone = @()
$metricvaluestwo = @()
$metricvaluesthree = @()
$timestamps = @()
for ($i = 0;$i -lt 12;$i++) {
$metricvaluesone += (get-random -Minimum 1 -Maximum 100)
$metricvaluestwo += (get-random -Minimum 1 -Maximum 100)
$metricvaluesthree += (get-random -Minimum 1 -Maximum 100)
$timestamps += gettimesinceepoch -date (get-date).AddMinutes(($i*-5))}
$statcontent = @()
$statcontent += (@{statKey='CloudKindergarten|Demo|MultiMetricOne';timestamps=$timestamps;data=$metricvaluesone;others=@();otherAttributes=@{};})
$statcontent += (@{statKey='CloudKindergarten|Demo|MultiMetricTwo';timestamps=$timestamps;data=$metricvaluestwo;others=@();otherAttributes=@{};})
$statcontent += (@{statKey='CloudKindergarten|Demo|MultiMetricThree';timestamps=$timestamps;data=$metricvaluesthree;others=@();otherAttributes=@{};})
$vmstatdetail = @{ 'id' = $object.resourcelist.identifier 'stat-contents' = $statcontent}
$allvmstatcontent += $vmstatdetail}
$vmstatcontent = @{ 'resource-stat-content' = $allvmstatcontent }
addstatsforresources -resthost $resthost -token $token -body ($vmstatcontent | convertto-json -depth 10)

The results can be seen for the three metrics on three different virtual machines:

Screen Shot 2018-01-30 at 19.39.19

All posts in this series:

Using PowervROps cmdlets (part 1) – Introduction

Using PowervROps cmdlets (part 2) – Retrieving metrics from objects

Using PowervROps cmdlets (part 3) – Adding metrics and properties to objects

Using PowervROps cmdlets (part 4) – Working with objects

Using PowervROps cmdlets (part 5) – Working with relationships

Using PowervROps cmdlets (part 6) – Working with custom groups

Using PowervROps cmdlets (part 7) – Working with supermetrics

Using PowervROps cmdlets (part 8) – Working with reports

Using PowervROps cmdlets (part 9) – Working with alerts

 

Using PowervROps cmdlets (part 2) – Retrieving metrics from objects

Introduction

This is the second in a series of posts about PowervROps and the available functions. This post will focus on the ability to query metric data from objects in vROps. Two functions are available to query the stats held for resources:

  • getLatestStatsofResources
  • getStatsForResources

The former returns just the latest value for the given resource IDs and metrics, whilst the latter allows a large degree of customisation over the time frame of metrics and rollup of data e.g. averages or maximums within specified time frames

getLatestStatsofResources

This is the simpler of the two functions available, but as a consequence only returns the latest data point for each metric. The example below shows the value for the metric ‘mem|guest_demand’ for the VM ‘esxi-04a’

import-module c:\users\taguser\documents\github\powervrops\powervrops.psm1
$resthost = 'vrops-01a.cloudkindergarten.local'
$token = acquiretoken -resthost $resthost -username admin -password VMware1! -authsource local
$object = getresources -resthost $resthost -token $token -resourceKind 'VirtualMachine' -name 'esxi-04a'
$stats = getLatestStatsofResources -resthost $resthost -token $token -objectid $object.resourceList.identifier -statkey 'mem|guest_demand'
$stats.values.'stat-list'.stat

The output of this script is as follows:

Screen Shot 2018-01-30 at 21.38.28

getStatsForResources

The getStatsForResources function can return a vast amount of data and perform transformation of that data in a similar manner available within vROps views. The function requires a body element that contains the query parameters.

The example below queries all virtual machines for a single metric; mem|guest_demand. The data returned in this example returns all data at five minute intervals for the last hour

import-module c:\users\taguser\documents\github\powervrops\powervrops.psm1
$resthost = 'vrops-01a.cloudkindergarten.local'
$token = acquiretoken -resthost $resthost -username admin -password VMware1! -authsource local
$allvms = getresources -resthost $resthost -token $token -resourceKind 'VirtualMachine'
$resourcelist = @()
$metricstoquery = @('mem|guest_demand')
foreach ($vm in $allvms) {
$resourcelist += $vm.resourcelist.identifier
}
$body = @{
'resourceId' = $resourcelist
'statKey' = $metricstoquery
'begin' = (getTimeSinceEpoch -date ((get-date).AddHours(-1)))
'end' = (getTimeSinceEpoch)
'rollUpType' = 'LATEST'
'intervalType' = 'MINUTES'
'intervalQuantifier' = 5
'dt' = $false
'latestMaxSmaples' = 1
} | convertto-json -depth 10
$statsofresources = getStatsForResources -resthost $resthost -token $token -body $body
foreach ($statentry in $statsofresources.values) {
write-host ''
write-host ("Virtual Machine: " + ($allvms.resourceList | where { $_.identifier -eq $statentry.resourceid }).resourcekey.name)
foreach ($stat in $statentry.'stat-list') {
write-host ('Metric: ' + $stat.stat.statkey.key)
for ($i=0;$i -lt $stat.stat.timestamps.count;$i++) {
write-host (((Get-Date '1/1/1970').AddMilliseconds($stat.stat.timestamps[$i])).datetime + ' | ' + $stat.stat.data[$i])
}
}
}

The example above outputs the data to the powershell session, but in practice once the data has been returned then it can be used in any way.

Screen Shot 2018-01-30 at 20.49.20

The data held in vROps can be queried and returned in a number of different ways. The relevant elements to modify are as follows:

'resourceId' = $resourcelist

An array of vROps identifiers

'statKey' = $metricstoquery

An array of metrics to query

'begin' = (getTimeSinceEpoch -date ((get-date).AddDays(-7)))
'end' = (getTimeSinceEpoch)

The start and end times for the queried data. In the example above all data from the current time and for the last seven days will be queried.

'rollUpType' = 'LATEST'

How the data will be transformed. Available options are as follows:

SUM – The sum of all datapoints in each interval period
AVG – The average of the datapoints in each interval period

Screen Shot 2018-01-30 at 21.19.13
MIN – The minimum value of the datapoints in each interval period
MAX – The maximum value of the datapoints in each interval period

Screen Shot 2018-01-30 at 21.20.17
LATEST – The most recent sample of the datapoints in each interval period (see the example for interval type below to better describe the data that will be returned)
COUNT – The number of samples within each interval period

Screen Shot 2018-01-30 at 21.18.24

Take care when using a large time frame with a small interval type and a large number of metrics and resources as it can take a long time for the data to be returned

'intervalType' = 'MINUTES'
'intervalQuantifier' = 5

The time interval between data points. Note that if using any interval period beyond hours then the values returned will have time stamps of the last second of each hour. They will not be for hour points directly preceding the time at which the query is executed. An example of this is shown below:

Screen Shot 2018-01-30 at 21.15.09

In this example, the data point for 21:59:59 is the last data point in the hour between 21:00:00 and 21:59:59 which in this case is actually 9:09:13 – the query was run at approximately 21:14:00. The data point for 20:59:59 is the last value between 20:00:00 and 21:59:59 which was actually at 21:59:13

Using PowervROps cmdlets (part 1) – Introduction

Using PowervROps cmdlets (part 2) – Retrieving metrics from objects

Using PowervROps cmdlets (part 3) – Adding metrics and properties to objects

Using PowervROps cmdlets (part 4) – Working with objects

Using PowervROps cmdlets (part 5) – Working with relationships

Using PowervROps cmdlets (part 6) – Working with custom groups

Using PowervROps cmdlets (part 7) – Working with supermetrics

Using PowervROps cmdlets (part 8) – Working with reports

Using PowervROps cmdlets (part 9) – Working with alerts

Using the PowervROps Cmdlets (Part 1) – Introduction

This is the first in a multi part series on how the cmdlets within the PowervROps module (https://github.com/andydvmware/PowervROps) can be used, and gives specific examples for use.

Loading the module

The first thing that needs to be done prior to using the module is to load it into the current PowerShell session. This can be accomplished by running the following command:

import-module <path-to-module>\powervrops.psm1

To list all of the available commands within the module issue the get-command cmdlet:

get-command -module powervrops

Screen Shot 2017-08-21 at 14.32.07

As with all PowerShell cmdlets the get-help cmdlet can be run to return information about a specific one:

get-help addStats -detailed

Authentication

Before any meaningful commands can be executed against vROps we must have a mechanism to authenticate to it. With PowervROps there are two options; a credentials based method and a token based method. Both authentication methods work with all of the cmdlets and indeed they could be mixed and matched as necessary.

Credentials based authentication

Credentials based authentication allows identical functionality when running in interactive mode in that a credentials object can be generated and then used in the same way as using token based authentication:

$credentials = get-credential -username <username>

The advantage of using credentials based authentication is that (although a security risk), the password used for authentication can be saved to a file and then read in during credentials creation. There is lots of information on this subject and below is a link to a blog post I’ve referenced a number of times:

https://blog.kloud.com.au/2016/04/21/using-saved-credentials-securely-in-powershell-scripts/

With this method scripts can be written and then used with task scheduler in a non-interactive fashion.

Token based authentication

Token based authentication requires that a user authenticates to vROps and in turn receives a token that lasts for 24 hours and can then be used on all subsequent requests. To make the process simpler there is a cmdlet called acquireToken which handles this for you. In order to be able to use the token during the session save it to a variable:

$token = acquiretoken -resthost <fqdn-of-the-vrops-node-or-cluster> -username <username> -password <password> -authsource <authsource>

If we execute this and then query the $token variable we should return something like below:

cac9cdc1-c2b3-487c-a51f-4ccb45e2b246::571da88c-a643-4706-a4d5-2e67d9ab1254

A few things to note about this command:

  • The password if using this command directly will be shown in plain text on screen, although there are methods around this when using the command in a script and prompting the user for their password an example is as follows:
  • $token = acquireToken -resthost $resthost -username $username -password ([Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((read-host 'Password: ' -assecurestring)))) -authSource $authsource)))
  • The authsource argument can either be local for local vROps accounts or the name of the domain name as configured via the authentication sources section in vROps.

Running our first command

Now that we have an authentication method we can execute our first command. For the purposes of the rest of this post (and the others in this series) I will use variables for things like the authentication token and the rest host that I will be connecting to. There is a cmdlet called getNodeStatus which returns information about the status of your vROps nodes:

getNodeStatus -resthost $resthost -token $token

This will return information similar to the following:

Screen Shot 2017-09-12 at 10.38.19

This command could be used along with a credentials object in a scheduled task to perform daily checks against vROps in a script format. If the variable is set by the command such as $notestatus then $nodestatus.status would quickly and easily allow you to retrieve the status of your vROps nodes without needing to open up a browser

Getting specific property information about an object

As interesting as retrieving the status of your vROps cluster is, that is far from the most interesting thing that can be achieved with PowervROPs. The scenario is to retrieve whether vSphere HA is enabled on a specific cluster. Now this information can be retrieved in many different ways and this is by far the most efficient (that’s what PowerCLI is for….). However, it shows what can be achieved via PowervROps.

There are a number of stages necessary in order to retrieve this information

  1. We need to obtain the ID of the object we want to query (the GUID that you see in the browser window when viewing the object in the vROps UI)
  2. We then need to get the specific property we are interested in from that object

Obtain the resources vROps ID

To get a resource we use the getResources cmdlet. Along with the standard arguments used in all of the cmdlets this has additional arguments for ‘name’, ‘resourceKind’ and ‘objectID’ which can be used to get a specific resource. This cmdlet can also be used to get all cluster resources, or all resources that have a common name element. For now we are going to get the cluster object called ‘Cluster A’ and save it to the variable $cluster

$cluster = getResources -token $token -resthost $resthost -name 'Cluster A' -resourceKind 'ClusterComputeResource'

If we query the cluster object and get its members we can see what a vROps resource query returns:

Screen Shot 2017-09-12 at 10.58.02

To get at the actual cluster object we need to step through the resourceList element:

Screen Shot 2017-09-12 at 10.58.43

We’ll go through the resourceList element in further detail in a future post but for now what we are interested in is the identifier element which is the object ID within vROps. We can get at this ID directly via:

$cluster.resourceList.identifier

Get all properties

Whilst we are specifically interesting in the HA enabled property it is worth knowing how to retrieve all properties as it has the benefit of showing you how the property is named when it is returned via such a query:

$clusterproperties =getResourceProperties -resthost $resthost -token $token -objectid $cluster.resourceList.identifier

If we look at the members of this variable we can see there is an element called property and if we query that then we can see all of the properties for this object

Screen Shot 2017-09-12 at 11.09.42

Get the HA setting property

To get at the specific property via a single command then we need to alter it slightly

$clusterhaproperty = getResourceProperties -resthost $resthost -token $token -objectid $cluster.resourceList.identifier).property | where { $_.name -eq 'configuration|dasConfig|enabled' }

Screen Shot 2017-09-12 at 11.12.38

As you can see knowing what the name of property is comes in handy when querying it directly.

This is the end of the first part in this series, check back soon for additional instalments where we will look at (amongst other things), generating reports, adding properties to an object, creating new objects, creating custom groups and investigating supermetrics.

All posts in this series:

Using PowervROps cmdlets (part 1) – Introduction

Using PowervROps cmdlets (part 2) – Retrieving metrics from objects

Using PowervROps cmdlets (part 3) – Adding metrics and properties to objects

Using PowervROps cmdlets (part 4) – Working with objects

Using PowervROps cmdlets (part 5) – Working with relationships

Using PowervROps cmdlets (part 6) – Working with custom groups

Using PowervROps cmdlets (part 7) – Working with supermetrics

Using PowervROps cmdlets (part 8) – Working with reports

Using PowervROps cmdlets (part 9) – Working with alerts

 

 

PowervROPs – Powershell cmdlets for the vROps API

What started out as the functions that were written for a customer I was working with has become something of an obsession that has resulted in a full-scale PowerShell module that exposes various parts of the vROps API.

The module should not be seen as a replacement for the vROps cmdlets available within PowerCLI, more as a complementary set that were born out of the specific requirements of a customer, but have since evolved as additional functions have been written.

The module is available on GitHub at the following URL:

https://github.com/andydvmware/PowervROps

There are currently 41 functions within the module, and for the most part they accept all parameters as defined by the API.

Screen Shot 2017-08-21 at 14.32.07

Over the coming days/weeks I’m going to write a series of posts detailed some of the ways in which the module has been used, however some of the highlights of the current release include:

  • Ability to generate and then download reports
  • Ability to add metrics and properties to objects
  • Add, set and delete relationships
  • Create new resources (for example custom datacenter objects)
  • Creation and deletion of custom groups
  • Ability to start/stop monitoring of resources
  • Ability to mark/unmark resources as being maintained