Why you are sometimes unable to see vRO actions when creating vRA Property Definitions

A common question I get asked when working with customers is why are they unable to see recently created vRealize Orchestrator (vRO) action when creating vRealize Automation (vRA) Property Defintions. For example, let’s say I created the vRO action below:


The main things to notice are:

  1. The action is called getNames and is under the io.orchestration package
  2. The return type is Array/string

In my vRA Property Definition I’ll set the Data type to be a String and Display as to Dropdown as shown:


Now if I select set Values to External values (a vRO action) and press Select, I’ll be presented with a list of vRO actions:


Here we can see the same vRO action (getNames) we created in vRO:


Before displaying the Select Script Action screen above, vRA queried vRO for all actions that have a return type of Array/string. This is because in the Property Definition I’m going to be displaying a dropdown box of strings.

If I was to change the Property Definition to use a Data type of Integer:


and tried to use External values, I wouldn’t be able to see my vRO script action:


So as you can see your vRO action’s return type must match the data type defined in your Property Defintion otherwise you’ll be unable to see your vRO action.

Because vRA allows you to configure a global vRO server and vRO servers per tenant, sometimes users will create a vRO action on one vRO server, but their vRA tenant will be configured to be using a different vRO server. If you have ssh access to the vRO servers, you can confirm that you’re working with the correct vRO server by running the following command as you attempt to browse vRO actions from your Property Definition:

tail -F /var/log/vmware/vco/app-server/localhost_access_log.txt | grep getNames

If you’re on the correct server, you’ll see results such as these:

vra73a:/var/log/vmware/vco/app-server # tail -F localhost_access_log.txt | grep getNames
2017-12-07 03:55:28.677+0000 – – [http-nio-] “GET /vco/api/actions/com.vmware.o11n.plugin.dynamictypes.configuration/getNamespaceByName HTTP/1.1” 200 1011 194
2017-12-07 03:55:32.875+0000 – – [http-nio-] “GET /vco/api/actions/io.orchestration/getNames HTTP/1.1” 200 827 196




What does vRealize Automation’s Unregister action do?

Today I had a customer say that they added the vRA “Unregister (Machine)” entitlement to their account but were unable to see the Unregister action in the Actions dropdown list:


Read the rest of this entry »

Preparing CentOS 7 vRA templates with Ansible

In my lab I’m often spinning up new instances of vRealize Automation (vRA) and need to configure CentOS 7 templates. I created this Ansible playbook to get a freshly installed CentOS 7.2 minimal machine ready to be used by vRA. This is my first attempt and I’ll be modifying it to make it more usable. The playbook can be found at Github. Read the rest of this entry »

PowerCLI script to monitor recent vSphere Tasks

I haven’t had much time to look at vSphere 6.5 yet, but appearently the C# client is no more. I used to always have the C# client up as a diagnostic tool so that I could watch events trigger in real time as opposed to having to refresh the vSphere web client. Normally I’d open the C# client in full screen and then arrange my browsers so that they would cover the C# client but leave room so I’d be able to see the recent tasks pane. This would allow me to work in another product like vRealize Automation and see events appear in vCenter immediately.

If I can’t use the C# client to do this going forward, I thought I’d create a little PowerCLI script to provide me with the same information. I’m not sure how well it will work out yet, but you can find it on GitHub.

The result look like this:


NetApp ONTAP 9 Simulator Guide by Neil Anderson

I want to take a moment to mention the great work Neal Anderson did in his NetApp ONTAP 9 Simulator Guide. This incredibly detailed (117 pages) guide not only shows you how to set up a NetApp ONTAP 9 simulator for your lab, but you’ll also learn how install/configure:

Storage is critical to any infrastructure and while you’re learning it’s easy to quickly install a storage solution that’s not representative of what you’ll see in the real world. I try to make my lab environment match what I see in real production environments as much as possible. That means using segregated networks with VLANs, firewalls, load balancers, CA signed certificates, and with the help this guide you’ll be able to implement a real world storage solution.

Listing all vCenter performance metrics with govmomi

In the past I wrote about how to List all vCenter performance counters with PowerCLI. In this post I’ll show how to do the same in Go with govmomi and compare the performance between the two.  I created the PowerCLI version of the script to gather vSphere performance counter information that I needed while creating the script in Gathering real-time vSphere performance metrics in parallel using PowerCLI. My goal is to create a Go version of this script using govmomi.

The code can be found at on github.

The performance counters are the same since it’s running against the same version of vCenter and can be found here.

You can also look at the vSphere performance counters through the vCenter mob by going to https://vcenter/mob/ and selecting content and then PerfMgr.




If you’re not familiar with the vSphere API (like me), the mob can be a create place to explore and learn.


The performance relevant pieces are highlighted towards the end.

package main

