CloudBolt API v2.0

Philosophy

In designing the CloudBolt API, we evaluated and selected the latest in industry-proven conventions and design for REST APIs. Most notable is our adoption of HAL (Hypertext Application Language), which brings many benefits to our API such as making it explorable and self-descriptive. Documentation for our API is made available from within the API itself in addition to being presented in a browsable web UI, making the CloudBolt API easy to learn and consumable for developers of any modern language.

Another central benefit of adopting HAL is that it decouples the CloudBolt server’s API from the API clients, adding a level of automatic resilience to changes in the API that was not possible with API standards just a few years ago.

The resultant API is not just highly functional, enabling creative and powerful integrations, but even fun to learn and use. We welcome feedback on any aspect of the API and its documentation.

API Conventions

URLs / Resources

Collections of type “noun” are found at /{plural-noun}. Items within a collection are found at /{plural-noun}/id. A singleton item (one that exists without a collection) is made available at /{single-noun}. Collections and items are both called resources.

Collections will be more common, but two examples of singletons are: /user (representing the currently authenticated user) /user/current-order (the user’s current order)

Functionality that is better expressed in RPC style vs REST are exposed under an actions/ subpath. Example: /resource-handlers/actions/sync-vms.

Verbs

For collections and subcollections:

  • GET — retrieve the collection
  • POST — create a new item in the collection (not applicable to all collections)

For items:

  • GET — retrieve the item
  • DELETE — delete the item

For actions:

  • POST — trigger the action

Query String Parameters

CloudBolt API recognizes 3 special parameters that can be passed in the querystring part of the url:

Attributes

The attributes parameter can be used to append to the list of attributes that are returned for the Resource, or Collection being retrieved. It takes a comma delimited list of the Resource attributes.

Example: /api/v2/users/?attributes=user.first-name,user.last-name,user.is-superuser

Filter

The filter parameter can be used to limit the resources returned in a collection. It takes a semi-colon delimited list of key-value pairs, where the key and value are separated by a colon. It supports any Django QuerySet filter syntax where a single value of type string or numeric is expected (this includes booleans represented as 0 or 1).

Examples:

  • /api/v2/servers/?filter=hostname:linprodsvr0213
  • /api/v2/servers/?filter=environment.name.contains:Dev
  • /api/v2/users/?filter=user.first-name.startswith:A
  • /api/v2/jobs/?filter=type:provision;status:success

Authentication

Access to API end-points require the use of a bearer token in the request header. The API is subject to the same authentication and permissions model as the rest of CloudBolt, meaning that the security for which users can perform which actions will be consistent, regardless of whether they use the API or the web UI. It also means that requesting the access token supports the same parameters as when logging into the CloudBolt web interface.

Token Based Access to Resources

Access to API resources requires the use of a bearer token in the request header. The special end-point for requesting the token is api/v2/api-token-auth. The end-point expects clients to POST a JSON representation of authentication attributes like:

  • username - The username for the user requesting the token.
  • password - The password to which the user credentials should be checked against
  • token - A current user token, if CloudBolt is setup with 2-factor authentication
  • domain - The AD/LDAP directory domain the user belongs to, if not an internal user.

The token default expiration is set to 5 minutes. This can be changed by adding the following section to your customer_settings.py file and modifying the time in seconds to your preference:

import datetime
from settings import JWT_AUTH

JWT_AUTH['JWT_EXPIRATION_DELTA'] = datetime.timedelta(seconds=300)

For a complete list of all advanced settings related to the bearer token see http://getblimp.github.io/django-rest-framework-jwt/#additional-settings

Relationships & Properties

Resources contain relationships and properties (see “Format of HTTP success bodies (HAL)” for their representation).

  • relationships — expose related resources (example: a server resource has an “owner” relationship that points to a user resource)
  • properties — are data attached to a resource that are not resources themselves (example: a server has a “mem_size” property that is a simple numerical value)

Format of HTTP success bodies (HAL)

When a request for a CloudBolt API resource is successful, CloudBolt responds with an application/hal+json document. HAL stands for “Hypertext Application Language”, and defines a JSON-compliant format for expressing hyperlinks in APIs. The HAL IETF spec: http://tools.ietf.org/html/draft-kelly-json-hal-06.

