MAAS (Metal as a Service) is a hardware provisioning and orchestration system developed by Canonical (my employer). Cutting to the chase, MAAS provides a HTTP based API to allow users to control any aspect of the system programatically. Whilst there is documentation for this API, it is slightly fragmented and assumes a decent level of understanding of how ‘Restful APIs’ work. My goal in this blog post is to guide someone with a good understanding of Python and some knowledge of HTTP, through setting themselves up to start writing programs which use this API.
Prerequisites
Before starting, you should have access to a running instance of MAAS, which has at least an admin user account created on it. I won’t help you with that here, but the MAAS docs lay it all out. Provided that is in place, you will need the API key for that user. This is available on the User Preferences page (in the top right corner). This key and the URL of the MAAS server are required for the next step.
From a Python modules point-of-view, we are going to be working with Requests. This is the premier HTTP library available for Python today and offers a rich and easy to use interface for working with HTTP. Install this however you see fit and make sure you can:
>>> import requests
Authentication
Most API calls to MAAS require the user to be authenticated. To do these we need to provide a dictionary of headers to the Requests library. This dictionary can be generated using the following code snippet:
import oauth.oauth as oauth import httplib2 import uuid def get_auth_headers(url, apikey): consumer_key, key, secret = apikey.split(':') resource_tok_string = "oauth_token_secret=%s&oauth_token=%s" % ( secret, key) resource_token = oauth.OAuthToken.from_string(resource_tok_string) consumer_token = oauth.OAuthConsumer(consumer_key, "") oauth_request = oauth.OAuthRequest.from_consumer_and_token( consumer_token, token=resource_token, http_url=site, parameters={'oauth_nonce': uuid.uuid4().hex}) oauth_request.sign_request( oauth.OAuthSignatureMethod_PLAINTEXT(), consumer_token, resource_token) headers = oauth_request.to_header() headers['Accept'] = 'application/json' return headers
Note that I snuck a little something extra in, where on the second last line I set the ‘Accept’ header to ‘application/json’. This is not strictly required, but things will be much easier if the API gives us back straight-up JSON rather than anything else.
Sending Requests
Now that you have a way of getting the authentication headers, the rest is really straightforward. There are four types of requests that can be sent to MAAS (these concepts are general to HTTP and not MAAS specific)
GET
This type of request retrieves information on entities stored in MAAS. No parameters are required and they are very simple to send:
response = requests.get('http://mymaas.com:5240/MAAS/api/2.0/machines/', headers=get_auth_headers(apikey))
Upon returning, you can check if the call was successful and what the status code was (this is common to all requests) and the response text.
response.ok # True if successful, False otherwise response.status_code response.text
Assuming the call was successful, it should normally be possible to get the JSON output like so:
output = response.json()
POST
This type of request usually creates entities in MAAS, although it is also utilised in a slightly non-standard way in order to issue commands. There will usually be some parameters required for the request, which should be defined in a dictionary and passed like so:
data = {
'architecture': 'amd64/generic',
'mac_addresses': '00:00:00:00:00:00',
'power_type': 'manual',
}
response = requests.post(
'http://mymaas.com:5240/MAAS/api/2.0/machines/',
data=data,
headers=get_auth_headers(apikey)
)
As above for GET requests, you can access the status and output of the command quite easily. POST requests usually return a JSON representation of whatever they created.