So, my request to enter on the free and private beta season of the new HP Cloud Services was gently accepted by the HP Cloud team, and today I finally got some time to play with the OpenStack API at HP Cloud. I’ll start with the first impressions I had with the service:

The user interface of the management is very user-friendly, the design is much like of the Twitter Bootstrap, see the screenshot below of the “Compute” page from the “Manage” section:

As you can see, they have a set of 4 Ubuntu images and a CentOS, I think that since they are still in the beta period, soon we’ll have more default images to use.

Here is a screenshot of the instance size set:

Since they are using OpenStack, I really think that they should have imported the vocabulary of the OpenStack into the user interface, and instead of calling it “Size”, it would be more sensible to use “Flavour“.

The user interface still doesn’t have many features, something that I would really like to have is a “Stop” or something like that for the instances, only the “Terminate” function is present on the Manage interface, but those are details that they should be still working on since they’re only in beta.

Another important info to cite is that the access to the instances are done through SSH using a generated RSA key that they provide to you.

Let’s dig into the OpenStack API now.

OpenStack API

To access the OpenStack API you’ll need the credentials for the authentication, HP Cloud services provide these keys on the Manage interface for each zone/service you have, see the screenshot below (with keys anonymized of course):

Now, OpenStack authentication could be done in different schemes, the scheme that I know that HP supports is the token authentication. I know that there is a lot of clients already supporting the OpenStack API (some have no documentation, some have weird API design, etc.), but the aim of this post is to show how easy would be to create a simple interface to access the OpenStack API using Python and Requests (HTTP for Humans !).

Let’s start defining our authentication scheme by sub-classing Requests AuthBase:

[enlighter lang=”python” ]

class OpenStackAuth(AuthBase):

def __init__(self, auth_user, auth_key):

self.auth_key = auth_key

self.auth_user = auth_user

def __call__(self, r):

r.headers[‘X-Auth-User’] = self.auth_user

r.headers[‘X-Auth-Key’] = self.auth_key

return r

[/enlighter]

As you can see, we’re defining the X-Auth-User and the X-Auth-Key in the header of the request with the parameters. These parameters are respectively your Account ID and Access Key we cited earlier. Now, all you have to do is to make the request itself using the authentication scheme, which is pretty easy using Requests:

[enlighter lang=”python”]

ENDPOINT_URL = ‘https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/’

ACCESS_KEY = ‘Your Access Key’

ACCOUNT_ID = ‘Your Account ID’

response = requests.get(ENDPOINT_URL, auth=OpenStackAuth(ACCOUNT_ID, ACCESS_KEY))

[/enlighter]

And that is it, you’re done with the authentication mechanism using just a few lines of code, and this is how the request is going to be sent to the HP Cloud service server:

This request is sent to the HP Cloud Endpoint URL (https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/). Let’s see now how the server answered this authentication request:

You can show this authentication response using Requests by printing the header attribute of the request Response object. You can see that the server answered our request with two important header items: X-Server-Management-URL and the X-Auth-Token. The management URL is now our new endpoint, is the URL we should use to do further requests to the HP Cloud services and the X-Auth-Token is the authentication Token that the server generated based on our credentials, these tokens are usually valid for 24 hours, although I haven’t tested it.

What we need to do now is to sub-class the Requests AuthBase class again but this time defining only the authentication token that we need to use on each new request we’re going to make to the management URL:

[enlighter lang=”python”]

class OpenStackAuthToken(AuthBase):

def __init__(self, request):

self.auth_token = request.headers[‘x-auth-token’]

def __call__(self, r):

r.headers[‘X-Auth-Token’] = self.auth_token

return r

[/enlighter]

Note that the OpenStackAuthToken is receiving now a response request as parameter, copying the X-Auth-Token and setting it on the request.

Let’s consume a service from the OpenStack API v.1.1, I’m going to call the List Servers API function, parse the results using JSON and then show the results on the screen:

[enlighter lang=”python”]

# Get the management URL from the response header

mgmt_url = response.headers[‘x-server-management-url’]

# Create a new request to the management URL using the /servers path

# and the OpenStackAuthToken scheme we created

r_server = requests.get(mgmt_url + ‘/servers’, auth=OpenStackAuthToken(response))

# Parse the response and show it to the screen

json_parse = json.loads(r_server.text)

print json.dumps(json_parse, indent=4)

[/enlighter]

And this is what we get in response to this request:

[enlighter]

{

“servers”: [

{

“id”: 22378,

“uuid”: “e2964d51-fe98-48f3-9428-f3083aa0318e”,

“links”: [

{

“href”: “https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/20817201684751/servers/22378”,

“rel”: “self”

},

{

“href”: “https://az-1.region-a.geo-1.compute.hpcloudsvc.com/20817201684751/servers/22378”,

“rel”: “bookmark”

}

],

“name”: “Server 22378”

},

{

“id”: 11921,

“uuid”: “312ff473-3d5d-433e-b7ee-e46e4efa0e5e”,

“links”: [

{

“href”: “https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/20817201684751/servers/11921”,

“rel”: “self”

},

{

“href”: “https://az-1.region-a.geo-1.compute.hpcloudsvc.com/20817201684751/servers/11921”,

“rel”: “bookmark”

}

],

“name”: “Server 11921”

}

]

}

[/enlighter]

And that is it, now you know how to use Requests and Python to consume OpenStack API. If you wish to read more information about the API and how does it works, you can read the documentation here.

– Christian S. Perone