Browse files

Added RunAbove's Compute driver with tests and docs.

Closes #550

Signed-off-by: Tomaz Muraus <>
  • Loading branch information...
ZuluPro authored and Kami committed Jul 7, 2015
1 parent ebe71ac commit f6038f6f9f38594d7d544de5b6e6dc78720cd29d
@@ -275,6 +275,10 @@ Compute
[Rico Echwald-Tijsen]

- Add new driver for RunAbove ( provider.


Binary file not shown.
@@ -0,0 +1,72 @@
Cloudwatt Compute Driver Documentation

`RunAbove`_ is a public cloud offer created by OVH Group with datacenters
in North America and Europe.

.. figure:: /_static/images/provider_logos/runabove.png
:align: center
:width: 300

RunAbove driver uses the OVH/RunAbove API so for more information about
that, please refer to `RunAbove knowledge base`_ page and `API console`_.

Instantiating a driver

When you instantiate a driver you need to pass the following arguments to the
driver constructor:

* ``user_id`` - Application key
* ``secret`` - Application secret
* ``ex_consumer_key`` - Consumer key

For get application key and secret, you must first register an application
at Next step, create a consumer key with
following command: ::

curl -X POST \
-H 'X-Ra-Application: youApplicationKey' \
-H 'Content-Type: application/json' \
-d '{
}' \

This will answer a JSON like below with inside your Consumer Key and
``validationUrl``. Follow this link for valid your key. ::


Now you have and can use you credentials with Libcloud.


Create instance

.. literalinclude:: /examples/compute/runabove/

API Docs

.. autoclass:: libcloud.compute.drivers.runabove.RunAboveNodeDriver

.. _`Runabove`:
.. _`RunAbove knowledge base`:
.. _`API console`:
@@ -0,0 +1,12 @@
from libcloud.compute.types import Provider
from libcloud.compute.providers import get_driver

RunAbove = get_driver(Provider.RUNABOVE)
driver = RunAbove('yourAppKey', 'yourAppSecret', 'YourConsumerKey')

image = [i for i in driver.list_images() if 'Debian 8' ==][0]
size = [s for s in driver.list_sizes() if == 'ra.s'][0]
location = [l for l in driver.list_locations() if == 'SBG-1'][0]

node = driver.create_node(name='yournode', size=size, image=image,
@@ -0,0 +1,134 @@
# licensed to the apache software foundation (asf) under one or more
# contributor license agreements. see the notice file distributed with
# this work for additional information regarding copyright ownership.
# the asf licenses this file to you under the apache license, version 2.0
# (the "license"); you may not use this file except in compliance with
# the license. you may obtain a copy of the license at
# unless required by applicable law or agreed to in writing, software
# distributed under the license is distributed on an "as is" basis,
# without warranties or conditions of any kind, either express or implied.
# see the license for the specific language governing permissions and
# limitations under the license.

import hashlib
import time
import simplejson as json
except ImportError:
import json
from libcloud.common.base import ConnectionUserAndKey, JsonResponse
from libcloud.httplib_ssl import LibcloudHTTPSConnection

API_ROOT = '/1.0'
'SBG-1': {'id': 'SBG-1', 'name': 'Strasbourg 1', 'country': 'FR'},
'BHS-1': {'id': 'BHS-1', 'name': 'Montreal 1', 'country': 'CA'}
{"method": "GET", "path": "/*"},
{"method": "POST", "path": "/*"},
{"method": "PUT", "path": "/*"},
{"method": "DELETE", "path": "/*"},

class RunAboveException(Exception):

class RunAboveConnection(ConnectionUserAndKey):
A connection to the RunAbove API
Wraps SSL connections to the RunAbove API, automagically injecting the
parameters that the API needs for each request.
host = API_HOST
request_path = API_ROOT
responseCls = JsonResponse
timestamp = None
ua = []
_timedelta = None

allow_insecure = True

def __init__(self, user_id, *args, **kwargs):
self.consumer_key = kwargs.pop('ex_consumer_key', None)
if self.consumer_key is None:
consumer_key_json = self.request_consumer_key(user_id)
msg = "Your consumer key isn't validated, " \
"go to '{validationUrl}' for valid it. After instantiate " \
"your driver with \"ex_consumer_key='{consumerKey}'\"."\
raise RunAboveException(msg)
super(RunAboveConnection, self).__init__(user_id, *args, **kwargs)

def request_consumer_key(self, user_id):
action = self.request_path + '/auth/credential'
data = json.dumps({
"redirection": "",
headers = {
'Content-Type': 'application/json',
'X-Ra-Application': user_id,
httpcon = LibcloudHTTPSConnection(
httpcon.request(method='POST', url=action, body=data, headers=headers)
response = httpcon.getresponse().read()
json_response = json.loads(response)
return json_response

def get_timestamp(self):
if not self._timedelta:
action = API_ROOT + '/auth/time'
response = self.connection.request('GET', action, headers={})
timestamp = int(response)
self._time_delta = timestamp - int(time.time())
return int(time.time()) + self._timedelta

def make_signature(self, method, action, data, timestamp):
full_url = 'https://%s%s' % (API_HOST, action)
sha1 = hashlib.sha1()
base_signature = "+".join([
data if data else '',
signature = '$1$' + sha1.hexdigest()
return signature

def add_default_params(self, params):
return params

def add_default_headers(self, headers):
"X-Ra-Application": self.user_id,
"X-Ra-Consumer": self.consumer_key,
"Content-type": "application/json",
return headers

def request(self, action, params=None, data=None, headers=None,
method='GET', raw=False):
data = json.dumps(data) if data else None
timestamp = self.get_timestamp()
signature = self.make_signature(method, action, data, timestamp)
headers = headers or {}
"X-Ra-Timestamp": timestamp,
"X-Ra-Signature": signature
return super(RunAboveConnection, self)\
.request(action, params=params, data=data, headers=headers,
method=method, raw=raw)
Oops, something went wrong.

0 comments on commit f6038f6

Please sign in to comment.