Using HAL gives these benefits:

  • a well-defined response format (so we don’t have to invent/document our own) simple discovery/traversal of relationships (very useful — think about how densely hyperlinked our UI is!)
  • clients that don’t need to know how to build URLs — only follow relationships. This reduces client/server coupling down to an interface of relationships.
  • mechanism for including partials of related resources so they don’t have to be requested separately in many cases (imagine pre-fetching and Django ORM’s select_related).
  • no need to update HAL-aware API clients when new relations or URLs are added or changed — the new rels will be immediately available for use.
  • interactive point-and-click browsing of our API

Format of HTTP error bodies

{
  "status_code": 400-500,
  "detail": "Human readable error description",
  "error": "String representation of error",
}

Getting Started

Developers should feel free to interact with the API using any clients, libraries or tools that support making http requests. An example of retrieving the top level collections available using cURL, would look something like this, for instance:

$ curl -X POST -H "Content-Type: application/json" -d '{"username": "[username]", "password": "[password]"}' --insecure  https://[cb_server]/api/v2/api-token-auth/ -o token.txt
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current  Dload  Upload   Total   Spent    Left  Speed
100   243  100   197  100    46    542    126 --:--:-- --:--:-- --:--:--   542
$ cat token.txt | python -mjson.tool
{
    "token": "[encrypted_token_value]"
}
$ curl -H "Authorization: Bearer [encrypted_token_value]"--insecure https://[cb_server]/api/v2/ -o collections.txt
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current  Dload  Upload   Total   Spent    Left  Speed
113   226    0   226    0     0   1336      0 --:--:-- --:--:-- --:--:--  1345
$ cat collections.txt | python -mjson.tool
{
  "jobs": "/api/v2/jobs/",
  "users": "/api/v2/users/",
  "rules": "/api/v2/rules/",
  "blueprints": "/api/v2/blueprints/",
  "server-actions": "/api/v2/server-actions/",
  "environments": "/api/v2/environments/",
  "servers": "/api/v2/servers/",
  "orchestration-actions": "/api/v2/orchestration-actions/",
  "applications": "/api/v2/applications/",
  "service-actions": "/api/v2/service-actions/",
  "actions": "/api/v2/actions/",
  "groups": "/api/v2/groups/",
  "services": "/api/v2/services/",
  "os-builds": "/api/v2/os-builds/",
  "orders": "/api/v2/orders/",
  "resource-handlers": "/api/v2/resource-handlers/"
}

Out-Of-The-Box API Tools

CloudBolt ships with a couple of tools to help you quick-start developing API consumable resources. These tools are:

  • Browseable version of the API - To explore the available collections, resources and actions navigate to Admin -> Advanced -> API Browser

  • Sample API Client - is available for download here.

  • To use the sample Python scripts:

    1. Unpack the zip on a server with Python 2.6, 2.7, or 3.x
    2. cd api_samples/python_client/samples/
    3. Run ./order_blueprint.py -h

    #. Determine which IDs to use and parameters to pass. One easy way to do this is to submit an order from the CloudBolt web UI, then navigate to that order in the API browser (ex. /api/v2/orders/<your_order_id/>), and inspect the items in the order.

  • To use the sample Python client module to make API calls from an interactive Python shell:

    1. cd api_samples/python_client
    2. type: python to start the Python interpreter, and enter the following code:
    >>> from api_client import CloudBoltAPIClient
    >>> username = "YOUR_USERNAME"
    >>> password = "YOUR_PASSWORD"
    >>> hostname = "CB_HOST_NAME"
    >>> c = CloudBoltAPIClient(username, password, host=hostname, port=443, protocol="https")
    >>> c.get()
    {
        "actions": "/api/v2/actions/",
        "applications": "/api/v2/applications/",
        "environments": "/api/v2/environments/",
        "groups": "/api/v2/groups/",
        "jobs": "/api/v2/jobs/",
        "orchestration-actions": "/api/v2/orchestration-actions/",
        "orders": "/api/v2/orders/",
        "os-builds": "/api/v2/os-builds/",
        "resource-handlers": "/api/v2/resource-handlers/"
        "servers": "/api/v2/servers/",
        "server-actions": "/api/v2/server-actions/",
        "services": "/api/v2/services/",
        "service-actions": "/api/v2/service-actions/",
        "blueprints": "/api/v2/blueprints/",
        "users": "/api/v2/users/",
    }
    

