You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by pq...@apache.org on 2010/08/13 01:24:41 UTC
svn commit: r985035 - in /incubator/libcloud/trunk: libcloud/
libcloud/drivers/ test/ test/fixtures/elastichosts/
Author: pquerna
Date: Thu Aug 12 23:24:40 2010
New Revision: 985035
URL: http://svn.apache.org/viewvc?rev=985035&view=rev
Log:
Add driver for the ElasticHosts provider (http://www.elastichosts.com/), closing LIBCLOUD-45.
Submitted by: Tomaz Muraus <tomaz cloudkick.com>
Added:
incubator/libcloud/trunk/libcloud/drivers/elastichosts.py (with props)
incubator/libcloud/trunk/test/fixtures/elastichosts/
incubator/libcloud/trunk/test/fixtures/elastichosts/drives_create.json
incubator/libcloud/trunk/test/fixtures/elastichosts/drives_info.json
incubator/libcloud/trunk/test/fixtures/elastichosts/servers_create.json
incubator/libcloud/trunk/test/fixtures/elastichosts/servers_info.json
incubator/libcloud/trunk/test/test_elastichosts.py (with props)
Modified:
incubator/libcloud/trunk/libcloud/drivers/__init__.py
incubator/libcloud/trunk/libcloud/providers.py
incubator/libcloud/trunk/libcloud/types.py
Modified: incubator/libcloud/trunk/libcloud/drivers/__init__.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/__init__.py?rev=985035&r1=985034&r2=985035&view=diff
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/__init__.py (original)
+++ incubator/libcloud/trunk/libcloud/drivers/__init__.py Thu Aug 12 23:24:40 2010
@@ -21,6 +21,7 @@ __all__ = [
'dummy',
'ec2',
'ecp',
+ 'elastichosts',
'gogrid',
'ibm_sbc',
'linode',
Added: incubator/libcloud/trunk/libcloud/drivers/elastichosts.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/elastichosts.py?rev=985035&view=auto
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/elastichosts.py (added)
+++ incubator/libcloud/trunk/libcloud/drivers/elastichosts.py Thu Aug 12 23:24:40 2010
@@ -0,0 +1,457 @@
+# 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+# Copyright 2009 RedRata Ltd
+"""
+ElasticHosts Driver
+"""
+import re
+import time
+import base64
+
+from libcloud.types import Provider, NodeState, InvalidCredsException
+from libcloud.base import ConnectionUserAndKey, Response, NodeAuthPassword
+from libcloud.base import NodeDriver, NodeSize, Node, NodeLocation
+from libcloud.base import NodeImage
+
+# JSON is included in the standard library starting with Python 2.6. For 2.5
+# and 2.4, there's a simplejson egg at: http://pypi.python.org/pypi/simplejson
+try:
+ import json
+except:
+ import simplejson as json
+
+# API end-points
+API_ENDPOINTS = {
+ 'uk-1': {
+ 'name': 'London Peer 1',
+ 'country': 'United Kingdom',
+ 'host': 'api.lon-p.elastichosts.com'
+ },
+ 'uk-2': {
+ 'name': 'London BlueSquare',
+ 'country': 'United Kingdom',
+ 'host': 'api.lon-b.elastichosts.com'
+ },
+ 'us-1': {
+ 'name': 'San Antonio Peer 1',
+ 'country': 'United States',
+ 'host': 'api.sat-p.elastichosts.com'
+ },
+}
+
+# Default API end-point for the base connection clase.
+DEFAULT_ENDPOINT = 'us-1'
+
+# ElasticHosts doesn't specify special instance types, so I just specified
+# some plans based on the pricing page (http://www.elastichosts.com/cloud-hosting/pricing)
+# and other provides.
+#
+# Basically for CPU any value between 500Mhz and 20000Mhz should work,
+# 256MB to 8192MB for ram and 1GB to 2TB for disk.
+INSTANCE_TYPES = {
+ 'small': {
+ 'id': 'small',
+ 'name': 'Small instance',
+ 'cpu': 2000,
+ 'memory': 1700,
+ 'disk': 160,
+ 'bandwidth': None,
+ },
+ 'large': {
+ 'id': 'large',
+ 'name': 'Large instance',
+ 'cpu': 4000,
+ 'memory': 7680,
+ 'disk': 850,
+ 'bandwidth': None,
+ },
+ 'extra-large': {
+ 'id': 'extra-large',
+ 'name': 'Extra Large instance',
+ 'cpu': 8000,
+ 'memory': 8192,
+ 'disk': 1690,
+ 'bandwidth': None,
+ },
+ 'high-cpu-medium': {
+ 'id': 'high-cpu-medium',
+ 'name': 'High-CPU Medium instance',
+ 'cpu': 5000,
+ 'memory': 1700,
+ 'disk': 350,
+ 'bandwidth': None,
+ },
+ 'high-cpu-extra-large': {
+ 'id': 'high-cpu-extra-large',
+ 'name': 'High-CPU Extra Large instance',
+ 'cpu': 20000,
+ 'memory': 7168,
+ 'disk': 1690,
+ 'bandwidth': None,
+ },
+}
+
+# Retrieved from http://www.elastichosts.com/cloud-hosting/api
+STANDARD_DRIVES = {
+ 'cf82519b-01a0-4247-aff5-a2dadf4401ad': {
+ 'uuid': 'cf82519b-01a0-4247-aff5-a2dadf4401ad',
+ 'description': 'Debian Linux 4.0: Base system without X',
+ 'size_gunzipped': '1GB',
+ },
+ 'e6111e4c-67af-4438-b1bc-189747d5a8e5': {
+ 'uuid': 'e6111e4c-67af-4438-b1bc-189747d5a8e5',
+ 'description': 'Debian Linux 5.0: Base system without X',
+ 'size_gunzipped': '1GB',
+ },
+ 'bf1d943e-2a55-46bb-a8c7-6099e44a3dde': {
+ 'uuid': 'bf1d943e-2a55-46bb-a8c7-6099e44a3dde',
+ 'description': 'Ubuntu Linux 8.10: Base system with X',
+ 'size_gunzipped': '3GB',
+ },
+ '757586d5-f1e9-4d9c-b215-5a391c9a24bf': {
+ 'uuid': '757586d5-f1e9-4d9c-b215-5a391c9a24bf',
+ 'description': 'Ubuntu Linux 9.04: Base system with X',
+ 'size_gunzipped': '3GB',
+ },
+ 'b9d0eb72-d273-43f1-98e3-0d4b87d372c0': {
+ 'uuid': 'b9d0eb72-d273-43f1-98e3-0d4b87d372c0',
+ 'description': 'Windows Web Server 2008',
+ 'size_gunzipped': '13GB',
+ },
+ '30824e97-05a4-410c-946e-2ba5a92b07cb': {
+ 'uuid': '30824e97-05a4-410c-946e-2ba5a92b07cb',
+ 'description': 'Windows Web Server 2008 R2',
+ 'size_gunzipped': '13GB',
+ },
+ '9ecf810e-6ad1-40ef-b360-d606f0444671': {
+ 'uuid': '9ecf810e-6ad1-40ef-b360-d606f0444671',
+ 'description': 'Windows Web Server 2008 R2 + SQL Server',
+ 'size_gunzipped': '13GB',
+ },
+ '10a88d1c-6575-46e3-8d2c-7744065ea530': {
+ 'uuid': '10a88d1c-6575-46e3-8d2c-7744065ea530',
+ 'description': 'Windows Server 2008 Standard R2',
+ 'size_gunzipped': '13GB',
+ },
+ '2567f25c-8fb8-45c7-95fc-bfe3c3d84c47': {
+ 'uuid': '2567f25c-8fb8-45c7-95fc-bfe3c3d84c47',
+ 'description': 'Windows Server 2008 Standard R2 + SQL Server',
+ 'size_gunzipped': '13GB',
+ },
+}
+
+NODE_STATE_MAP = {
+ 'active': NodeState.RUNNING,
+ 'dead': NodeState.TERMINATED,
+ 'dumped': NodeState.TERMINATED,
+}
+
+# Default timeout (in seconds) for the drive imaging process
+IMAGING_TIMEOUT = 10 * 60
+
+class ElasticHostsException(Exception):
+ """
+ Exception class for ElasticHosts driver
+ """
+
+ def __str__(self):
+ return self.args[0]
+
+ def __repr__(self):
+ return "<ElasticHostsException '%s'>" % (self.args[0])
+
+class ElasticHostsResponse(Response):
+ def success(self):
+ if self.status == 401:
+ raise InvalidCredsException()
+
+ return self.status >= 200 and self.status <= 299
+
+ def parse_body(self):
+ if not self.body:
+ return self.body
+
+ try:
+ data = json.loads(self.body)
+ except ValueError:
+ raise ElasticHostsException('Could not parse body: %s')
+
+ return data
+
+ def parse_error(self):
+ error_header = self.headers.get('x-elastic-error', '')
+ message = self.body
+
+ return 'X-Elastic-Error: %s (%s)' % (error_header, self.body.strip())
+
+class ElasticHostsNodeSize(NodeSize):
+ def __init__(self, id, name, cpu, ram, disk, bandwidth, price, driver):
+ self.id = id
+ self.name = name
+ self.cpu = cpu
+ self.ram = ram
+ self.disk = disk
+ self.bandwidth = bandwidth
+ self.price = price
+ self.driver = driver
+
+ def __repr__(self):
+ return (('<NodeSize: id=%s, name=%s, cpu=%s, ram=%s disk=%s bandwidth=%s '
+ 'price=%s driver=%s ...>')
+ % (self.id, self.name, self.cpu, self.ram, self.disk, self.bandwidth,
+ self.price, self.driver.name))
+
+class ElasticHostsBaseConnection(ConnectionUserAndKey):
+ """
+ Base connection class for the ElasticHosts driver
+ """
+
+ host = API_ENDPOINTS[DEFAULT_ENDPOINT]['host']
+ responseCls = ElasticHostsResponse
+
+ def add_default_headers(self, headers):
+ headers['Accept'] = 'application/json'
+ headers['Content-Type'] = 'application/json'
+
+ headers['Authorization'] = 'Basic %s' % (base64.b64encode('%s:%s' % (self.user_id, self.key)))
+
+ return headers
+
+class ElasticHostsBaseNodeDriver(NodeDriver):
+ """
+ Base ElasticHosts node driver
+ """
+
+ type = Provider.ELASTICHOSTS
+ name = 'ElasticHosts'
+ connectionCls = ElasticHostsBaseConnection
+
+ def reboot_node(self, node):
+ # Reboots the node
+ response = self.connection.request(action = '/servers/%s/reset' % (node.id),
+ method = 'POST')
+ return response.status == 204
+
+ def destroy_node(self, node):
+ # Kills the server immediately
+ response = self.connection.request(action = '/servers/%s/destroy' % (node.id),
+ method = 'POST')
+ return response.status == 204
+
+ def list_images(self, location=None):
+ # Returns a list of available pre-installed system drive images
+ images = []
+ for key, value in STANDARD_DRIVES.iteritems():
+ image = NodeImage(id = value['uuid'], name = value['description'], driver = self.connection.driver,
+ extra = {'size_gunzipped': value['size_gunzipped']})
+ images.append(image)
+
+ return images
+
+ def list_sizes(self, location=None):
+ sizes = []
+ for key, value in INSTANCE_TYPES.iteritems():
+ size = ElasticHostsNodeSize(id = value['id'], name = value['name'], cpu = value['cpu'], ram = value['memory'],
+ disk = value['disk'], bandwidth = value['bandwidth'], price = '',
+ driver = self.connection.driver)
+ sizes.append(size)
+
+ return sizes
+
+ def list_nodes(self):
+ # Returns a list of active (running) nodes
+ response = self.connection.request(action = '/servers/info').object
+
+ nodes = []
+ for data in response:
+ node = self._to_node(data)
+ nodes.append(node)
+
+ return nodes
+
+ def create_node(self, **kwargs):
+ """Creates a ElasticHosts instance
+
+ See L{NodeDriver.create_node} for more keyword args.
+
+ @keyword name: String with a name for this new node (required)
+ @type name: C{string}
+
+ @keyword smp: Number of virtual processors or None to calculate based on the cpu speed
+ @type smp: C{int}
+
+ @keyword nic_model: e1000, rtl8139 or virtio (is not specified, e1000 is used)
+ @type nic_model: C{string}
+
+ @keyword vnc_password: If not set, VNC access is disabled.
+ @type vnc_password: C{bool}
+ """
+ size = kwargs['size']
+ image = kwargs['image']
+ smp = kwargs.get('smp', 'auto')
+ nic_model = kwargs.get('nic_model', 'e1000')
+ vnc_password = kwargs.get('vnc_password', None)
+
+ if nic_model not in ['e1000', 'rtl8139', 'virtio']:
+ raise ElasticHostsException('Invalid NIC model specified')
+
+ # check that drive size is not smaller then pre installed image size
+
+ # First we create a drive with the specified size
+ drive_data = {}
+ drive_data.update({'name': kwargs['name'], 'size': '%sG' % (kwargs['size'].disk)})
+
+ response = self.connection.request(action = '/drives/create', data = json.dumps(drive_data),
+ method = 'POST').object
+
+ if not response:
+ raise ElasticHostsException('Drive creation failed')
+
+ drive_uuid = response['drive']
+
+ # Then we image the selected pre-installed system drive onto it
+ response = self.connection.request(action = '/drives/%s/image/%s/gunzip' % (drive_uuid, image.id),
+ method = 'POST')
+
+ if response.status != 204:
+ raise ElasticHostsException('Drive imaging failed')
+
+ # We wait until the drive is imaged and then boot up the node (in most cases, the imaging process
+ # shouldn't take longer then a few minutes)
+ response = self.connection.request(action = '/drives/%s/info' % (drive_uuid)).object
+ imaging_start = time.time()
+ while response.has_key('imaging'):
+ response = self.connection.request(action = '/drives/%s/info' % (drive_uuid)).object
+ elapsed_time = time.time() - imaging_start
+ if response.has_key('imaging') and elapsed_time >= IMAGING_TIMEOUT:
+ raise ElasticHostsException('Drive imaging timed out')
+ time.sleep(1)
+
+ node_data = {}
+ node_data.update({'name': kwargs['name'], 'cpu': size.cpu, 'mem': size.ram, 'ide:0:0': drive_uuid,
+ 'boot': 'ide:0:0'})
+ node_data.update({'nic:0:model': nic_model, 'nic:0:dhcp': 'auto'})
+
+ if vnc_password:
+ node_data.update({'vnc:ip': 'auto', 'vnc:password': vnc_password})
+
+ response = self.connection.request(action = '/servers/create', data = json.dumps(node_data),
+ method = 'POST').object
+
+ if isinstance(response, list):
+ nodes = [self._to_node(node) for node in response]
+ else:
+ nodes = self._to_node(response)
+
+ return nodes
+
+ # Extension methods
+ def ex_set_node_configuration(self, node, **kwargs):
+ # Changes the configuration of the running server
+ valid_keys = ('^name$', '^parent$', '^cpu$', '^smp$', '^mem$', '^boot$', '^nic:0:model$', '^nic:0:dhcp',
+ '^nic:1:model$', '^nic:1:vlan$', '^nic:1:mac$', '^vnc:ip$', '^vnc:password$', '^vnc:tls',
+ '^ide:[0-1]:[0-1](:media)?$', '^scsi:0:[0-7](:media)?$', '^block:[0-7](:media)?$')
+
+ invalid_keys = []
+ for key in kwargs.keys():
+ matches = False
+ for regex in valid_keys:
+ if re.match(regex, key):
+ matches = True
+ break
+ if not matches:
+ invalid_keys.append(key)
+
+ if invalid_keys:
+ raise ElasticHostsException('Invalid configuration key specified: %s' % (',' .join(invalid_keys)))
+
+ response = self.connection.request(action = '/servers/%s/set' % (node.id), data = json.dumps(kwargs),
+ method = 'POST')
+
+ return (response.status == 200 and response.body != '')
+
+ def ex_shutdown_node(self, node):
+ # Sends the ACPI power-down event
+ response = self.connection.request(action = '/servers/%s/shutdown' % (node.id),
+ method = 'POST')
+ return response.status == 204
+
+ def ex_destroy_drive(self, drive_uuid):
+ # Deletes a drive
+ response = self.connection.request(action = '/drives/%s/destroy' % (drive_uuid),
+ method = 'POST')
+ return response.status == 204
+
+ # Helper methods
+ def _to_node(self, data):
+ try:
+ state = NODE_STATE_MAP[data['status']]
+ except KeyError:
+ state = NodeState.UNKNOWN
+
+ if isinstance(data['nic:0:dhcp'], list):
+ public_ip = data['nic:0:dhcp']
+ else:
+ public_ip = [data['nic:0:dhcp']]
+
+ extra = {'cpu': data['cpu'], 'smp': data['smp'], 'mem': data['mem'], 'started': data['started']}
+
+ if data.has_key('vnc:ip') and data.has_key('vnc:password'):
+ extra.update({'vnc_ip': data['vnc:ip'], 'vnc_password': data['vnc:password']})
+
+ node = Node(id = data['server'], name = data['name'], state = state,
+ public_ip = public_ip, private_ip = None, driver = self.connection.driver,
+ extra = extra)
+
+ return node
+
+class ElasticHostsUK1Connection(ElasticHostsBaseConnection):
+ """
+ Connection class for the ElasticHosts driver for the London Peer 1 end-point
+ """
+
+ host = API_ENDPOINTS['uk-1']['host']
+
+class ElasticHostsUK1NodeDriver(ElasticHostsBaseNodeDriver):
+ """
+ ElasticHosts node driver for the London Peer 1 end-point
+ """
+ connectionCls = ElasticHostsUK1Connection
+
+class ElasticHostsUK2Connection(ElasticHostsBaseConnection):
+ """
+ Connection class for the ElasticHosts driver for the London Bluesquare end-point
+ """
+ host = API_ENDPOINTS['uk-2']['host']
+
+class ElasticHostsUK2NodeDriver(ElasticHostsBaseNodeDriver):
+ """
+ ElasticHosts node driver for the London Bluesquare end-point
+ """
+ connectionCls = ElasticHostsUK2Connection
+
+class ElasticHostsUS1Connection(ElasticHostsBaseConnection):
+ """
+ Connection class for the ElasticHosts driver for the San Antonio Peer 1 end-point
+ """
+ host = API_ENDPOINTS['us-1']['host']
+
+class ElasticHostsUS1NodeDriver(ElasticHostsBaseNodeDriver):
+ """
+ ElasticHosts node driver for the San Antonio Peer 1 end-point
+ """
+ connectionCls = ElasticHostsUS1Connection
+
+
Propchange: incubator/libcloud/trunk/libcloud/drivers/elastichosts.py
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/libcloud/trunk/libcloud/drivers/elastichosts.py
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: incubator/libcloud/trunk/libcloud/drivers/elastichosts.py
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: incubator/libcloud/trunk/libcloud/providers.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/providers.py?rev=985035&r1=985034&r2=985035&view=diff
==============================================================================
--- incubator/libcloud/trunk/libcloud/providers.py (original)
+++ incubator/libcloud/trunk/libcloud/providers.py Thu Aug 12 23:24:40 2010
@@ -29,6 +29,12 @@ DRIVERS = {
('libcloud.drivers.ec2', 'EC2USWestNodeDriver'),
Provider.ECP:
('libcloud.drivers.ecp', 'ECPNodeDriver'),
+ Provider.ELASTICHOSTS_UK1:
+ ('libcloud.drivers.elastichosts', 'ElasticHostsUK1NodeDriver'),
+ Provider.ELASTICHOSTS_UK2:
+ ('libcloud.drivers.elastichosts', 'ElasticHostsUK2NodeDriver'),
+ Provider.ELASTICHOSTS_US1:
+ ('libcloud.drivers.elastichosts', 'ElasticHostsUS1NodeDriver'),
Provider.GOGRID:
('libcloud.drivers.gogrid', 'GoGridNodeDriver'),
Provider.RACKSPACE:
Modified: incubator/libcloud/trunk/libcloud/types.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/types.py?rev=985035&r1=985034&r2=985035&view=diff
==============================================================================
--- incubator/libcloud/trunk/libcloud/types.py (original)
+++ incubator/libcloud/trunk/libcloud/types.py Thu Aug 12 23:24:40 2010
@@ -56,6 +56,10 @@ class Provider(object):
IBM = 15
OPENNEBULA = 16
DREAMHOST = 17
+ ELASTICHOSTS = 18
+ ELASTICHOSTS_UK1 = 19
+ ELASTICHOSTS_UK2 = 20
+ ELASTICHOSTS_US1 = 21
class NodeState(object):
"""
Added: incubator/libcloud/trunk/test/fixtures/elastichosts/drives_create.json
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/test/fixtures/elastichosts/drives_create.json?rev=985035&view=auto
==============================================================================
--- incubator/libcloud/trunk/test/fixtures/elastichosts/drives_create.json (added)
+++ incubator/libcloud/trunk/test/fixtures/elastichosts/drives_create.json Thu Aug 12 23:24:40 2010
@@ -0,0 +1,12 @@
+{
+ "drive": "0012e24a-6eae-4279-9912-3432f698cec8",
+ "encryption:cipher": "aes-xts-plain",
+ "name": "test drive",
+ "read:bytes": "4096",
+ "read:requests": "1",
+ "size": 10737418240,
+ "status": "active",
+ "user": "2164ce57-591c-43ee-ade5-e2fe0ee13c3e",
+ "write:bytes": "4096",
+ "write:requests": "1"
+}
\ No newline at end of file
Added: incubator/libcloud/trunk/test/fixtures/elastichosts/drives_info.json
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/test/fixtures/elastichosts/drives_info.json?rev=985035&view=auto
==============================================================================
--- incubator/libcloud/trunk/test/fixtures/elastichosts/drives_info.json (added)
+++ incubator/libcloud/trunk/test/fixtures/elastichosts/drives_info.json Thu Aug 12 23:24:40 2010
@@ -0,0 +1,12 @@
+{
+ "drive": "0012e24a-6eae-4279-9912-3432f698cec8",
+ "encryption:cipher": "aes-xts-plain",
+ "name": "test drive",
+ "read:bytes": "4096",
+ "read:requests": "1",
+ "size": 10737418240,
+ "status": "active",
+ "user": "2164ce57-591c-43ee-ade5-e2fe0ee13c3e",
+ "write:bytes": "4096",
+ "write:requests": "1"
+}
\ No newline at end of file
Added: incubator/libcloud/trunk/test/fixtures/elastichosts/servers_create.json
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/test/fixtures/elastichosts/servers_create.json?rev=985035&view=auto
==============================================================================
--- incubator/libcloud/trunk/test/fixtures/elastichosts/servers_create.json (added)
+++ incubator/libcloud/trunk/test/fixtures/elastichosts/servers_create.json Thu Aug 12 23:24:40 2010
@@ -0,0 +1,25 @@
+{
+ "boot": "ide:0:0",
+ "cpu": 2000,
+ "ide:0:0": "b6049e7a-aa1b-47f9-b21d-cdf2354e28d3",
+ "ide:0:0:read:bytes": "299696128",
+ "ide:0:0:read:requests": "73168",
+ "ide:0:0:write:bytes": "321044480",
+ "ide:0:0:write:requests": "78380",
+ "mem": 1024,
+ "name": "test api node",
+ "nic:0:block": "tcp/21 tcp/22 tcp/23 tcp/25",
+ "nic:0:dhcp": ["1.2.3.4", "1.2.3.5"],
+ "nic:0:model": "virtio",
+ "rx": 679560,
+ "rx:packets": 644,
+ "server": "b605ca90-c3e6-4cee-85f8-a8ebdf8f9903",
+ "smp": 1,
+ "started": 1280723696,
+ "status": "active",
+ "tx": 21271,
+ "tx:packets": "251",
+ "user": "2164ce57-591a-43ee-ade5-e2fe0ee13c3f",
+ "vnc:ip": "216.151.208.174",
+ "vnc:password": "testvncpass"
+}
\ No newline at end of file
Added: incubator/libcloud/trunk/test/fixtures/elastichosts/servers_info.json
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/test/fixtures/elastichosts/servers_info.json?rev=985035&view=auto
==============================================================================
--- incubator/libcloud/trunk/test/fixtures/elastichosts/servers_info.json (added)
+++ incubator/libcloud/trunk/test/fixtures/elastichosts/servers_info.json Thu Aug 12 23:24:40 2010
@@ -0,0 +1,27 @@
+[
+ {
+ "boot": "ide:0:0",
+ "cpu": 2000,
+ "ide:0:0": "b6049e7a-aa1b-47f9-b21d-cdf2354e28d3",
+ "ide:0:0:read:bytes": "299696128",
+ "ide:0:0:read:requests": "73168",
+ "ide:0:0:write:bytes": "321044480",
+ "ide:0:0:write:requests": "78380",
+ "mem": 1024,
+ "name": "test api node",
+ "nic:0:block": "tcp/21 tcp/22 tcp/23 tcp/25",
+ "nic:0:dhcp": ["1.2.3.4", "1.2.3.5"],
+ "nic:0:model": "virtio",
+ "rx": 679560,
+ "rx:packets": 644,
+ "server": "b605ca90-c3e6-4cee-85f8-a8ebdf8f9903",
+ "smp": 1,
+ "started": 1280723696,
+ "status": "active",
+ "tx": 21271,
+ "tx:packets": "251",
+ "user": "2164ce57-591a-43ee-ade5-e2fe0ee13c3f",
+ "vnc:ip": "216.151.208.174",
+ "vnc:password": "testvncpass"
+ }
+]
\ No newline at end of file
Added: incubator/libcloud/trunk/test/test_elastichosts.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/test/test_elastichosts.py?rev=985035&view=auto
==============================================================================
--- incubator/libcloud/trunk/test/test_elastichosts.py (added)
+++ incubator/libcloud/trunk/test/test_elastichosts.py Thu Aug 12 23:24:40 2010
@@ -0,0 +1,104 @@
+# 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+# Copyright 2009 RedRata Ltd
+
+import sys
+import unittest
+import httplib
+
+from libcloud.drivers.elastichosts import ElasticHostsBaseNodeDriver
+from test import MockHttp, TestCaseMixin
+from test.file_fixtures import FileFixtures
+
+class ElasticHostsTestCase(unittest.TestCase, TestCaseMixin):
+ def setUp(self):
+ ElasticHostsBaseNodeDriver.connectionCls.conn_classes = (None,
+ ElasticHostsHttp)
+ self.driver = ElasticHostsBaseNodeDriver('foo', 'bar')
+
+ def test_list_nodes(self):
+ nodes = self.driver.list_nodes()
+ self.assertTrue(isinstance(nodes, list))
+ self.assertEqual(len(nodes), 1)
+
+ node = nodes[0]
+ self.assertEqual(node.public_ip[0], "1.2.3.4")
+ self.assertEqual(node.public_ip[1], "1.2.3.5")
+ self.assertEqual(node.extra['smp'], 1)
+
+ def test_list_sizes(self):
+ images = self.driver.list_sizes()
+ self.assertEqual(len(images), 5)
+ image = images[0]
+ self.assertEqual(image.id, 'small')
+ self.assertEqual(image.name, 'Small instance')
+ self.assertEqual(image.cpu, 2000)
+ self.assertEqual(image.ram, 1700)
+ self.assertEqual(image.disk, 160)
+
+ def test_list_images(self):
+ sizes = self.driver.list_images()
+ self.assertEqual(len(sizes), 9)
+ size = sizes[0]
+ self.assertEqual(size.id, '757586d5-f1e9-4d9c-b215-5a391c9a24bf')
+ self.assertEqual(size.name, 'Ubuntu Linux 9.04: Base system with X')
+
+ def test_list_locations_response(self):
+ pass
+
+ def test_reboot_node(self):
+ node = self.driver.list_nodes()[0]
+ self.assertTrue(self.driver.reboot_node(node))
+
+ def test_destroy_node(self):
+ node = self.driver.list_nodes()[0]
+ self.assertTrue(self.driver.destroy_node(node))
+
+ def test_create_node(self):
+ size = self.driver.list_sizes()[0]
+ image = self.driver.list_images()[0]
+ self.assertTrue(self.driver.create_node(name="api.ivan.net.nz", image=image, size=size))
+
+class ElasticHostsHttp(MockHttp):
+
+ fixtures = FileFixtures('elastichosts')
+
+ def _servers_b605ca90_c3e6_4cee_85f8_a8ebdf8f9903_reset(self, method, url, body, headers):
+ return (httplib.NO_CONTENT, body, {}, httplib.responses[httplib.NO_CONTENT])
+
+ def _servers_b605ca90_c3e6_4cee_85f8_a8ebdf8f9903_destroy(self, method, url, body, headers):
+ return (httplib.NO_CONTENT, body, {}, httplib.responses[httplib.NO_CONTENT])
+
+ def _drives_create(self, method, url, body, headers):
+ body = self.fixtures.load('drives_create.json')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _drives_0012e24a_6eae_4279_9912_3432f698cec8_image_757586d5_f1e9_4d9c_b215_5a391c9a24bf_gunzip(self, method, url, body, headers):
+ return (httplib.NO_CONTENT, body, {}, httplib.responses[httplib.NO_CONTENT])
+
+ def _drives_0012e24a_6eae_4279_9912_3432f698cec8_info(self, method, url, body, headers):
+ body = self.fixtures.load('drives_info.json')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _servers_create(self, method, url, body, headers):
+ body = self.fixtures.load('servers_create.json')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _servers_info(self, method, url, body, headers):
+ body = self.fixtures.load('servers_info.json')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+if __name__ == '__main__':
+ sys.exit(unittest.main())
Propchange: incubator/libcloud/trunk/test/test_elastichosts.py
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/libcloud/trunk/test/test_elastichosts.py
------------------------------------------------------------------------------
svn:keywords = Date Revision Author HeadURL Id
Propchange: incubator/libcloud/trunk/test/test_elastichosts.py
------------------------------------------------------------------------------
svn:mime-type = text/plain