You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2011/10/15 23:22:57 UTC
svn commit: r1183722 - in /libcloud/trunk: libcloud/common/
libcloud/compute/ libcloud/compute/drivers/ test/compute/
test/compute/fixtures/openstack_v1.1/
Author: tomaz
Date: Sat Oct 15 21:22:57 2011
New Revision: 1183722
URL: http://svn.apache.org/viewvc?rev=1183722&view=rev
Log:
Add support for 1.1 API and many other improvements for the OpenStack driver.
This patch is part of LIBCLOUD-83. External contributors include Mike Nerone and
Brad Morgan.
Added:
libcloud/trunk/test/compute/fixtures/openstack_v1.1/
libcloud/trunk/test/compute/fixtures/openstack_v1.1/README
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_7.json
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_detail.json
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_13.json
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_detail.json
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_os_quota_sets_aTenantId.json
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers.json
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064.json
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064_updated_name_bob.json
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail.json
libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail_EMPTY.json
Modified:
libcloud/trunk/libcloud/common/base.py
libcloud/trunk/libcloud/compute/base.py
libcloud/trunk/libcloud/compute/drivers/openstack.py
libcloud/trunk/libcloud/compute/providers.py
libcloud/trunk/test/compute/test_openstack.py
libcloud/trunk/test/compute/test_rackspace.py
Modified: libcloud/trunk/libcloud/common/base.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/common/base.py?rev=1183722&r1=1183721&r2=1183722&view=diff
==============================================================================
--- libcloud/trunk/libcloud/common/base.py (original)
+++ libcloud/trunk/libcloud/common/base.py Sat Oct 15 21:22:57 2011
@@ -520,7 +520,8 @@ class BaseDriver(object):
connectionCls = ConnectionKey
- def __init__(self, key, secret=None, secure=True, host=None, port=None):
+ def __init__(self, key, secret=None, secure=True, host=None, port=None,
+ api_version=None):
"""
@keyword key: API key or username to used
@type key: str
@@ -537,6 +538,11 @@ class BaseDriver(object):
@keyword port: Override port used for connections.
@type port: int
+
+ @keyword api_version: Optional API version. Only used by drivers
+ which support multiple API versions.
+ @type api_version: str
+
"""
self.key = key
self.secret = secret
Modified: libcloud/trunk/libcloud/compute/base.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/base.py?rev=1183722&r1=1183721&r2=1183722&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/base.py (original)
+++ libcloud/trunk/libcloud/compute/base.py Sat Oct 15 21:22:57 2011
@@ -351,9 +351,11 @@ class NodeDriver(BaseDriver):
NODE_STATE_MAP = {}
- def __init__(self, key, secret=None, secure=True, host=None, port=None):
+ def __init__(self, key, secret=None, secure=True, host=None, port=None,
+ api_version=None):
super(NodeDriver, self).__init__(key=key, secret=secret, secure=secure,
- host=host, port=port)
+ host=host, port=port,
+ api_version=api_version)
def create_node(self, **kwargs):
"""Create a new node instance.
Modified: libcloud/trunk/libcloud/compute/drivers/openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/openstack.py?rev=1183722&r1=1183721&r2=1183722&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/openstack.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/openstack.py Sat Oct 15 21:22:57 2011
@@ -15,15 +15,21 @@
"""
OpenStack driver
"""
+
+try:
+ import simplejson as json
+except ImportError:
+ import json
+
import os
import base64
+import httplib
import warnings
from xml.etree import ElementTree as ET
-from xml.parsers.expat import ExpatError
-from libcloud.pricing import get_size_price, PRICING_DATA
+from libcloud.pricing import get_size_price
from libcloud.common.base import Response
from libcloud.common.types import MalformedResponseError
from libcloud.compute.types import NodeState, Provider
@@ -37,9 +43,38 @@ __all__ = [
'OpenStack_1_0_NodeDriver',
'OpenStack_1_0_SharedIpGroup',
'OpenStack_1_0_NodeIpAddresses',
+ 'OpenStack_1_1_Response',
+ 'OpenStack_1_1_Connection',
+ 'OpenStack_1_1_NodeDriver',
+ 'OpenStackDriver'
]
-class OpenStack_1_0_Response(Response):
+
+ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"
+
+OPENSTACK_NODE_STATE_MAP = {'BUILD': NodeState.PENDING,
+ 'REBUILD': NodeState.PENDING,
+ 'ACTIVE': NodeState.RUNNING,
+ 'SUSPENDED': NodeState.TERMINATED,
+ 'QUEUE_RESIZE': NodeState.PENDING,
+ 'PREP_RESIZE': NodeState.PENDING,
+ 'VERIFY_RESIZE': NodeState.RUNNING,
+ 'PASSWORD': NodeState.PENDING,
+ 'RESCUE': NodeState.PENDING,
+ 'REBUILD': NodeState.PENDING,
+ 'REBOOT': NodeState.REBOOTING,
+ 'HARD_REBOOT': NodeState.REBOOTING,
+ 'SHARE_IP': NodeState.PENDING,
+ 'SHARE_IP_NO_CONFIG': NodeState.PENDING,
+ 'DELETE_IP': NodeState.PENDING,
+ 'UNKNOWN': NodeState.UNKNOWN}
+
+DEFAULT_API_VERSION = '1.1'
+
+
+class OpenStack_Response(Response):
+
+ node_driver = None
def success(self):
i = int(self.status)
@@ -51,6 +86,9 @@ class OpenStack_1_0_Response(Response):
return content_type_value.find(content_type.lower()) > -1
def parse_body(self):
+ if self.status == httplib.NO_CONTENT or not self.body:
+ return None
+
if self.has_content_type('application/xml'):
try:
return ET.XML(self.body)
@@ -58,46 +96,40 @@ class OpenStack_1_0_Response(Response):
raise MalformedResponseError(
'Failed to parse XML',
body=self.body,
- driver=OpenStack_1_0_NodeDriver)
+ driver=self.node_driver)
+ elif self.has_content_type('application/json'):
+ try:
+ return json.loads(self.body)
+ except:
+ raise MalformedResponseError(
+ 'Failed to parse JSON',
+ body=self.body,
+ driver=self.node_driver)
else:
return self.body
def parse_error(self):
- # TODO: fixup; only uses response codes really!
- try:
- body = ET.XML(self.body)
- except:
- raise MalformedResponseError(
- "Failed to parse XML",
- body=self.body, driver=OpenStack_1_0_NodeDriver)
- try:
- text = "; ".join([err.text or ''
- for err in
- body.getiterator()
- if err.text])
- except ExpatError:
- text = self.body
- return '%s %s %s' % (self.status, self.error, text)
+ text = None
+ body = self.parse_body()
+ if self.has_content_type('application/xml'):
+ text = "; ".join([err.text or '' for err in body.getiterator()
+ if err.text])
+ elif self.has_content_type('application/json'):
+ text = ';'.join([fault_data['message'] for fault_data
+ in body.values()])
+ else:
+ # while we hope a response is always one of xml or json, we have
+ # seen html or text in the past, its not clear we can really do
+ # something to make it more readable here, so we will just pass
+ # it along as the whole response body in the text variable.
+ text = body
-class OpenStack_1_0_Connection(OpenStackBaseConnection):
+ return '%s %s %s' % (self.status, self.error, text)
- responseCls = OpenStack_1_0_Response
- _url_key = "server_url"
- XML_NAMESPACE = 'http://docs.rackspacecloud.com/servers/api/v1.0'
- def __init__(self, user_id, key, secure=True, host=None, port=None,
- ex_force_base_url=None,
- ex_force_auth_url=None,
- ex_force_auth_version=None):
- super(OpenStack_1_0_Connection, self).__init__(
- user_id, key, host=host, port=port,
- ex_force_base_url=ex_force_base_url,
- ex_force_auth_url=ex_force_auth_url,
- ex_force_auth_version=ex_force_auth_version)
- self.api_version = 'v1.0'
- self.accept_format = 'application/xml'
+class OpenStackComputeConnection(OpenStackBaseConnection):
def request(self, action, params=None, data='', headers=None,
method='GET'):
@@ -107,17 +139,106 @@ class OpenStack_1_0_Connection(OpenStack
params = {}
if method in ("POST", "PUT"):
- headers = {'Content-Type': 'application/xml; charset=UTF-8'}
+ headers = {'Content-Type': self.default_content_type}
+
if method == "GET":
params['cache-busting'] = os.urandom(8).encode('hex')
- return super(OpenStack_1_0_Connection, self).request(
+
+ return super(OpenStackComputeConnection, self).request(
action=action,
params=params, data=data,
method=method, headers=headers
)
-class OpenStack_1_0_NodeDriver(NodeDriver):
+class OpenStackNodeDriver(NodeDriver):
+
+ def __new__(cls, key, secret=None, secure=True, host=None, port=None,
+ api_version=DEFAULT_API_VERSION, **kwargs):
+ if cls is OpenStackNodeDriver:
+ if api_version == '1.0':
+ cls = OpenStack_1_0_NodeDriver
+ elif api_version == '1.1':
+ cls = OpenStack_1_1_NodeDriver
+ else:
+ raise NotImplementedError(
+ "No OpenStackNodeDriver found for API version %s" %
+ (api_version)
+ )
+ return super(OpenStackNodeDriver, cls).__new__(cls)
+
+ def _ex_connection_class_kwargs(self):
+ rv = {}
+ if self._ex_force_base_url:
+ rv['ex_force_base_url'] = self._ex_force_base_url
+ if self._ex_force_auth_url:
+ rv['ex_force_auth_url'] = self._ex_force_auth_url
+ if self._ex_force_auth_version:
+ rv['ex_force_auth_version'] = self._ex_force_auth_version
+ return rv
+
+ def list_nodes(self):
+ return self._to_nodes(self.connection.request('/servers/detail')
+ .object)
+
+ def list_sizes(self, location=None):
+ return self._to_sizes(self.connection.request('/flavors/detail')
+ .object)
+
+ def list_images(self, location=None, ex_only_active=True):
+ return self._to_images(self.connection.request('/images/detail')
+ .object, ex_only_active)
+
+ def ex_get_node_details(self, node_id):
+ # @TODO: Remove this if in 0.6
+ if isinstance(node_id, Node):
+ node_id = node_id.id
+
+ uri = '/servers/%s' % (node_id)
+ resp = self.connection.request(uri, method='GET')
+ if resp.status == httplib.NOT_FOUND:
+ return None
+
+ return self._to_node_from_obj(resp.object)
+
+ def destroy_node(self, node):
+ uri = '/servers/%s' % (node.id)
+ resp = self.connection.request(uri, method='DELETE')
+ # The OpenStack and Rackspace documentation both say this API will
+ # return a 204, but in-fact, everyone everywhere agrees it actually
+ # returns a 202, so we are going to accept either, and someday,
+ # someone will fix either the implementation or the documentation to
+ # agree.
+ return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED)
+
+ def ex_soft_reboot_node(self, node):
+ return self._reboot_node(node, reboot_type='SOFT')
+
+ def ex_hard_reboot_node(self, node):
+ return self._reboot_node(node, reboot_type='HARD')
+
+ def reboot_node(self, node):
+ return self._reboot_node(node, reboot_type='HARD')
+
+
+class OpenStack_1_0_Response(OpenStack_Response):
+
+ def __init__(self, *args, **kwargs):
+ # done because of a circular reference from
+ # NodeDriver -> Connection -> Response
+ self.node_driver = OpenStack_1_0_NodeDriver
+ super(OpenStack_1_0_Response, self).__init__(*args, **kwargs)
+
+
+class OpenStack_1_0_Connection(OpenStackComputeConnection):
+ responseCls = OpenStack_1_0_Response
+ _url_key = "server_url"
+ default_content_type = 'application/xml; charset=UTF-8'
+ accept_format = 'application/xml'
+ XML_NAMESPACE = 'http://docs.rackspacecloud.com/servers/api/v1.0'
+
+
+class OpenStack_1_0_NodeDriver(OpenStackNodeDriver):
"""
OpenStack node driver.
@@ -134,54 +255,17 @@ class OpenStack_1_0_NodeDriver(NodeDrive
features = {"create_node": ["generates_password"]}
- NODE_STATE_MAP = {'BUILD': NodeState.PENDING,
- 'REBUILD': NodeState.PENDING,
- 'ACTIVE': NodeState.RUNNING,
- 'SUSPENDED': NodeState.TERMINATED,
- 'QUEUE_RESIZE': NodeState.PENDING,
- 'PREP_RESIZE': NodeState.PENDING,
- 'VERIFY_RESIZE': NodeState.RUNNING,
- 'PASSWORD': NodeState.PENDING,
- 'RESCUE': NodeState.PENDING,
- 'REBUILD': NodeState.PENDING,
- 'REBOOT': NodeState.REBOOTING,
- 'HARD_REBOOT': NodeState.REBOOTING,
- 'SHARE_IP': NodeState.PENDING,
- 'SHARE_IP_NO_CONFIG': NodeState.PENDING,
- 'DELETE_IP': NodeState.PENDING,
- 'UNKNOWN': NodeState.UNKNOWN}
+ NODE_STATE_MAP = OPENSTACK_NODE_STATE_MAP
def __init__(self, *args, **kwargs):
self._ex_force_base_url = kwargs.pop('ex_force_base_url', None)
self._ex_force_auth_url = kwargs.pop('ex_force_auth_url', None)
self._ex_force_auth_version = kwargs.pop('ex_force_auth_version', None)
+ self._ex_force_api_version = str(kwargs.pop('ex_force_api_version',
+ None))
self.XML_NAMESPACE = self.connectionCls.XML_NAMESPACE
super(OpenStack_1_0_NodeDriver, self).__init__(*args, **kwargs)
- def _ex_connection_class_kwargs(self):
- rv = {}
- if self._ex_force_base_url:
- rv['ex_force_base_url'] = self._ex_force_base_url
- if self._ex_force_auth_url:
- rv['ex_force_auth_url'] = self._ex_force_auth_url
- if self._ex_force_auth_version:
- rv['ex_force_auth_version'] = self._ex_force_auth_version
- return rv
-
-
- def list_nodes(self):
- return self._to_nodes(self.connection.request('/servers/detail')
- .object)
-
- def list_sizes(self, location=None):
- return self._to_sizes(self.connection.request('/flavors/detail')
- .object)
-
- def list_images(self, location=None):
- return self._to_images(self.connection.request('/images/detail')
- .object)
- # TODO: def list_locations: Is there an OpenStack way to do this? Rackspace-specific docstring says no.
-
def _change_password_or_name(self, node, name=None, password=None):
uri = '/servers/%s' % (node.id)
@@ -264,6 +348,7 @@ class OpenStack_1_0_NodeDriver(NodeDrive
files_elm = self._files_to_xml(kwargs.get("ex_files", {}))
if files_elm:
server_elm.append(files_elm)
+
resp = self.connection.request("/servers",
method='POST',
data=ET.tostring(server_elm))
@@ -460,31 +545,6 @@ class OpenStack_1_0_NodeDriver(NodeDrive
resp = self._node_action(node, ['reboot', ('type', reboot_type)])
return resp.status == 202
- def ex_soft_reboot_node(self, node):
- return self._reboot_node(node, reboot_type='SOFT')
-
- def ex_hard_reboot_node(self, node):
- return self._reboot_node(node, reboot_type='HARD')
-
- def reboot_node(self, node):
- return self._reboot_node(node, reboot_type='HARD')
-
- def destroy_node(self, node):
- uri = '/servers/%s' % (node.id)
- resp = self.connection.request(uri, method='DELETE')
- return resp.status == 202
-
- def ex_get_node_details(self, node_id):
- # @TODO: Remove this if in 0.6
- if isinstance(node_id, Node):
- node_id = node_id.id
-
- uri = '/servers/%s' % (node_id)
- resp = self.connection.request(uri, method='GET')
- if resp.status == 404:
- return None
- return self._to_node(resp.object)
-
def _node_action(self, node, body):
if isinstance(body, list):
attr = ' '.join(['%s="%s"' % (item[0], item[1])
@@ -500,11 +560,15 @@ class OpenStack_1_0_NodeDriver(NodeDrive
def _fixxpath(self, xpath):
# ElementTree wants namespaces in its xpaths, so here we add them.
- return "/".join(["{%s}%s" % (self.XML_NAMESPACE, e) for e in xpath.split("/")])
+ return "/".join(["{%s}%s" % (self.XML_NAMESPACE, e) for e
+ in xpath.split("/")])
def _findall(self, element, xpath):
return element.findall(self._fixxpath(xpath))
+ def _to_node_from_obj(self, obj):
+ return self._to_node(self._findall(obj, 'server')[0])
+
def _to_node(self, el):
def get_ips(el):
return [ip.get('addr') for ip in el]
@@ -549,16 +613,21 @@ class OpenStack_1_0_NodeDriver(NodeDrive
name=el.get('name'),
ram=int(el.get('ram')),
disk=int(el.get('disk')),
- bandwidth=None, # XXX: needs hardcode
- price=self._get_size_price(el.get('id')), # Hardcoded,
+ # XXX: needs hardcode
+ bandwidth=None,
+ # Hardcoded
+ price=self._get_size_price(el.get('id')),
driver=self.connection.driver)
return s
- def _to_images(self, object):
+ def _to_images(self, object, ex_only_active):
elements = self._findall(object, "image")
- return [self._to_image(el)
- for el in elements
- if el.get('status') == 'ACTIVE']
+ rv = []
+ for el in elements:
+ if ex_only_active and el.get('status') != 'ACTIVE':
+ continue
+ rv.append(self._to_image(el))
+ return rv
def _to_image(self, el):
i = NodeImage(id=el.get('id'),
@@ -676,3 +745,262 @@ class OpenStack_1_0_NodeIpAddresses(obje
def __init__(self, public_addresses, private_addresses):
self.public_addresses = public_addresses
self.private_addresses = private_addresses
+
+
+class OpenStack_1_1_Response(OpenStack_Response):
+
+ def __init__(self, *args, **kwargs):
+ # done because of a circular reference from
+ # NodeDriver -> Connection -> Response
+ self.node_driver = OpenStack_1_1_NodeDriver
+ super(OpenStack_1_1_Response, self).__init__(*args, **kwargs)
+
+
+class OpenStack_1_1_Connection(OpenStackComputeConnection):
+ responseCls = OpenStack_1_1_Response
+ _url_key = "server_url"
+ accept_format = 'application/json'
+ default_content_type = 'application/json; charset=UTF-8'
+
+ def encode_data(self, data):
+ return json.dumps(data)
+
+
+class OpenStack_1_1_NodeDriver(OpenStackNodeDriver):
+ """
+ OpenStack node driver.
+ """
+ connectionCls = OpenStack_1_1_Connection
+ type = Provider.OPENSTACK
+ api_name = 'openstack'
+ name = 'OpenStack'
+
+ features = {"create_node": ["generates_password"]}
+
+ NODE_STATE_MAP = OPENSTACK_NODE_STATE_MAP
+
+ def __init__(self, *args, **kwargs):
+ self._ex_force_base_url = kwargs.pop('ex_force_base_url', None)
+ self._ex_force_auth_url = kwargs.pop('ex_force_auth_url', None)
+ self._ex_force_auth_version = kwargs.pop('ex_force_auth_version',
+ None)
+ self._ex_force_api_version = str(kwargs.pop('ex_force_api_version',
+ None))
+ super(OpenStack_1_1_NodeDriver, self).__init__(*args, **kwargs)
+
+ def _to_nodes(self, obj):
+ servers = obj['servers']
+ return [self._to_node(server) for server in servers]
+
+ def _to_sizes(self, obj):
+ flavors = obj['flavors']
+ return [self._to_size(flavor) for flavor in flavors]
+
+ def _to_images(self, obj, ex_only_active):
+ images = obj['images']
+ rv = []
+ for image in images:
+ if ex_only_active and image.get('status') != 'ACTIVE':
+ continue
+ rv.append(self._to_image(image))
+ return rv
+
+ def _create_args_to_params(self, node, kwargs):
+ server_params = {
+ 'name': kwargs.get('name'),
+ 'metadata': kwargs.get('ex_metadata', {}),
+ 'personality': self._files_to_personality(kwargs.get("ex_files",
+ {}))
+ }
+
+ if 'name' in kwargs:
+ server_params['name'] = kwargs.get('name')
+ else:
+ server_params['name'] = node.name
+
+ if 'image' in kwargs:
+ server_params['imageRef'] = kwargs.get('image').id
+ else:
+ server_params['imageRef'] = node.extra.get('imageId')
+
+ if 'size' in kwargs:
+ server_params['flavorRef'] = kwargs.get('size').id
+ else:
+ server_params['flavorRef'] = node.extra.get('flavorId')
+
+ return server_params
+
+ def create_node(self, **kwargs):
+ """Create a new node
+
+ See L{NodeDriver.create_node} for more keyword args.
+ @keyword ex_metadata: Key/Value metadata to associate with a node
+ @type ex_metadata: C{dict}
+
+ @keyword ex_files: File Path => File contents to create on
+ the node
+ @type ex_files: C{dict}
+ """
+
+ server_params = self._create_args_to_params(None, kwargs)
+
+ resp = self.connection.request("/servers",
+ method='POST',
+ data={'server': server_params})
+
+ return self._to_node(resp.object['server'])
+
+ def _files_to_personality(self, files):
+ rv = []
+
+ for k, v in files.items():
+ rv.append({'path': k, 'contents': base64.b64encode(v)})
+
+ return rv
+
+ def _reboot_node(self, node, reboot_type='SOFT'):
+ resp = self._node_action(node, 'reboot', type=reboot_type)
+ return resp.status == httplib.ACCEPTED
+
+ def ex_set_password(self, node, password):
+ resp = self._node_action(node, 'changePassword', adminPass=password)
+ node.extra['password'] = password
+ return resp.status == httplib.ACCEPTED
+
+ def ex_rebuild(self, node, **kwargs):
+ server_params = self._create_args_to_params(node, kwargs)
+ resp = self._node_action(node, 'rebuild', **server_params)
+ return resp.status == httplib.ACCEPTED
+
+ def ex_resize(self, node, size):
+ resp = self._node_action(node, 'resize', flavorRef=size.id)
+ return resp.status == httplib.ACCEPTED
+
+ def ex_confirm_resize(self, node):
+ resp = self._node_action(node, 'confirmResize')
+ return resp.status == httplib.NO_CONTENT
+
+ def ex_revert_resize(self, node):
+ resp = self._node_action(node, 'revertResize')
+ return resp.status == httplib.ACCEPTED
+
+ def ex_save_image(self, node, name, metadata=None):
+ # This has not yet been implemented by OpenStack 1.1
+ raise NotImplementedError()
+
+ optional_params = {}
+ if metadata:
+ optional_params['metadata'] = metadata
+ resp = self._node_action(node, 'createImage', name=name,
+ **optional_params)
+ # TODO: concevt location header into NodeImage object
+ return resp.status == httplib.NO_CONTENT
+
+ def ex_set_server_name(self, node, name):
+ """
+ Sets the Node's name.
+ """
+ return self.ex_update_node(node, name=name)
+
+ def ex_update_node(self, node, **node_updates):
+ # Currently only setting the name is supported in OpenStack, but we
+ # leave the function signature prepared to support metadata or other
+ # fields in the future.
+ potential_data = self._create_args_to_params(node, node_updates)
+ return self._to_node(
+ self.connection.request(
+ '/servers/%s' % (node.id,), method='PUT',
+ data={'server': {'name': potential_data['name']}}
+ ).object['server']
+ )
+
+ def ex_get_size(self, size_id):
+ return self._to_size(self.connection.request('/flavors/%s' %
+ (size_id,))
+ .object['flavor'])
+
+ def ex_get_image(self, image_id):
+ return self._to_image(self.connection.request('/images/%s' %
+ (image_id,))
+ .object['image'])
+
+ def ex_delete_image(self, image):
+ # This has not yet been implemented by OpenStack 1.1
+ raise NotImplementedError()
+
+ resp = self.connection.request('/images/%s' % (image.id,),
+ method='DELETE')
+ return resp.status == httplib.ACCEPTED
+
+ def _node_action(self, node, action, **params):
+ params = params or None
+ return self.connection.request('/servers/%s/action' % (node.id,),
+ method='POST', data={action: params})
+
+ def _to_node_from_obj(self, obj):
+ return self._to_node(obj['server'])
+
+ def _to_node(self, api_node):
+ return Node(
+ id=api_node['id'],
+ name=api_node['name'],
+ state=self.NODE_STATE_MAP.get(api_node['status'],
+ NodeState.UNKNOWN),
+ public_ip=[addr_desc['addr'] for addr_desc in
+ api_node['addresses'].get('public', [])],
+ private_ip=[addr_desc['addr'] for addr_desc in
+ api_node['addresses'].get('private', [])],
+ driver=self,
+ extra=dict(
+ hostId=api_node['hostId'],
+ # Docs says "tenantId", but actual is "tenant_id". *sigh*
+ # Best handle both.
+ tenantId=api_node.get('tenant_id') or api_node['tenantId'],
+ imageId=api_node['image']['id'],
+ flavorId=api_node['flavor']['id'],
+ uri=(link['href'] for link in api_node['links'] if
+ link['rel'] == 'self').next(),
+ metadata=api_node['metadata'],
+ password=api_node.get('adminPass'),
+ ),
+ )
+
+ def _to_size(self, api_flavor, price=None, bandwidth=None):
+ # if provider-specific subclasses can get better values for
+ # price/bandwidth, then can pass them in when they super().
+ if not price:
+ price = self._get_size_price(str(api_flavor['id']))
+
+ return NodeSize(
+ id=api_flavor['id'],
+ name=api_flavor['name'],
+ ram=api_flavor['ram'],
+ disk=api_flavor['disk'],
+ bandwidth=bandwidth,
+ price=price,
+ driver=self,
+ )
+
+ def _to_image(self, api_image):
+ return NodeImage(
+ id=api_image['id'],
+ name=api_image['name'],
+ driver=self,
+ extra=dict(
+ updated=api_image['updated'],
+ created=api_image['created'],
+ status=api_image['status'],
+ progress=api_image.get('progress'),
+ metadata=api_image.get('metadata'),
+ ),
+ )
+
+ def _get_size_price(self, size_id):
+ try:
+ return get_size_price(
+ driver_type='compute',
+ driver_name=self.api_name,
+ size_id=size_id,
+ )
+ except KeyError:
+ return(0.0)
Modified: libcloud/trunk/libcloud/compute/providers.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/providers.py?rev=1183722&r1=1183721&r2=1183722&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/providers.py (original)
+++ libcloud/trunk/libcloud/compute/providers.py Sat Oct 15 21:22:57 2011
@@ -88,7 +88,7 @@ DRIVERS = {
Provider.OPSOURCE:
('libcloud.compute.drivers.opsource', 'OpsourceNodeDriver'),
Provider.OPENSTACK:
- ('libcloud.compute.drivers.openstack', 'OpenStack_1_0_NodeDriver'),
+ ('libcloud.compute.drivers.openstack', 'OpenStackNodeDriver'),
Provider.NINEFOLD:
('libcloud.compute.drivers.ninefold', 'NinefoldNodeDriver'),
}
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/README
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/README?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/README (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/README Sat Oct 15 21:22:57 2011
@@ -0,0 +1,7 @@
+The json responses contained in this directory are copied directly from the
+OpenStack 1.1 documentation at
+http://docs.openstack.org/trunk/openstack-compute/developer/openstack-compute-api-1.1/
+as of this writing.
+
+The only exception is _os_quota_sets_aTenantId.json, which was captured (and
+perturbed) via packet capture.
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_7.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_7.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_7.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_7.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1 @@
+{"flavor": {"rxtx_quota": 2500, "name": "15.5GB slice", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/flavors/7", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/7", "rel": "bookmark"}], "ram": 16384, "vcpus": 8, "rxtx_cap": 200, "swap": 0, "disk": 620, "id": 7}}
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_detail.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_detail.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_detail.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_flavors_detail.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1 @@
+{"flavors": [{"rxtx_quota": 2500, "name": "15.5GB slice", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/flavors/7", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/7", "rel": "bookmark"}], "ram": 16384, "vcpus": 8, "rxtx_cap": 200, "swap": 0, "disk": 620, "id": 7}, {"rxtx_quota": 600, "name": "1GB slice", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/flavors/3", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/3", "rel": "bookmark"}], "ram": 1024, "vcpus": 1, "rxtx_cap": 30, "swap": 0, "disk": 40, "id": 3}, {"rxtx_quota": 150, "name": "256 slice", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/flavors/1", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/1", "rel": "boo
kmark"}], "ram": 256, "vcpus": 1, "rxtx_cap": 10, "swap": 0, "disk": 10, "id": 1}, {"rxtx_quota": 1200, "name": "2GB slice", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/flavors/4", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/4", "rel": "bookmark"}], "ram": 2048, "vcpus": 2, "rxtx_cap": 60, "swap": 0, "disk": 80, "id": 4}, {"rxtx_quota": 2500, "name": "30GB slice", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/flavors/8", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/8", "rel": "bookmark"}], "ram": 30720, "vcpus": 8, "rxtx_cap": 400, "swap": 0, "disk": 1200, "id": 8}, {"rxtx_quota": 2500, "name": "4GB slice", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/flavors/5", "rel": "self"}, {"href": "http://alpha.ord.serve
rs.api.rackspacecloud.com:8774/rs-reach-project/flavors/5", "rel": "bookmark"}], "ram": 4096, "vcpus": 2, "rxtx_cap": 100, "swap": 0, "disk": 160, "id": 5}, {"rxtx_quota": 300, "name": "512 slice", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/flavors/2", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/2", "rel": "bookmark"}], "ram": 512, "vcpus": 1, "rxtx_cap": 20, "swap": 0, "disk": 20, "id": 2}, {"rxtx_quota": 2500, "name": "8GB slice", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/flavors/6", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/6", "rel": "bookmark"}], "ram": 8192, "vcpus": 4, "rxtx_cap": 150, "swap": 0, "disk": 320, "id": 6}]}
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_13.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_13.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_13.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_13.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1 @@
+{"image": {"status": "ACTIVE", "updated": "2011-08-06T18:14:02Z", "name": "Windows 2008 SP2 x86 (B24)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/13", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/13", "rel": "bookmark"}, {"href": "http://10.13.136.245:9292/rs-reach-project/images/13", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-06T18:13:11Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "13", "metadata": {"os_type": "windows"}}}
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_detail.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_detail.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_detail.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_images_detail.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1 @@
+{"images": [{"status": "ACTIVE", "updated": "2011-08-06T18:14:02Z", "name": "Windows 2008 SP2 x86 (B24)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/13", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/13", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/13", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-06T18:13:11Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "13", "metadata": {"os_type": "windows"}}, {"status": "ACTIVE", "updated": "2011-08-06T18:13:11Z", "name": "Windows 2003 R2 x86 (B24)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/12", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/12", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/12
", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-06T18:12:33Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "12", "metadata": {"os_type": "windows"}}, {"status": "ACTIVE", "updated": "2011-08-06T16:27:56Z", "name": "Windows 2008 SP2 x64 (B24)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/11", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/11", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/11", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-06T16:26:15Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "11", "metadata": {"os_type": "windows"}}, {"status": "ACTIVE", "updated": "2011-08-06T16:26:14Z", "name": "Windows 2008 R2 x64 (B24)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/10", "rel":
"self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/10", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/10", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-06T16:24:51Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "10", "metadata": {"os_type": "windows"}}, {"status": "ACTIVE", "updated": "2011-08-06T16:24:51Z", "name": "Windows 2003 R2 x64 (B24)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/9", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/9", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/9", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-06T16:23:52Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "9", "metadata": {"os_type": "windows"}}, {"status": "ACTIVE", "updat
ed": "2011-08-05T22:58:29Z", "name": "Ubuntu Natty (11.04)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/8", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/8", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/8", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-05T22:58:20Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "8", "metadata": {}}, {"status": "ACTIVE", "updated": "2011-08-05T22:58:19Z", "name": "Ubuntu Lucid (10.04)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/7", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/7", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/7", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created"
: "2011-08-05T22:58:14Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "7", "metadata": {}}, {"status": "ACTIVE", "updated": "2011-08-05T22:58:14Z", "name": "Fedora 15", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/6", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/6", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/6", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-05T22:58:01Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "6", "metadata": {}}, {"status": "ACTIVE", "updated": "2011-08-05T22:58:00Z", "name": "Fedora 14", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/5", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/5", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292
/rs-reach-project/images/5", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-05T22:57:47Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "5", "metadata": {}}, {"status": "ACTIVE", "updated": "2011-08-05T22:57:47Z", "name": "Debian Squeeze (6.0)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/4", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/4", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/4", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-05T22:57:41Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "4", "metadata": {}}, {"status": "ACTIVE", "updated": "2011-08-05T22:57:40Z", "name": "Debian Lenny (5.0)", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/3", "rel": "self"}, {"href": "http://alpha.
ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/3", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/3", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-05T22:57:30Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "3", "metadata": {}}, {"status": "ACTIVE", "updated": "2011-08-05T22:57:30Z", "name": "CentOS 6.0", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/2", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/2", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/2", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-05T22:57:20Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "2", "metadata": {}}, {"status": "ACTIVE", "updated": "2011-08-05T22:56:20Z", "name": "CentOS 5.6", "links": [{"href": "http://alpha.ord.ser
vers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/images/1", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/1", "rel": "bookmark"}, {"href": "http://10.13.136.170:9292/rs-reach-project/images/1", "type": "application/vnd.openstack.image", "rel": "alternate"}], "created": "2011-08-05T22:56:03Z", "minDisk": 0, "progress": 100, "minRam": 0, "id": "1", "metadata": {}}]}
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_os_quota_sets_aTenantId.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_os_quota_sets_aTenantId.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_os_quota_sets_aTenantId.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_os_quota_sets_aTenantId.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1 @@
+{"quota_set": {"metadata_items": 10, "injected_file_content_bytes": 1000, "injected_files": 10, "volumes": 0, "instances": 25, "gigabytes": 500, "cores": 50, "ram": 102400, "id": "aTenantId", "floating_ips": 10}}
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1,78 @@
+{
+ "server": {
+ "id": "52415800-8b69-11e0-9b19-734f565bc83b",
+ "tenantId": "1234",
+ "userId": "5678",
+ "name": "new-server-test",
+ "created": "2010-11-11T12:00:00Z",
+ "hostId": "e4d909c290d0fb1ca068ffaddf22cbd0",
+ "accessIPv4" : "67.23.10.138",
+ "accessIPv6" : "::babe:67.23.10.138",
+ "progress": 0,
+ "status": "BUILD",
+ "adminPass": "GFf1j9aP",
+ "image" : {
+ "id": "52415800-8b69-11e0-9b19-734f6f006e54",
+ "name": "CentOS 5.2",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f6f006e54"
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f6f006e54"
+ }
+ ]
+ },
+ "flavor" : {
+ "id": "52415800-8b69-11e0-9b19-734f1195ff37",
+ "name": "256 MB Server",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://servers.api.openstack.org/v1.1/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37"
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f1195ff37"
+ }
+ ]
+ },
+ "metadata": {
+ "My Server Name": "Apache1"
+ },
+ "addresses": {
+ "public" : [
+ {
+ "version": 4,
+ "addr": "67.23.10.138"
+ },
+ {
+ "version": 6,
+ "addr": "::babe:67.23.10.138"
+ }
+ ],
+ "private" : [
+ {
+ "version": 4,
+ "addr": "10.176.42.19"
+ },
+ {
+ "version": 6,
+ "addr": "::babe:10.176.42.19"
+ }
+ ]
+ },
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://servers.api.openstack.org/v1.1/1234/servers/52415800-8b69-11e0-9b19-734fcece0043"
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://servers.api.openstack.org/1234/servers/52415800-8b69-11e0-9b19-734fcece0043"
+ }
+ ]
+ }
+}
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1 @@
+{"server": {"status": "ACTIVE", "updated": "2011-10-11T00:44:20Z", "hostId": "a024053a6201e6c6c12660aab3d8fd879e332e663a5e1fdbc02a0307", "user_id": "rs-reach", "name": "lc-test", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/servers/12064", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/servers/12064", "rel": "bookmark"}], "addresses": {"public": [{"version": 4, "addr": "50.57.94.30"}, {"version": 6, "addr": "2001:4801:7808:52:16:3eff:fe77:32e3"}], "private": [{"version": 4, "addr": "10.182.64.29"}, {"version": 6, "addr": "fec0:4801:7808:52:16:3eff:fe6e:b7e2"}]}, "tenant_id": "rs-reach-project", "image": {"id": "7", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/7", "rel": "bookmark"}]}, "created": "2011-10-11T00:45:02Z", "uuid": "ec53630b-e4fb-442a-a748-c376f5c4345b", "accessIPv4": "", "accessIPv6": "", "key_name": null, "progre
ss": 100, "flavor": {"id": "2", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/2", "rel": "bookmark"}]}, "config_drive": "", "id": 12064, "metadata": {}}}
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064_updated_name_bob.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064_updated_name_bob.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064_updated_name_bob.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_12064_updated_name_bob.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1 @@
+{"server": {"status": "ACTIVE", "updated": "2011-10-11T01:22:04Z", "hostId": "a024053a6201e6c6c12660aab3d8fd879e332e663a5e1fdbc02a0307", "user_id": "rs-reach", "name": "Bob", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/servers/12064", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/servers/12064", "rel": "bookmark"}], "addresses": {"public": [{"version": 4, "addr": "50.57.94.30"}, {"version": 6, "addr": "2001:4801:7808:52:16:3eff:fe77:32e3"}], "private": [{"version": 4, "addr": "10.182.64.29"}, {"version": 6, "addr": "fec0:4801:7808:52:16:3eff:fe6e:b7e2"}]}, "tenant_id": "rs-reach-project", "image": {"id": "7", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/7", "rel": "bookmark"}]}, "created": "2011-10-11T00:45:02Z", "uuid": "ec53630b-e4fb-442a-a748-c376f5c4345b", "accessIPv4": "", "accessIPv6": "", "key_name": null, "progress":
100, "flavor": {"id": "2", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/2", "rel": "bookmark"}]}, "config_drive": "", "id": 12064, "metadata": {}}}
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1 @@
+{"servers": [{"status": "BUILD", "updated": "2011-10-11T00:50:04Z", "hostId": "912566d83a13fbb357ea3f13c629363d9f7e1ba3f925b49f3d2ab725", "user_id": "rs-reach", "name": "lc-test-2", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/servers/12065", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/servers/12065", "rel": "bookmark"}], "addresses": {"public": [{"version": 4, "addr": "50.57.94.35"}, {"version": 6, "addr": "2001:4801:7808:52:16:3eff:fe47:788a"}], "private": [{"version": 4, "addr": "10.182.64.34"}, {"version": 6, "addr": "fec0:4801:7808:52:16:3eff:fe60:187d"}]}, "tenant_id": "rs-reach-project", "image": {"id": "7", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/images/7", "rel": "bookmark"}]}, "created": "2011-10-11T00:51:39Z", "uuid": "02786501-714e-40af-8342-9c17eccb166d", "accessIPv4": "", "accessIPv6": "", "key_name": null, "pro
gress": 25, "flavor": {"id": "2", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/2", "rel": "bookmark"}]}, "config_drive": "", "id": 12065, "metadata": {}}, {"status": "ACTIVE", "updated": "2011-10-11T00:44:20Z", "hostId": "a024053a6201e6c6c12660aab3d8fd879e332e663a5e1fdbc02a0307", "user_id": "rs-reach", "name": "lc-test", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/v1.1/rs-reach-project/servers/12064", "rel": "self"}, {"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/servers/12064", "rel": "bookmark"}], "addresses": {"public": [{"version": 4, "addr": "50.57.94.30"}, {"version": 6, "addr": "2001:4801:7808:52:16:3eff:fe77:32e3"}], "private": [{"version": 4, "addr": "10.182.64.29"}, {"version": 6, "addr": "fec0:4801:7808:52:16:3eff:fe6e:b7e2"}]}, "tenant_id": "rs-reach-project", "image": {"id": "7", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:87
74/rs-reach-project/images/7", "rel": "bookmark"}]}, "created": "2011-10-11T00:45:02Z", "uuid": "ec53630b-e4fb-442a-a748-c376f5c4345b", "accessIPv4": "", "accessIPv6": "", "key_name": null, "progress": 100, "flavor": {"id": "2", "links": [{"href": "http://alpha.ord.servers.api.rackspacecloud.com:8774/rs-reach-project/flavors/2", "rel": "bookmark"}]}, "config_drive": "", "id": 12064, "metadata": {}}]}
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail_EMPTY.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail_EMPTY.json?rev=1183722&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail_EMPTY.json (added)
+++ libcloud/trunk/test/compute/fixtures/openstack_v1.1/_servers_detail_EMPTY.json Sat Oct 15 21:22:57 2011
@@ -0,0 +1,3 @@
+{
+ "servers": []
+}
Modified: libcloud/trunk/test/compute/test_openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/test_openstack.py?rev=1183722&r1=1183721&r2=1183722&view=diff
==============================================================================
--- libcloud/trunk/test/compute/test_openstack.py (original)
+++ libcloud/trunk/test/compute/test_openstack.py Sat Oct 15 21:22:57 2011
@@ -17,7 +17,12 @@ import unittest
import httplib
from libcloud.common.types import InvalidCredsError, MalformedResponseError
-from libcloud.compute.drivers.rackspace import OpenStack_1_0_NodeDriver, OpenStack_1_0_Response
+from libcloud.compute.types import Provider
+from libcloud.compute.providers import get_driver
+from libcloud.compute.drivers.openstack import (
+ OpenStack_1_0_NodeDriver, OpenStack_1_0_Response,
+ OpenStack_1_1_NodeDriver
+)
from libcloud.compute.base import Node, NodeImage, NodeSize
from libcloud.pricing import set_pricing, clear_pricing_data
@@ -28,18 +33,18 @@ from test.compute import TestCaseMixin
from test.secrets import OPENSTACK_PARAMS
-class OpenStackResponseTestCase(unittest.TestCase):
+class OpenStack_1_0_ResponseTestCase(unittest.TestCase):
XML = """<?xml version="1.0" encoding="UTF-8"?><root/>"""
def test_simple_xml_content_type_handling(self):
- http_response = MockResponse(200, OpenStackResponseTestCase.XML, headers={'content-type': 'application/xml'})
+ http_response = MockResponse(200, OpenStack_1_0_ResponseTestCase.XML, headers={'content-type': 'application/xml'})
body = OpenStack_1_0_Response(http_response, None).parse_body()
self.assertTrue(hasattr(body, 'tag'), "Body should be parsed as XML")
def test_extended_xml_content_type_handling(self):
http_response = MockResponse(200,
- OpenStackResponseTestCase.XML,
+ OpenStack_1_0_ResponseTestCase.XML,
headers={'content-type': 'application/xml; charset=UTF-8'})
body = OpenStack_1_0_Response(http_response, None).parse_body()
@@ -54,19 +59,22 @@ class OpenStackResponseTestCase(unittest
self.assertEqual(body, RESPONSE_BODY, "Non-XML body should be returned as is")
-class OpenStackTests(unittest.TestCase, TestCaseMixin):
+class OpenStack_1_0_Tests(unittest.TestCase, TestCaseMixin):
should_list_locations = False
- driver_type = OpenStack_1_0_NodeDriver
+ driver_klass = OpenStack_1_0_NodeDriver
driver_args = OPENSTACK_PARAMS
+ driver_kwargs = {}
@classmethod
def create_driver(self):
- return self.driver_type(*self.driver_args)
+ if self is not OpenStack_1_0_FactoryMethodTests:
+ self.driver_type = self.driver_klass
+ return self.driver_type(*self.driver_args, **self.driver_kwargs)
def setUp(self):
- self.driver_type.connectionCls.conn_classes = (OpenStackMockHttp, OpenStackMockHttp)
- self.driver_type.connectionCls.auth_url = "https://auth.api.example.com/v1.1/"
+ self.driver_klass.connectionCls.conn_classes = (OpenStackMockHttp, OpenStackMockHttp)
+ self.driver_klass.connectionCls.auth_url = "https://auth.api.example.com/v1.1/"
OpenStackMockHttp.type = None
self.driver = self.create_driver()
clear_pricing_data()
@@ -287,7 +295,7 @@ class OpenStackTests(unittest.TestCase,
if self.driver.api_name != 'openstack':
return
- pricing = dict((str(i), i) for i in range(1, 9))
+ pricing = dict((str(i), i) for i in range(1, 8))
set_pricing(driver_type='compute', driver_name='openstack',
pricing=pricing)
@@ -301,6 +309,22 @@ class OpenStackTests(unittest.TestCase,
self.assertEqual(float(size.price), float(pricing[size.id]))
+class OpenStack_1_0_FactoryMethodTests(OpenStack_1_0_Tests):
+ should_list_locations = False
+
+ driver_klass = OpenStack_1_0_NodeDriver
+ driver_type = get_driver(Provider.OPENSTACK)
+ driver_args = OPENSTACK_PARAMS + ('1.0',)
+
+ def test_factory_method_invalid_version(self):
+ try:
+ self.driver_type(*(OPENSTACK_PARAMS + ('15.5',)))
+ except NotImplementedError:
+ pass
+ else:
+ self.fail('Exception was not thrown')
+
+
class OpenStackMockHttp(MockHttpTestCase):
fixtures = ComputeFileFixtures('openstack')
auth_fixtures = OpenStackFixtures()
@@ -341,14 +365,14 @@ class OpenStackMockHttp(MockHttpTestCase
def _v1_0_slug_images_333111(self, method, url, body, headers):
if method != "DELETE":
- raise NotImplemented
+ raise NotImplementedError()
# this is currently used for deletion of an image
# as such it should not accept GET/POST
return(httplib.NO_CONTENT,"","",httplib.responses[httplib.NO_CONTENT])
def _v1_0_slug_images(self, method, url, body, headers):
if method != "POST":
- raise NotImplemented
+ raise NotImplementedError()
# this is currently used for creation of new image with
# POST request, don't handle GET to avoid possible confusion
body = self.fixtures.load('v1_slug_images_post.xml')
@@ -375,7 +399,7 @@ class OpenStackMockHttp(MockHttpTestCase
def _v1_0_slug_servers_72258_action(self, method, url, body, headers):
if method != "POST" or body[:8] != "<reboot ":
- raise NotImplemented
+ raise NotImplementedError()
# only used by reboot() right now, but we will need to parse body someday !!!!
return (httplib.ACCEPTED, "", {}, httplib.responses[httplib.ACCEPTED])
@@ -385,7 +409,7 @@ class OpenStackMockHttp(MockHttpTestCase
def _v1_0_slug_servers_72258(self, method, url, body, headers):
if method != "DELETE":
- raise NotImplemented
+ raise NotImplementedError()
# only used by destroy node()
return (httplib.ACCEPTED, "", {}, httplib.responses[httplib.ACCEPTED])
@@ -395,7 +419,7 @@ class OpenStackMockHttp(MockHttpTestCase
def _v1_0_slug_shared_ip_groups_5467(self, method, url, body, headers):
if method != 'DELETE':
- raise NotImplemented
+ raise NotImplementedError()
return (httplib.NO_CONTENT, "", {}, httplib.responses[httplib.NO_CONTENT])
def _v1_0_slug_shared_ip_groups(self, method, url, body, headers):
@@ -443,6 +467,260 @@ class OpenStackMockHttp(MockHttpTestCase
def _v1_1__auth_INTERNAL_SERVER_ERROR(self, method, url, body, headers):
return (httplib.INTERNAL_SERVER_ERROR, "<h1>500: Internal Server Error</h1>", {'content-type': 'text/html'}, httplib.responses[httplib.INTERNAL_SERVER_ERROR])
+class OpenStack_1_1_Tests(unittest.TestCase, TestCaseMixin):
+ should_list_locations = False
+
+ driver_klass = OpenStack_1_1_NodeDriver
+ driver_type = OpenStack_1_1_NodeDriver
+ driver_args = OPENSTACK_PARAMS
+ driver_kwargs = {'ex_force_auth_version': '1.0'}
+
+ @classmethod
+ def create_driver(self):
+ if self is not OpenStack_1_1_FactoryMethodTests:
+ self.driver_type = self.driver_klass
+ return self.driver_type(*self.driver_args, **self.driver_kwargs)
+
+ def setUp(self):
+ self.driver_klass.connectionCls.conn_classes = (OpenStack_1_1_MockHttp, OpenStack_1_1_MockHttp)
+ self.driver_klass.connectionCls.auth_url = "https://auth.api.example.com/v1.0/"
+ OpenStack_1_1_MockHttp.type = None
+ self.driver = self.create_driver()
+ clear_pricing_data()
+ self.node = self.driver.list_nodes()[1]
+
+ def test_list_nodes(self):
+ nodes = self.driver.list_nodes()
+ self.assertEqual(len(nodes), 2)
+ node = nodes[0]
+
+ self.assertEqual('12065', node.id)
+ self.assertEqual('50.57.94.35', node.public_ip[0])
+ self.assertEqual('2001:4801:7808:52:16:3eff:fe47:788a', node.public_ip[1])
+ self.assertEqual('10.182.64.34', node.private_ip[0])
+ self.assertEqual('fec0:4801:7808:52:16:3eff:fe60:187d', node.private_ip[1])
+
+ self.assertEqual(node.extra.get('flavorId'), '2')
+ self.assertEqual(node.extra.get('imageId'), '7')
+ self.assertEqual(node.extra.get('metadata'), {})
+
+ def test_list_sizes(self):
+ sizes = self.driver.list_sizes()
+ self.assertEqual(len(sizes), 8, 'Wrong sizes count')
+
+ for size in sizes:
+ self.assertTrue(isinstance(size.price, float),
+ 'Wrong size price type')
+ self.assertEqual(size.price, 0,
+ 'Size price should be zero by default')
+
+ def test_list_sizes_with_specified_pricing(self):
+
+ pricing = dict((str(i), i*5.0) for i in range(1, 9))
+
+ set_pricing(driver_type='compute', driver_name='openstack', pricing=pricing)
+
+ sizes = self.driver.list_sizes()
+ self.assertEqual(len(sizes), 8, 'Wrong sizes count')
+
+ for size in sizes:
+ self.assertTrue(isinstance(size.price, float),
+ 'Wrong size price type')
+ self.assertEqual(size.price, pricing[size.id],
+ 'Size price should match')
+
+ def test_list_images(self):
+ images = self.driver.list_images()
+ self.assertEqual(len(images), 13, 'Wrong images count')
+
+ image = images[0]
+ self.assertEqual(image.id, '13')
+ self.assertEqual(image.name, 'Windows 2008 SP2 x86 (B24)')
+ self.assertEqual(image.extra['updated'], '2011-08-06T18:14:02Z')
+ self.assertEqual(image.extra['created'], '2011-08-06T18:13:11Z')
+ self.assertEqual(image.extra['status'], 'ACTIVE')
+ self.assertEqual(image.extra['metadata']['os_type'], 'windows')
+
+ def test_create_node(self):
+ image = NodeImage(id=11, name='Ubuntu 8.10 (intrepid)', driver=self.driver)
+ size = NodeSize(1, '256 slice', None, None, None, None, driver=self.driver)
+ node = self.driver.create_node(name='racktest', image=image, size=size)
+ self.assertEqual(node.id, '52415800-8b69-11e0-9b19-734f565bc83b')
+ self.assertEqual(node.name, 'new-server-test')
+ self.assertEqual(node.extra['password'], 'GFf1j9aP')
+ self.assertEqual(node.extra['metadata']['My Server Name'], 'Apache1')
+
+ def test_destroy_node(self):
+ self.assertTrue(self.node.destroy())
+
+ def test_reboot_node(self):
+ self.assertTrue(self.node.reboot())
+
+ def test_ex_set_password(self):
+ try:
+ self.driver.ex_set_password(self.node, 'New1&53jPass')
+ except Exception, e:
+ self.fail('An error was raised: ' + repr(e))
+
+ def test_ex_rebuild(self):
+ image = NodeImage(id=11, name='Ubuntu 8.10 (intrepid)', driver=self.driver)
+ try:
+ self.driver.ex_rebuild(self.node, image=image)
+ except Exception, e:
+ self.fail('An error was raised: ' + repr(e))
+
+ def test_ex_resize(self):
+ size = NodeSize(1, '256 slice', None, None, None, None,
+ driver=self.driver)
+ try:
+ self.driver.ex_resize(self.node, size)
+ except Exception, e:
+ self.fail('An error was raised: ' + repr(e))
+
+ def test_ex_confirm_resize(self):
+ try:
+ self.driver.ex_confirm_resize(self.node)
+ except Exception, e:
+ self.fail('An error was raised: ' + repr(e))
+
+ def test_ex_revert_resize(self):
+ try:
+ self.driver.ex_revert_resize(self.node)
+ except Exception, e:
+ self.fail('An error was raised: ' + repr(e))
+
+ def test_ex_save_image(self):
+ try:
+ self.driver.ex_save_image(self.node, 'new_image')
+ except NotImplementedError:
+ pass
+ else:
+ self.fail('An expected error was not raised')
+
+ def test_ex_update_node(self):
+ old_node = Node(
+ id='12064',
+ name=None, state=None, public_ip=None, private_ip=None, driver=self.driver,
+ )
+
+ new_node = self.driver.ex_update_node(old_node, name='Bob')
+
+ self.assertTrue(new_node)
+ self.assertEqual('Bob', new_node.name)
+ self.assertEqual('50.57.94.30', new_node.public_ip[0])
+
+ def test_ex_get_node_details(self):
+ node_id = '12064'
+ node = self.driver.ex_get_node_details(node_id)
+ self.assertEqual(node.id, '12064')
+ self.assertEqual(node.name, 'lc-test')
+
+ def test_ex_get_size(self):
+ size_id = '7'
+ size = self.driver.ex_get_size(size_id)
+ self.assertEqual(size.id, size_id)
+ self.assertEqual(size.name, '15.5GB slice')
+
+ def test_ex_get_image(self):
+ image_id = '13'
+ image = self.driver.ex_get_image(image_id)
+ self.assertEqual(image.id, image_id)
+ self.assertEqual(image.name, 'Windows 2008 SP2 x86 (B24)')
+
+ def test_ex_delete_image(self):
+ image = NodeImage(id='26365521-8c62-11f9-2c33-283d153ecc3a', name='My Backup', driver=self.driver)
+ try:
+ self.driver.ex_delete_image(image)
+ except NotImplementedError:
+ pass
+ else:
+ self.fail('An expected error was not raised')
+
+class OpenStack_1_1_FactoryMethodTests(OpenStack_1_1_Tests):
+ should_list_locations = False
+
+ driver_klass = OpenStack_1_1_NodeDriver
+ driver_type = get_driver(Provider.OPENSTACK)
+ driver_args = OPENSTACK_PARAMS + ('1.1',)
+
+
+class OpenStack_1_1_MockHttp(MockHttpTestCase):
+ fixtures = ComputeFileFixtures('openstack_v1.1')
+ auth_fixtures = OpenStackFixtures()
+ json_content_headers = {'content-type': 'application/json; charset=UTF-8'}
+
+ def _v1_0_(self, method, url, body, headers):
+ headers = {
+ 'x-auth-token': 'FE011C19-CF86-4F87-BE5D-9229145D7A06',
+ 'x-server-management-url': 'https://api.example.com/v1.1/slug',
+ }
+ return (httplib.NO_CONTENT, "", headers, httplib.responses[httplib.NO_CONTENT])
+
+ def _servers_detail(self, method, url, body, headers):
+ body = self.fixtures.load('_servers_detail.json')
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+
+ def _flavors_detail(self, method, url, body, headers):
+ body = self.fixtures.load('_flavors_detail.json')
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+
+ def _images_detail(self, method, url, body, headers):
+ body = self.fixtures.load('_images_detail.json')
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+
+ def _servers(self, method, url, body, headers):
+ body = self.fixtures.load('_servers.json')
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+
+ def _servers_12065_action(self, method, url, body, headers):
+ if method != "POST":
+ self.fail('HTTP method other than POST to action URL')
+
+ return (httplib.ACCEPTED, "", {}, httplib.responses[httplib.ACCEPTED])
+
+ def _servers_12064_action(self, method, url, body, headers):
+ if method != "POST":
+ self.fail('HTTP method other than POST to action URL')
+
+ return (httplib.ACCEPTED, "", {}, httplib.responses[httplib.ACCEPTED])
+
+ def _servers_12065(self, method, url, body, headers):
+ if method == "DELETE":
+ return (httplib.ACCEPTED, "", {}, httplib.responses[httplib.ACCEPTED])
+ else:
+ raise NotImplementedError()
+
+ def _servers_12064(self, method, url, body, headers):
+ if method == "GET":
+ body = self.fixtures.load('_servers_12064.json')
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+ elif method == "PUT":
+ body = self.fixtures.load('_servers_12064_updated_name_bob.json')
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+ elif method == "DELETE":
+ return (httplib.ACCEPTED, "", {}, httplib.responses[httplib.ACCEPTED])
+ else:
+ raise NotImplementedError()
+
+ def _flavors_7(self, method, url, body, headers):
+ if method == "GET":
+ body = self.fixtures.load('_flavors_7.json')
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+ else:
+ raise NotImplementedError()
+
+ def _images_13(self, method, url, body, headers):
+ if method == "GET":
+ body = self.fixtures.load('_images_13.json')
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+ else:
+ raise NotImplementedError()
+
+ def _images_DELETEUUID(self, method, url, body, headers):
+ if method == "DELETE":
+ return (httplib.ACCEPTED, "", {}, httplib.responses[httplib.ACCEPTED])
+ else:
+ raise NotImplementedError()
if __name__ == '__main__':
Modified: libcloud/trunk/test/compute/test_rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/test_rackspace.py?rev=1183722&r1=1183721&r2=1183722&view=diff
==============================================================================
--- libcloud/trunk/test/compute/test_rackspace.py (original)
+++ libcloud/trunk/test/compute/test_rackspace.py Sat Oct 15 21:22:57 2011
@@ -16,15 +16,16 @@ import sys
import unittest
from libcloud.compute.drivers.rackspace import RackspaceNodeDriver
-from test.compute.test_openstack import OpenStackTests
+from test.compute.test_openstack import OpenStack_1_0_Tests
from test.secrets import RACKSPACE_PARAMS
-class RackspaceTests(OpenStackTests):
+class RackspaceTests(OpenStack_1_0_Tests):
should_list_locations = True
should_have_pricing = True
+ driver_klass = RackspaceNodeDriver
driver_type = RackspaceNodeDriver
driver_args = RACKSPACE_PARAMS