Using AD/LDAP Credentials For API Requests

CB API Requests are subject to the same permissions and authentication rules as web portal users. In order to use your AD/LDAP integration for API calls simply use the domain keyword argument. For instance, if I want to make API calls using the jdoe account on domain example.com, then the sample python client should be initialized as:

>>> from api_client import CloudBoltAPIClient
>>> username = "jdoe"
>>> password = "jdoe_directory_password"
>>> domain = "example.com"
>>> hostname = "CB_HOST_NAME"
>>> c = CloudBoltAPIClient(username, password, domain=dmomain, host=hostname, port=443, protocol="https")

Sample Use Case

In order to illustrate how one might interact with the API, this document will list the ordered steps that could be used in ordering a new server. Sample requests and responses will be demonstrated with the use of the python client described in the previous section.

Ordering a new server:

  • Get your user id from your profile view in the web UI

  • Get groups available to the currently authenticated user

    >>> c.get("/api/v2/users/2/orderable-groups")
    {
        "links": {
            "self": {
              "href": "/api/v2/users/2/orderable-groups/",
              "title": "Orderable Groups Where '[user name]' Is A Requestor"
            }
        },
        "_embedded": [
            {
                "link": {
                    "self": {
                        "href": "/api/v2/groups/2",
                        "title": "Group Foo"
                    }
                },
                "name": "Group Foo"
            },
            {
                "link": {
                    "self": {
                        "href": "/api/v2/groups/3",
                        "title": "Group Bar"
                    }
                },
                "name": "Group Bar"
            }
        ]
    }
    
  • Select a group (Foo, id: 2)

  • Get environments available for the group

    >>> c.get("/api/v2/groups/2/orderable-environments")
    {
        "links": {
            "self": {
                "href": "/api/v2/groups/2/orderable-environments/",
                "title": "Orderable Environments For CB"
            }
        },
        "_embedded": [
            {
                "link": {
                    "self": {
                        "href": "/api/v2/environments/2",
                        "title": "Advanced Environment"
                    }
                },
                "name": "Advanced Environment"
            },
            {
                "link": {
                    "self": {
                        "href": "/api/v2/environments/3",
                        "title": "Simple Environment"
                    }
                },
                "name": "Simple Environment"
            }
        ]
    }
    
  • Select an environment (‘Simple Environment’, id: 3)

  • Create an order to provision a custom server. This is done by submitting an order for the blueprint called “Custom Server”.