import (


// GetEnvString returns string from environment variable.
func GetEnvString(v string, def string) string {
        r := os.Getenv(v)
        if r == "" {
                return def

        return r

// GetEnvBool returns boolean from environment variable.
func GetEnvBool(v string, def bool) bool {
        r := os.Getenv(v)
        if r == "" {
                return def

        switch strings.ToLower(r[0:1]) {
        case "t", "y", "1":
                return true

        return false

const (
        envURL      = "GOVMOMI_URL"
        envUserName = "GOVMOMI_USERNAME"
        envPassword = "GOVMOMI_PASSWORD"
        envInsecure = "GOVMOMI_INSECURE"

var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", GetEnvString(envURL, "https://username:password@host/sdk"), urlDescription)

var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", GetEnvBool(envInsecure, false), insecureDescription)

func processOverride(u *url.URL) {
        envUsername := os.Getenv(envUserName)
        envPassword := os.Getenv(envPassword)

        // Override username if provided
        if envUsername != "" {
                var password string
                var ok bool

                if u.User != nil {
                        password, ok = u.User.Password()

                if ok {
                        u.User = url.UserPassword(envUsername, password)
                } else {
                        u.User = url.User(envUsername)

        // Override password if provided
        if envPassword != "" {
                var username string

                if u.User != nil {
                        username = u.User.Username()

                u.User = url.UserPassword(username, envPassword)

func exit(err error) {
        fmt.Fprintf(os.Stderr, "Error: %s\n", err)

func main() {
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()


        // Parse URL from string
        u, err := url.Parse(*urlFlag)
        if err != nil {

        fmt.Println("u:", u)

        // Override username and/or password as required

        // Connect and log in to ESX or vCenter
        client, err := govmomi.NewClient(ctx, u, *insecureFlag)
        if err != nil {

        if client.IsVC() {
                fmt.Println("connected to vCenter")
        } else {
                fmt.Println("connected to ESXi host")

        var perfManager mo.PerformanceManager
        err = client.RetrieveOne(ctx, *client.ServiceContent.PerfManager, nil, &perfManager)
        perfCounters := perfManager.PerfCounter

        counterDetails := make([][]string, 0)

        for _, perfCounter := range perfCounters {
                groupInfo := perfCounter.GroupInfo.GetElementDescription()
                nameInfo := perfCounter.NameInfo.GetElementDescription()

                fullName := groupInfo.Key + "." + nameInfo.Key + "." + fmt.Sprint(perfCounter.RollupType)
                counterDetails = append(counterDetails, []string{fullName, fmt.Sprint(perfCounter.Level), nameInfo.Summary})

        outputFile, err := os.Create("performanceCounters.csv")
        csvWriter := csv.NewWriter(outputFile)

        if err := csvWriter.Error(); err != nil {
                log.Fatalln("error writing csv:", err)

Performance Results

This is hardly scientific, but here are the times it took to run the Go and Powershell versions of the script. I measured the runs three times and used the Powershell measure-command.

Ubuntu 14.04.5 LTS
go 1.7.1 776 ms
PowerCLI alpha for Linux 2259 ms
Windows 10
go 1.7.1 1746 ms
PowerCLI 6.0 Release 1 build 2548067 1639 ms

Hello Node.js on Rancher

In this post I’m going to show how to go through the Kubernetes Hello World Walkthrough but using Rancher instead of Google’s Cloud Platform. One of the reasons I wanted to install Kubernetes on my own resources instead of in the cloud is so that I don’t have to pay additional costs while I’m experimenting/learning.

You’ll need to have done the following before proceeding:

Create the Docker image

I’m going to build the Docker image on my Rancher machine (a VM), but you can build it anywhere. If you decide to build the Docker image somewhere other than the Rancher machine, you’ll need to push your image up to Docker Hub. You may be able to add a container registry to Rancher, but I haven’t explored that. You can also use my image.

Run the following on the Rancher machine.

mkdir hello-node
cd hello-node

Create a file named Dockerfile with the following contents:

FROM node:4.4
COPY server.js .
CMD node server.js

Create a file named server.js with the following contents:

var http = require(‘http’);
var handleRequest = function(request, response) {
response.end(“Hello World!”);
var www = http.createServer(handleRequest);

Build the Docker image (that’s a period after v1):

docker build -t chrisgreene/hello-node:v1 .

If you need to upload the image to Docker Hub (make sure to change the image name or it will conflict with mine and fail):

docker login
docker push

Create the deployment

Now that we have our Docker image ready to go we can create the deployment. To do so:

  1. Make sure you’re in the Kubernetes (k8s) environment.
  2. Select Kubernetes
  3. Select Kubectl
  4. You’ll now have a shell to enter commands


Enter the following command (replace the image name if you’re using your own):

kubectl run hello-node –image=chrisgreene/hello-node:v1 –port=8080


If the deployment was successfully created, you’ll see the following:


Verify our deployment:


If we get all of the pods, we will see the hello-node pod:


You can also view the replica sets by running kubectl get rs.

Select Infrastructure > Containers and you’ll see the hello-node containers:


Expose the Node.js service to the outside

In order to reach the Node.js service, we need to expose it. We can do this with the following command:

kubectl expose deployment hello-node –port=80 –target-port=8080 –external-ip= is the IP of my Rancher machine. You’ll most likely need to change this. If you’re copy and pasting from this example, make sure there are two dashes in front of port, target-port and external-ip. Sometimes those get lost during copy/paste and the command won’t work.


Let’s verify our service:


Now I can access my Node.js app:


Scale the app

Let’s scale the app to 4 replicas instead of one:


Verify that we now have 4 pods:


Upgrade the app

I’m not going to show the steps to upgrade the app, but they are exactly as described in Roll out an upgrade to your website.

I performed the steps and was able to see the new site: