CloudStack API PowerShell Example

Summary: This script uses a simple command, sent via PowerShell and REST to a CloudStack API, in order to list all visible Virtual Machines as well as their current state (‘Running’, ‘Stopped’, etc.).

CloudStack is an Apache Open Source project for managing a cloud service (much like OpenStack, but it’s been around a LOT longer). CloudStack also has an impressive list of customers (check out their Wikipedia post above). Like most cloud services, CloudStack has an API (REST) for programmatically interacting with the service.

Note: A valid account’s API public key and secret are required for this script.

This API authenticates requests by using an account’s public key and secret to create a signature for the API request. In order the create the signature, the command being signed must be broken down into key/value pairs, sorted, reassembled for signing, then converted to lower case.

On-going problems: This script mostly works. But it (or the API) has problems with certain command strings. And PowerShell doesn’t seem to like the API’s output in JSON (so this script uses the default XML). If you find a solution, please reach out.

Datapipe’s documentation of their implementation of the CloudStack API can be found here: https://docs.cloud.datapipe.com/developers/api/developers-guide

Here is a sample list of command strings that leverage the listVirtualMachines method (your mileage may vary):

command=listVirtualMachines
command=listVirtualMachines&state=Running
command=listVirtualMachines&account=General
command=listVirtualMachines&zoneid=13
command=listVirtualMachines&groupid=21&account=General
command=listVirtualMachines&groupid=21&account=General&state=Running
command=listVirtualMachines&state=Stopped&response=json
command=listVirtualMachines&id=3a57b2d3-b95a-4892-903a-34f4662ed475&response=json
command=listVirtualMachines&id=3a57b2d3-b95a-4892-903a-34f4662ed475
command=listVirtualMachines&state=Running&response=json

Note: This script requires PowerShell v.3+ due to the use of the Invoke-RestMethod cmdlets.

openstackApiExample.ps1

#
# Name:: openstackApiExample.ps1
# Version:: 0.1.0 (6/27/2016)
# Script Description:: Queries the Datapipe Cloud (Cloud-Stack) REST API
#
# API Documentation:: https://docs.cloud.datapipe.com/developers/api/developers-guide
#
# Author(s):: Otto Helweg
#
# PowerShell v.3+ is required for the Invoke-RestMethod cmdlet
#
# Parameters: -k = apikey, -s = secret (both are required)
# Example: .\apiExample.ps1 -k "F2rrzJiluwK39LpD6PvyF2rrzJiluwK39LpD6PvyF2rrzJiluwK39LpD6PvyF2rrzJiluwK39LpD6PvyF2rrzJ" -s "iluwK39LpD6PvyF2rrzJiluwK39LpD6PvyF2rrzJiluwK39LpD6PvyF2rrzJiluwK39LpD6PvyF2rrzJiluwK3"

param($k,$s)

$uri=@{}
$baseUri = "https://cloud.datapipe.com/api/compute/v1?"
$command = "command=listVirtualMachines"
# The following is a command string that should work, but doesn't
# $command = "command=listVirtualMachines&state=Running"
$uri["apikey"] = $k
$secret = $s

# Build the Command String for getting an authorization signature
# First extract all key/value pairs in the command into the uri hash
$subCommand = $command.split("&")
foreach ($item in $subCommand | Sort-Object) {
  if ($item -like "*=*") {
    $items = $item.Split("=")
    $uri[$items[0]] = $items[1]
  } else {
    $uri[$item] = ""
  }
}

# Build the signing String by sorting the command key/values then make lowercase for signing
$signString = ""
foreach ($key in $uri.Keys | Sort-Object) {
  if ($uri[$key]) {
    $signString = $signString + $key + "=" + $uri[$key] + "&"
  } else {
    $signString = $signString + $key + "&"
  }
}
$signString = $signString.ToLower()
$signString = $signString.TrimEnd("&")

# Get the HMAC SHA-1 signature for the specific Command String
$hmacSha = New-Object System.Security.Cryptography.HMACSHA1
$hmacSha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature = $hmacSha.ComputeHash([Text.Encoding]::ASCII.GetBytes($signString))
$signature = [Convert]::ToBase64String($signature)

# Build the signed REST URI
$newUri = $baseUri + $command + "&apiKey=" + $uri["apikey"] + "&signature=" + $signature
Write-Host "URI: $newUri"
Write-Host "signString: $signString"
Write-Host "Signature: $signature"

# Query for a list of all VMs
Write-Host "Querying the Cloud-Stack API..."
[xml]$vmList = Invoke-RestMethod -Method GET -Uri $newUri -ContentType "application/xml"

# List all VMs visible by the account
Write-Host ""
Write-Host "Virtual Machines:"
foreach ($vm in $vmList.listvirtualmachinesresponse.virtualmachine) {
  if ($vm.state -eq "Stopped") {
    $color = "yellow"
  } else {
    $color = "white"
  }
  Write-Host -ForegroundColor $color "$($vm.displayname) - $($vm.state)"
}

 

Enjoy!

 

Advertisements