TIP: One way to get familiar with the body of the request is to submit a Custom Server order in the CB web UI, then click the API… button on the order details page. The diaog that appears will contain the body of the request, which you can copy and paste, then tailor to your needs.

 >>> body = """
 ... {
...     "group": "/api/v2/groups/2",
...     "submit-now": "true"
...     "items": {
...         "deploy-items": [
...             {
...                 "blueprint": "/api/v2/blueprints/<ID of the Custom Server Blueprint>",
...                 "blueprint-items-arguments": {
...                     "build-item-Server": {
...                         "attributes": {
...                             "quantity": 1
...                         },
...                         "environment": "/api/v2/environments/3",
...                         "parameters": {
...                             "expiration-date": "2017-12-19",
...                             "os_build": "/api/v2/os-builds/1",
...                             "vm-size": "small"
...                         }
...                     }
...                 },
...                 "service-name": ""
...             }
...         ]
...     },
... }"""
 >>> c.post("/api/v2/orders/", body=body)
 {
     "_links": {
         "self": {
             "href": "/api/v2/orders/1",
             "title": "Order id 1"
         },
         "group": {
             "href": "/api/v2/groups/2",
             "title": "CB"
         },
         "owner": {
             "href": "/api/v2/users/2",
             "title": "User id 2"
         },
         "approved_by": {
             "href": "/api/v2/users/2",
             "title": "User id 2"
         },
         "actions": [
             {
                 "duplicate": {
                     "href": "/api/v2/orders/1/actions/duplicate",
                     "title": "Duplicate 'Order id 1'"
                 }
             }
         ],
     },
     "summary": "Provisioning of demo-api.cloudboltsw.com",
     "status": "ACTIVE",
     "rate": "0.00/month",
     "create-date": "2014-03-13T14:26:41",
     "approve-date": "2014-03-13T15:53:47",
     "items": {
         {'deploy-items': [
            {'blueprint': '/api/v2/blueprints/148',
             'blueprint-items-arguments': {
                'build-item-Server': {
                    'attributes': {'quantity': 1},
                    'environment': '/api/v2/environments/12',
                    'parameters': {
                        'sw-stack': 'Dev',
                        'vm-size': 'small'
                    }
                }
             },
           'service-name': 'Custom Server'}
         ]}
     }
 }
  • At this point the order has been submitted and auto-approved and the job that creates the server has been started

  • NOTE In order to modify a server, add a mod-item to an unsubmitted order

    >>> body = """
    ... {
    ...     "environment": "/api/v2/environments/3",
    ...     "server": "/api/v2/servers/1",
    ...     "parameters": {
    ...         "mem_size": "2 GB"
            }
    ... }"""
    >>> c.post("/api/v2/orders/2/mod-items/", body=body)
    {
        "_links": {
            "self": {
                "href": "/api/v2/orders/2",
                 "title": "Order id 2"
            },
            "group": {
                "href": "/api/v2/groups/2",
                "title": "CB"
            },
            "owner": {
                "href": "/api/v2/users/2",
                "title": "User id 2"
            },
            "actions": [
                {
                    "submit": {
                        "href": "/api/v2/orders/2/actions/submit",
                        "title": "Submit 'Order id 2'"
                    }
                },
                {
                    "cancel": {
                        "href": "/api/v2/orders/2/actions/cancel",
                        "title": "Cancel 'Order id 2'"
                    }
                }
            ]
        },
        "summary": "Modification of demo-api.cloudboltsw.com",
        "status": "CART",
        "rate": "0.00/month",
        "create-date": "2014-03-18T09:03:15",
        "items": {
            "mod-items": [
                {
                    "environment": "/api/v2/environments/3",
                    "server": "/api/v2/servers/1",
                    "delta": {
                        "Mem Size": "1 GB -> 2 GB"
                    }
                }
            ]
        }
    }
    
  • NOTE In order to delete a server, create a decommission order

    >>> body = """
    ... {
    ...    "group": "/api/v2/groups/2",
    ...    "items": {
    ...        "decom-items": [
    ...            {
    ...                "environment": "/api/v2/environments/3",
    ...                "servers": [
    ...                    "/api/v2/servers/1"
    ...                ]
    ...            }
    ...        ]
    ...    }
    ... }"""
    >>> c.post("/api/v2/orders/", body=body)
    {
        "_links": {
            "self": {
                "href": "/api/v2/orders/3",
                 "title": "Order id 3"
            },
            "group": {
                "href": "/api/v2/groups/2",
                "title": "CB"
            },
            "owner": {
                "href": "/api/v2/users/2",
                "title": "User id 2"
            },
            "actions": [
                {
                    "submit": {
                        "href": "/api/v2/orders/3/actions/submit",
                        "title": "Submit 'Order id 3'"
                    }
                },
                {
                    "cancel": {
                        "href": "/api/v2/orders/3/actions/cancel",
                        "title": "Cancel 'Order id 3'"
                    }
                }
            ]
        },
        "summary": "Deletion of demo-api.cloudboltsw.com",
        "status": "CART",
        "rate": "0.00/month",
        "create-date": "2014-03-18T09:03:15",
        "items": {
            "decom-items": [
                {
                    "environment": "/api/v2/environments/3",
                    "servers": [
                        {
                            "href": "/api/v2/servers/1",
                            "title": "demo-api.cloudboltsw.com"
                        }
                    ]
                }
            ]
        }
    }