The first way I elected to try and forcibly shut down the VSA VM was to do everything through the ESXi command line via SSH. ESXCLI itself is not implemented in VCO directly, so this will require some good old fashioned text parsing with AWK.
Enabling SSH on the host through a VCO Action
Unfortunately out of the box, there is no workflow/action that manages ESXi services, so I needed to roll my own.
Below is the Action setup and script code I used to check for the SSH service and start it up, given an input of type VC:HostSystem.
Create the Action, and name it startSSHService. There is no return value necessary on this Action.
// get the list of services var hostServices = inputHost.configManager.serviceSystem.serviceInfo.service var sshService = null // loop the services, find the SSH service. for each(svc in hostServices) { if(svc.key == "TSM-SSH") { sshService = svc System.log("Found SSH Service on host ["+inputHost.name+"]") break } } if(sshService == null) { throw "Couldn't find SSH service on ["+inputHost.name+"]!" } // Enable the service try { inputHost.configManager.serviceSystem.startService(sshService.key) } catch(err) { System.log("ERROR--Couldn't start SSH service. Error Text: "+err) } // the end
So, once you have SSH started on your ESXi host, you can send commands through VCO to do what you need.
SSH Service Check Action
For a more robust workflow, you will probably want an Action that will check to see if the service is running, and return a boolean value. That way you can build in a little bit more into the flow.
The setup for the ‘check’ Action is the same, with the exception of the return value being a boolean.

The code is similar as well, just doing a simple check at the end.
var hostservices = inputHost.config.service.service
var sshSvc = null
for each(svc in hostservices) {
// System.log("Service: "+svc.label+", Status is: "+svc.running)
if(svc.label == "SSH") {
sshSvc = svc
break
}
}
// check status, return true/false
if(sshSvc.running == true) {
return true
} else {
return false
}
Where’s my Burrit–VSA?
Before you power off the VSA VM you’ll want to make sure to vMotion your other guests to another node, or have a foolproof way of finding the VSA appliance on your host. Another Action to the rescue! Given an input ESXi host, this Action will query the VMs running on the host and check its tags out to see if it matches a specific value found on all VSA appliances. Note that these Tags are actually in the vCenter database, and not the Inventory Service Tags in the vSphere Web Client.
For purposes of this post, I’ll name the action getVSAonHost.

// for when you absolutely, positively need to make sure it's a VSA. var vsaKey = "SYSTEM/COM.VMWARE.VIM.SVA" // check the VMs on the host for the tag through a loop for each(vm in inputHost.vm) { if(vm.tag) { for each(tag in vm.tag) { if(tag.key == vsaKey) { return vm break } } } }
So now, you know you have the VM in question. You can then pass the VirtualMachine’s name property to your SSH command later.
Making a SSHandwich
With the ESXi host and the VSA VM in hand, you can execute the built in Run SSH Command workflow to do the final step.
Here’s the SSH command to send, which will find the VSA VM ID and power it off in one line, no questions asked:
VMID=$(vim-cmd vmsvc/getallvms | grep -i <VSA Name> | awk '{ print $1 }') && vim-cmd vmsvc/power.off $VMID
Begin by creating a new workflow, and create a single input parameter named inputHost, of type VC:HostSystem.
Then create three attributes in the General tab, naming them sshCommand, hostSystemName and vmVSAName, all of type string.
Finally, create another attribute called vsaAppliance of type VC:VirtualMachine for use with the Action.
Next, drop your getVSAonHost Action into the schema, and bind the actionResult to vsaAppliance as seen below.

Next, drop a Scriptable Task into the Schema and bind inputHost and vsaAppliance on the IN tab. On the OUT tab, bind the attributes of hostSystemName and vmVSAName. We are effectively going to write a small blurb of code that hands off the name properties of the input objects to the output attributes for use later, along with creating the SSH command string.

In the Scripting Tab, we’ll use a few simple lines of code to perform the handoff of values.
// assign values to output attributes hostSystemName = inputHost.name vmVSAName = vsaAppliance.name // create SSH command string using the input values sshCommand = "VMID=$(vim-cmd vmsvc/getallvms | grep -i "+vmVSAName+" | awk \'{ print $1 }\') && vim-cmd vmsvc/power.off $VMID"
Finally, drop a copy of the Run SSH Command workflow into the schema. There are a lot of inputs here, so you will have to do some more complicated bindings. You can either force them to be input each time the workflow is run, set a static value, or bind to existing attributes.
Here’s what it looks like by default.

How you approach this part is largely up to you, but here is how I did it for this example.

You’ll notice for the username/password I set a static value for root and set passwordAuthentication to Yes, and changed the initial hostNameOrIP and cmd values to the attributes we created earlier. For the outputs, I created new local attributes to show the results.
Run the workflow and you should see that VSA go down!
As an aside, if HA is enabled in your VSA HA Cluster object, it will immediately attempt to restart the machine – so make sure you add in the capability to disable HA into your parent workflows first so that this doesn’t end up being a problem.
Sweet Reprieve
It’s a bit crazy the amount of effort it takes to work around a disabled method, but it does work. I don’t think it’s particularly great, and if you’re the only one who cares about the systems and don’t have audits, this may be enough.
But for my purposes this was just the first step of the journey. I did not end up actually using this way to do things, but figured it may be a good exercise to document the process.
The next post will take it in a different direction altogether, and a little bit closer to an API based solution that can also be audited.