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 2012/02/16 08:05:44 UTC
svn commit: r1244862 - in /libcloud/trunk: ./ libcloud/common/
libcloud/compute/ libcloud/compute/drivers/ libcloud/dns/drivers/
libcloud/loadbalancer/drivers/ libcloud/storage/drivers/ test/
test/compute/ test/compute/fixtures/openstack/ test/dns/ tes...
Author: tomaz
Date: Thu Feb 16 07:05:43 2012
New Revision: 1244862
URL: http://svn.apache.org/viewvc?rev=1244862&view=rev
Log:
Make parsing of the Auth API responses in the OpenStack drivers more flexible
and extensible. This patch is part of LIBCLOUD-151 and has been contributed by
Brad Morgan <morgabra at cloudkick dot com>.
Added:
libcloud/trunk/libcloud/compute/drivers/rackspacenova.py
libcloud/trunk/test/compute/test_rackspacenova.py
Modified:
libcloud/trunk/CHANGES
libcloud/trunk/libcloud/common/openstack.py
libcloud/trunk/libcloud/compute/drivers/openstack.py
libcloud/trunk/libcloud/compute/drivers/rackspace.py
libcloud/trunk/libcloud/compute/providers.py
libcloud/trunk/libcloud/compute/types.py
libcloud/trunk/libcloud/dns/drivers/rackspace.py
libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py
libcloud/trunk/libcloud/storage/drivers/cloudfiles.py
libcloud/trunk/test/compute/fixtures/openstack/_v1_1__auth.json
libcloud/trunk/test/compute/fixtures/openstack/_v2_0__auth.json
libcloud/trunk/test/compute/test_deployment.py
libcloud/trunk/test/compute/test_openstack.py
libcloud/trunk/test/dns/test_rackspace.py
libcloud/trunk/test/loadbalancer/test_rackspace.py
libcloud/trunk/test/secrets.py-dist
libcloud/trunk/test/storage/test_cloudfiles.py
Modified: libcloud/trunk/CHANGES
URL: http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Thu Feb 16 07:05:43 2012
@@ -2,6 +2,26 @@
Changes with Apache Libcloud in development:
+ *) General:
+
+ - Make parsing of the Auth API responses in the OpenStack drivers more
+ flexible and extensible.
+
+ Now, every connection class that inherits from the openstack base
+ connection must implement get_endpoint(), who's job is to return the
+ correct endpoint out of the service catalog.
+
+ Note: The openstack.py base driver no longer works by default with
+ Rackspace nova. The default endpoint parsed from the service catalog
+ is the default compute endpoint for devstack.
+ [Brad Morgan]
+
+ *) Compute:
+
+ - Add new RackspaceNovaBeta and RackspaveNovaDfw driver based on the
+ OpenStack.
+ [Brad Morgan]
+
*) Storage:
- Don't lowercase special header names in the Amazon S3 storage driver. ;
Modified: libcloud/trunk/libcloud/common/openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/common/openstack.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/libcloud/common/openstack.py (original)
+++ libcloud/trunk/libcloud/common/openstack.py Thu Feb 16 07:05:43 2012
@@ -29,7 +29,7 @@ try:
except ImportError:
import json
-AUTH_API_VERSION = 'v1.0'
+AUTH_API_VERSION = '1.1'
__all__ = [
"OpenStackBaseConnection",
@@ -71,6 +71,7 @@ class OpenStackAuthResponse(Response):
return data
+
class OpenStackAuthConnection(ConnectionUserAndKey):
responseCls = OpenStackAuthResponse
@@ -166,19 +167,19 @@ class OpenStackAuthConnection(Connection
def authenticate_2_0_with_apikey(self):
# API Key based authentication uses the RAX-KSKEY extension.
# https://github.com/openstack/keystone/tree/master/keystone/content/service
- reqbody = json.dumps({'auth':{'RAX-KSKEY:apiKeyCredentials':{'username':self.user_id, 'apiKey':self.key}}})
+ reqbody = json.dumps({'auth': {'RAX-KSKEY:apiKeyCredentials': {'username': self.user_id, 'apiKey': self.key}}})
return self.authenticate_2_0_with_body(reqbody)
def authenticate_2_0_with_password(self):
# Password based authentication is the only 'core' authentication method in Keystone at this time.
# 'keystone' - http://docs.openstack.org/api/openstack-identity-service/2.0/content/Identity-Service-Concepts-e1362.html
- reqbody = json.dumps({'auth':{'passwordCredentials':{'username':self.user_id, 'password':self.key}}})
+ reqbody = json.dumps({'auth': {'passwordCredentials': {'username': self.user_id, 'password': self.key}}})
return self.authenticate_2_0_with_body(reqbody)
def authenticate_2_0_with_body(self, reqbody):
resp = self.request('/v2.0/tokens/',
data=reqbody,
- headers={'Content-Type':'application/json'},
+ headers={'Content-Type': 'application/json'},
method='POST')
if resp.status == httplib.UNAUTHORIZED:
raise InvalidCredsError()
@@ -202,65 +203,125 @@ class OpenStackAuthConnection(Connection
e = sys.exc_info()[1]
raise MalformedResponseError('Auth JSON response is missing required elements', e)
+
+class OpenStackServiceCatalog(object):
+ """
+ http://docs.openstack.org/api/openstack-identity-service/2.0/content/
+
+ This class should be instanciated with the contents of the 'serviceCatalog'
+ in the auth response. This will do the work of figuring out which services
+ actually exist in the catalog as well as split them up by type, name, and
+ region if available
+ """
+
+ _auth_version = None
+ _service_catalog = None
+
+ def __init__(self, service_catalog, ex_force_auth_version=None):
+ self._auth_version = ex_force_auth_version or AUTH_API_VERSION
+ self._service_catalog = {}
+
+ # check this way because there are a couple of different 2.0_* auth types
+ if '2.0' in self._auth_version:
+ self._parse_auth_v2(service_catalog)
+ elif ('1.1' in self._auth_version) or ('1.0' in self._auth_version):
+ self._parse_auth_v1(service_catalog)
+ else:
+ raise LibcloudError('auth version "%s" not supported' % (self._auth_version))
+
+ def get_endpoint(self, service_type=None, name=None, region=None):
+
+ if '2.0' in self._auth_version:
+ endpoint = self._service_catalog.get(service_type, {}).get(name, {}).get(region, [])
+ elif ('1.1' in self._auth_version) or ('1.0' in self._auth_version):
+ endpoint = self._service_catalog.get(name, {}).get(region, [])
+
+ # ideally an endpoint either isn't found or only one match is found.
+ if len(endpoint) == 1:
+ return endpoint[0]
+ else:
+ return {}
+
+ def _parse_auth_v1(self, service_catalog):
+
+ for service, endpoints in service_catalog.items():
+
+ self._service_catalog[service] = {}
+
+ for endpoint in endpoints:
+ region = endpoint.get('region')
+
+ if region not in self._service_catalog[service]:
+ self._service_catalog[service][region] = []
+
+ self._service_catalog[service][region].append(endpoint)
+
+ def _parse_auth_v2(self, service_catalog):
+
+ for service in service_catalog:
+
+ service_type = service['type']
+ service_name = service.get('name', None)
+
+ if service_type not in self._service_catalog:
+ self._service_catalog[service_type] = {}
+
+ if service_name not in self._service_catalog[service_type]:
+ self._service_catalog[service_type][service_name] = {}
+
+ for endpoint in service.get('endpoints', []):
+ region = endpoint.get('region', None)
+ if region not in self._service_catalog[service_type][service_name]:
+ self._service_catalog[service_type][service_name][region] = []
+
+ self._service_catalog[service_type][service_name][region].append(endpoint)
+
+
class OpenStackBaseConnection(ConnectionUserAndKey):
auth_url = None
+ auth_token = None
+ service_catalog = None
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):
- self.server_url = None
- self.cdn_management_url = None
- self.storage_url = None
- self.lb_url = None
- self.auth_token = None
- self._force_base_url = ex_force_base_url
+
+ self._ex_force_base_url = ex_force_base_url
self._ex_force_auth_url = ex_force_auth_url
self._auth_version = ex_force_auth_version
if not self._auth_version:
- self._auth_version = '1.1'
+ self._auth_version = AUTH_API_VERSION
super(OpenStackBaseConnection, self).__init__(
user_id, key, secure=secure)
+ def get_endpoint(self):
+ """
+ Every openstack driver must have a connection class that subclasses this
+ class and it must implement this method.
+
+ @returns: url of the relevant endpoint for the driver
+
+ Example implementation:
+ ep = self.service_catalog.get_endpoint(service_type='compute',
+ name='ServiceName',
+ region='US1')
+ return ep['publicURL']
+ """
+ raise NotImplementedError
+
def add_default_headers(self, headers):
headers['X-Auth-Token'] = self.auth_token
headers['Accept'] = self.accept_format
return headers
def morph_action_hook(self, action):
- if self._force_base_url:
- _, _, request_path, _, _, _ = urlparse.urlparse(self._force_base_url)
- return request_path + action
-
- value = getattr(self, self._url_key, None)
- if not value:
- self._populate_hosts_and_request_paths()
- request_path = getattr(self, '__request_path_%s' % (self._url_key), '')
- action = request_path + action
-
- return action
-
- @property
- def base_url(self):
- return self._get_base_url(url_key=self._url_key)
-
- def _get_base_url(self, url_key):
- value = getattr(self, url_key, None)
- if not value:
- self._populate_hosts_and_request_paths()
- value = getattr(self, url_key, None)
- if self._force_base_url != None:
- value = self._force_base_url
- return value
-
- def _get_default_region(self, arr):
- if len(arr):
- return arr[0]['publicURL']
- return None
+ self._populate_hosts_and_request_paths()
+ return super(OpenStackBaseConnection, self).morph_action_hook(action)
def request(self, **kwargs):
self._populate_hosts_and_request_paths()
@@ -269,9 +330,9 @@ class OpenStackBaseConnection(Connection
def _populate_hosts_and_request_paths(self):
"""
OpenStack uses a separate host for API calls which is only provided
- after an initial authentication request. If we haven't made that
- request yet, do it here. Otherwise, just return the management host.
+ after an initial authentication request.
"""
+
if not self.auth_token:
aurl = self.auth_url
@@ -288,39 +349,8 @@ class OpenStackBaseConnection(Connection
self.auth_token = osa.auth_token
- # TODO: Multi-region support
- if self._auth_version in ['2.0', '2.0_apikey', '2.0_password']:
- self.tenant_ids = {}
-
- for service in osa.urls:
- service_type = service['type']
- if service_type == 'compute':
- self.server_url = self._get_default_region(service.get('endpoints', []))
-
- self.tenant_ids[service_type] = service['endpoints'][0]['tenantId']
- elif self._auth_version in ['1.1', '1.0']:
- self.server_url = self._get_default_region(osa.urls.get('cloudServers', []))
- self.cdn_management_url = self._get_default_region(osa.urls.get('cloudFilesCDN', []))
- self.storage_url = self._get_default_region(osa.urls.get('cloudFiles', []))
- # TODO: this is even more broken, the service catalog does NOT show load
- # balanacers :( You must hard code in the Rackspace Load balancer URLs...
- self.lb_url = self.server_url.replace("servers", "ord.loadbalancers")
- self.dns_url = self.server_url.replace("servers", "dns")
- else:
- raise LibcloudError('auth version "%s" not supported' % (self._auth_version))
-
- for key in ['server_url', 'storage_url', 'cdn_management_url',
- 'lb_url', 'dns_url']:
- base_url = None
- if self._force_base_url != None:
- base_url = self._force_base_url
- else:
- base_url = getattr(self, key)
-
- scheme, server, request_path, param, query, fragment = (
- urlparse.urlparse(base_url))
- # Set host to where we want to make further requests to
- setattr(self, '__%s' % (key), server+request_path)
- setattr(self, '__request_path_%s' % (key), request_path)
+ # pull out and parse the service catalog
+ self.service_catalog = OpenStackServiceCatalog(osa.urls, ex_force_auth_version=self._auth_version)
- (self.host, self.port, self.secure, self.request_path) = self._tuple_from_url(self.base_url)
+ # Set up connection info
+ (self.host, self.port, self.secure, self.request_path) = self._tuple_from_url(self._ex_force_base_url or self.get_endpoint())
Modified: libcloud/trunk/libcloud/compute/drivers/openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/openstack.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/openstack.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/openstack.py Thu Feb 16 07:05:43 2012
@@ -37,7 +37,7 @@ import base64
from xml.etree import ElementTree as ET
from libcloud.common.openstack import OpenStackBaseConnection
-from libcloud.common.types import MalformedResponseError
+from libcloud.common.types import MalformedResponseError, LibcloudError
from libcloud.compute.types import NodeState, Provider
from libcloud.compute.base import NodeSize, NodeImage
from libcloud.compute.base import NodeDriver, Node, NodeLocation
@@ -121,6 +121,17 @@ class OpenStackResponse(Response):
class OpenStackComputeConnection(OpenStackBaseConnection):
+ def get_endpoint(self):
+
+ # default config for http://devstack.org/
+ ep = self.service_catalog.get_endpoint(service_type='compute',
+ name='nova',
+ region='RegionOne')
+ if 'publicURL' in ep:
+ return ep['publicURL']
+
+ raise LibcloudError('Could not find specified endpoint')
+
def request(self, action, params=None, data='', headers=None,
method='GET'):
if not headers:
@@ -245,7 +256,6 @@ class OpenStack_1_0_Response(OpenStackRe
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'
@@ -766,7 +776,6 @@ class OpenStack_1_1_Response(OpenStackRe
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'
Modified: libcloud/trunk/libcloud/compute/drivers/rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/rackspace.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/rackspace.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/rackspace.py Thu Feb 16 07:05:43 2012
@@ -15,7 +15,7 @@
"""
Rackspace driver
"""
-from libcloud.compute.types import Provider
+from libcloud.compute.types import Provider, LibcloudError
from libcloud.compute.base import NodeLocation
from libcloud.compute.drivers.openstack import OpenStack_1_0_Connection, OpenStack_1_0_NodeDriver, OpenStack_1_0_Response
@@ -32,6 +32,20 @@ class RackspaceConnection(OpenStack_1_0_
auth_url = AUTH_URL_US
XML_NAMESPACE = 'http://docs.rackspacecloud.com/servers/api/v1.0'
+ def get_endpoint(self):
+
+ ep = {}
+ if '2.0' in self._auth_version:
+ ep = self.service_catalog.get_endpoint(service_type='compute',
+ name='cloudServers')
+ elif ('1.1' in self._auth_version) or ('1.0' in self._auth_version):
+ ep = self.service_catalog.get_endpoint(name='cloudServers')
+
+ if 'publicURL' in ep:
+ return ep['publicURL']
+
+ raise LibcloudError('Could not find specified endpoint')
+
class RackspaceNodeDriver(OpenStack_1_0_NodeDriver):
name = 'Rackspace'
Added: libcloud/trunk/libcloud/compute/drivers/rackspacenova.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/rackspacenova.py?rev=1244862&view=auto
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/rackspacenova.py (added)
+++ libcloud/trunk/libcloud/compute/drivers/rackspacenova.py Thu Feb 16 07:05:43 2012
@@ -0,0 +1,70 @@
+# 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.
+"""
+Rackspace driver
+"""
+from libcloud.compute.providers import Provider
+from libcloud.compute.drivers.openstack import OpenStack_1_1_Connection, OpenStack_1_1_NodeDriver
+from libcloud.common.types import LibcloudError
+
+
+class RackspaceNovaConnection(OpenStack_1_1_Connection):
+ get_endpoint_args = {}
+
+ def get_endpoint(self):
+
+ if not self.get_endpoint_args:
+ raise LibcloudError('RackspaceNovaConnection must have get_endpoint_args set')
+
+ # Only support auth 2.0_*
+ if '2.0' in self._auth_version:
+ ep = self.service_catalog.get_endpoint(**self.get_endpoint_args)
+ else:
+ raise LibcloudError('Auth version "%s" not supported' % (self._auth_version))
+
+ # It's possible to authenticate but the service catalog not have the correct
+ # endpoint for this driver, so we throw here.
+ if 'publicURL' in ep:
+ return ep['publicURL']
+ else:
+ raise LibcloudError('Could not find specified endpoint')
+
+
+class RackspaceNovaBetaConnection(RackspaceNovaConnection):
+
+ get_endpoint_args = {'service_type': 'compute',
+ 'name': 'cloudServersPreprod',
+ 'region': 'DFW'}
+
+
+class RackspaceNovaDfwConnection(RackspaceNovaConnection):
+
+ get_endpoint_args = {'service_type': 'compute',
+ 'name': 'cloudServersOpenStack',
+ 'region': 'DFW'}
+
+
+class RackspaceNovaDfwNodeDriver(OpenStack_1_1_NodeDriver):
+ name = 'RackspaceNovadfw'
+ connectionCls = RackspaceNovaDfwConnection
+ type = Provider.RACKSPACE_NOVA_DFW
+ api_name = 'rackspacenovadfw'
+
+
+class RackspaceNovaBetaNodeDriver(OpenStack_1_1_NodeDriver):
+ name = 'RackspaceNovaBeta'
+ connectionCls = RackspaceNovaBetaConnection
+ type = Provider.RACKSPACE_NOVA_BETA
+ api_name = 'rackspacenovabeta'
Modified: libcloud/trunk/libcloud/compute/providers.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/providers.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/providers.py (original)
+++ libcloud/trunk/libcloud/compute/providers.py Thu Feb 16 07:05:43 2012
@@ -100,8 +100,13 @@ DRIVERS = {
Provider.TERREMARK:
('libcloud.compute.drivers.vcloud', 'TerremarkDriver'),
Provider.CLOUDSTACK:
- ('libcloud.compute.drivers.cloudstack', 'CloudStackNodeDriver')
+ ('libcloud.compute.drivers.cloudstack', 'CloudStackNodeDriver'),
+ Provider.RACKSPACE_NOVA_BETA:
+ ('libcloud.compute.drivers.rackspacenova', 'RackspaceNovaBetaNodeDriver'),
+ Provider.RACKSPACE_NOVA_DFW:
+ ('libcloud.compute.drivers.rackspacenova', 'RackspaceNovaDfwNodeDriver')
}
+
def get_driver(provider):
return _get_provider_driver(DRIVERS, provider)
Modified: libcloud/trunk/libcloud/compute/types.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/types.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/types.py (original)
+++ libcloud/trunk/libcloud/compute/types.py Thu Feb 16 07:05:43 2012
@@ -30,6 +30,8 @@ __all__ = [
"InvalidCredsError",
"InvalidCredsException"
]
+
+
class Provider(object):
"""
Defines for each of the supported providers
@@ -59,6 +61,7 @@ class Provider(object):
@cvar: EC2_US_WEST_OREGON: Amazon AWS US West 2 (Oregon)
@cvar CLOUDSTACK: CloudStack
@cvar CLOUDSIGMA_US: CloudSigma US Las Vegas
+ @cvar RACKSPACE_NOVA_BETA: Rackspace Nova Private Beta (ORD)
"""
DUMMY = 0
EC2 = 1 # deprecated name
@@ -102,6 +105,9 @@ class Provider(object):
CLOUDSTACK = 37
CLOUDSIGMA_US = 38
EC2_SA_EAST = 39
+ RACKSPACE_NOVA_BETA = 40
+ RACKSPACE_NOVA_DFW = 41
+
class NodeState(object):
"""
@@ -119,6 +125,7 @@ class NodeState(object):
PENDING = 3
UNKNOWN = 4
+
class Architecture(object):
"""
Image and size architectures.
@@ -129,6 +136,7 @@ class Architecture(object):
I386 = 0
X86_X64 = 1
+
class DeploymentError(LibcloudError):
"""
Exception used when a Deployment Task failed.
Modified: libcloud/trunk/libcloud/dns/drivers/rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/dns/drivers/rackspace.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/libcloud/dns/drivers/rackspace.py (original)
+++ libcloud/trunk/libcloud/dns/drivers/rackspace.py Thu Feb 16 07:05:43 2012
@@ -72,7 +72,6 @@ class RackspaceDNSConnection(OpenStack_1
"""
responseCls = RackspaceDNSResponse
- _url_key = 'dns_url'
XML_NAMESPACE = None
poll_interval = 2.5
timeout = 30
@@ -91,6 +90,25 @@ class RackspaceDNSConnection(OpenStack_1
return status == 'COMPLETED'
+ def get_endpoint(self):
+ """
+ FIXME:
+ Dirty, dirty hack. DNS doesn't get returned in the auth 1.1 service
+ catalog, so we build it from the servers url.
+ """
+
+ if self._auth_version == "1.1":
+ ep = self.service_catalog.get_endpoint(name="cloudServers")
+
+ if 'publicURL' in ep:
+ return ep['publicURL'].replace("servers", "dns")
+ else:
+ raise LibcloudError('Could not find specified endpoint')
+
+ else:
+ raise LibcloudError("Auth version %s not supported" % \
+ self._auth_version)
+
class RackspaceUSDNSConnection(RackspaceDNSConnection):
auth_url = AUTH_URL_US
Modified: libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py (original)
+++ libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py Thu Feb 16 07:05:43 2012
@@ -226,7 +226,6 @@ class RackspaceAccessRule(object):
class RackspaceConnection(OpenStackBaseConnection, PollingConnection):
responseCls = RackspaceResponse
auth_url = AUTH_URL_US
- _url_key = "lb_url"
poll_interval = 2
timeout = 80
@@ -263,6 +262,25 @@ class RackspaceConnection(OpenStackBaseC
return state == 'ACTIVE'
+ def get_endpoint(self):
+ """
+ FIXME:
+ Dirty, dirty hack. Loadbalancers so not show up in the auth 1.1 service
+ catalog, so we build it from the servers url.
+ """
+
+ if self._auth_version == "1.1":
+ ep = self.service_catalog.get_endpoint(name="cloudServers")
+
+ if 'publicURL' in ep:
+ return ep['publicURL'].replace("servers", "ord.loadbalancers")
+ else:
+ raise LibcloudError('Could not find specified endpoint')
+
+ else:
+ raise LibcloudError("Auth version %s not supported" % \
+ self._auth_version)
+
class RackspaceUKConnection(RackspaceConnection):
auth_url = AUTH_URL_UK
Modified: libcloud/trunk/libcloud/storage/drivers/cloudfiles.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/storage/drivers/cloudfiles.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/libcloud/storage/drivers/cloudfiles.py (original)
+++ libcloud/trunk/libcloud/storage/drivers/cloudfiles.py Thu Feb 16 07:05:43 2012
@@ -86,9 +86,11 @@ class CloudFilesResponse(Response):
return data
+
class CloudFilesRawResponse(CloudFilesResponse, RawResponse):
pass
+
class CloudFilesConnection(OpenStackBaseConnection):
"""
Base connection class for the Cloudfiles driver.
@@ -97,7 +99,6 @@ class CloudFilesConnection(OpenStackBase
auth_url = AUTH_URL_US
responseCls = CloudFilesResponse
rawResponseCls = CloudFilesRawResponse
- _url_key = "storage_url"
def __init__(self, user_id, key, secure=True, **kwargs):
super(CloudFilesConnection, self).__init__(user_id, key, secure=secure,
@@ -105,6 +106,31 @@ class CloudFilesConnection(OpenStackBase
self.api_version = API_VERSION
self.accept_format = 'application/json'
+ def get_endpoint(self, cdn_request=False):
+
+ # First, we parse out both files and cdn endpoints for each auth version
+ if '2.0' in self._auth_version:
+ ep = self.service_catalog.get_endpoint(service_type='object-store',
+ name='cloudFiles',
+ region='ORD')
+ cdn_ep = self.service_catalog.get_endpoint(service_type='object-store',
+ name='cloudFilesCDN',
+ region='ORD')
+ elif ('1.1' in self._auth_version) or ('1.0' in self._auth_version):
+ ep = self.service_catalog.get_endpoint(name='cloudFiles',
+ region='ORD')
+ cdn_ep = self.service_catalog.get_endpoint(name='cloudFilesCDN',
+ region='ORD')
+
+ # if this is a CDN request, return the cdn url instead
+ if cdn_request:
+ ep = cdn_ep
+
+ if 'publicURL' in ep:
+ return ep['publicURL']
+ else:
+ raise LibcloudError('Could not find specified endpoint')
+
def request(self, action, params=None, data='', headers=None, method='GET',
raw=False, cdn_request=False):
if not headers:
@@ -112,14 +138,17 @@ class CloudFilesConnection(OpenStackBase
if not params:
params = {}
- if cdn_request:
- host = self._get_host(url_key='cdn_management_url')
- else:
- host = None
+ # FIXME: Massive hack.
+ # This driver dynamically changes the url in it's connection, based on arguments
+ # passed to request(). As such, we have to manually check and reset connection
+ # params each request
+ self._populate_hosts_and_request_paths()
+ ep = self.get_endpoint(cdn_request)
+ (self.host, self.port, self.secure, self.request_path) = self._ex_force_base_url or self._tuple_from_url(ep)
params['format'] = 'json'
- if method in [ 'POST', 'PUT' ]:
+ if method in ['POST', 'PUT']:
headers.update({'Content-Type': 'application/json; charset=UTF-8'})
return super(CloudFilesConnection, self).request(
Modified: libcloud/trunk/test/compute/fixtures/openstack/_v1_1__auth.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack/_v1_1__auth.json?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack/_v1_1__auth.json (original)
+++ libcloud/trunk/test/compute/fixtures/openstack/_v1_1__auth.json Thu Feb 16 07:05:43 2012
@@ -1 +1,31 @@
-{"auth":{"token":{"id":"603d2bd9-f45c-4583-b91c-2c8eac0b5654","expires":"2011-09-18T02:44:17.000-05:00"},"serviceCatalog":{"cloudFilesCDN":[{"region":"ORD","publicURL":"https:\/\/cdn2.clouddrive.com\/v1\/MossoCloudFS","v1Default":true}],"cloudFiles":[{"region":"ORD","publicURL":"https:\/\/storage101.ord1.clouddrive.com\/v1\/MossoCloudFS","v1Default":true,"internalURL":"https:\/\/snet-storage101.ord1.clouddrive.com\/v1\/MossoCloudFS"}],"cloudServers":[{"publicURL":"https:\/\/servers.api.rackspacecloud.com\/v1.0\/slug","v1Default":true}]}}}
+{
+ "auth": {
+ "token": {
+ "id": "603d2bd9-f45c-4583-b91c-2c8eac0b5654",
+ "expires": "2011-09-18T02:44:17.000-05:00"
+ },
+ "serviceCatalog": {
+ "cloudFilesCDN": [
+ {
+ "region": "ORD",
+ "publicURL": "https://cdn2.clouddrive.com/v1/MossoCloudFS",
+ "v1Default": true
+ }
+ ],
+ "cloudFiles": [
+ {
+ "region": "ORD",
+ "publicURL": "https://storage101.ord1.clouddrive.com/v1/MossoCloudFS",
+ "v1Default": true,
+ "internalURL": "https://snet-storage101.ord1.clouddrive.com/v1/MossoCloudFS"
+ }
+ ],
+ "cloudServers": [
+ {
+ "publicURL": "https://servers.api.rackspacecloud.com/v1.0/slug",
+ "v1Default": true
+ }
+ ]
+ }
+ }
+}
Modified: libcloud/trunk/test/compute/fixtures/openstack/_v2_0__auth.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/openstack/_v2_0__auth.json?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/test/compute/fixtures/openstack/_v2_0__auth.json (original)
+++ libcloud/trunk/test/compute/fixtures/openstack/_v2_0__auth.json Thu Feb 16 07:05:43 2012
@@ -47,6 +47,45 @@
],
"name": "cloudServers",
"type": "compute"
+ },
+ {
+ "endpoints": [
+ {
+ "region": "RegionOne",
+ "tenantId": "1337",
+ "publicURL": "https://127.0.0.1/v2/1337",
+ "versionInfo": "https://127.0.0.1/v2/",
+ "versionList": "https://127.0.0.1/",
+ "versionId": "2"
+ }
+ ],
+ "name": "nova",
+ "type": "compute"
+ },
+ {
+ "endpoints": [
+ {
+ "region": "DFW",
+ "tenantId": "613469",
+ "publicURL": "https://dfw.servers.api.rackspacecloud.com/v2/1337",
+ "versionInfo": "https://dfw.servers.api.rackspacecloud.com/v2/",
+ "versionList": "https://dfw.servers.api.rackspacecloud.com/",
+ "versionId": "2"
+ }
+ ],
+ "name": "cloudServersOpenStack",
+ "type": "compute"
+ },
+ {
+ "endpoints": [
+ {
+ "region": "DFW",
+ "tenantId": "1337",
+ "publicURL": "https://preprod.dfw.servers.api.rackspacecloud.com/v2/1337"
+ }
+ ],
+ "name": "cloudServersPreprod",
+ "type": "compute"
}
],
"user": {
Modified: libcloud/trunk/test/compute/test_deployment.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/test_deployment.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/test/compute/test_deployment.py (original)
+++ libcloud/trunk/test/compute/test_deployment.py Thu Feb 16 07:05:43 2012
@@ -34,10 +34,12 @@ from mock import Mock, patch
from test.secrets import RACKSPACE_PARAMS
+
class MockDeployment(Deployment):
def run(self, node, client):
return node
+
class MockClient(BaseSSHClient):
def __init__(self, *args, **kwargs):
self.stdout = ''
@@ -53,12 +55,15 @@ class MockClient(BaseSSHClient):
def delete(self, name):
return True
+
class DeploymentTests(unittest.TestCase):
def setUp(self):
Rackspace.connectionCls.conn_classes = (None, RackspaceMockHttp)
RackspaceMockHttp.type = None
self.driver = Rackspace(*RACKSPACE_PARAMS)
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
self.driver.features = {'create_node': ['generates_password']}
self.node = Node(id=12345, name='test', state=NodeState.RUNNING,
public_ips=['1.2.3.4'], private_ips=['1.2.3.5'],
@@ -145,7 +150,6 @@ class DeploymentTests(unittest.TestCase)
else:
self.fail('Exception was not thrown')
-
def test_wait_until_running_running_node_missing_from_list_nodes(self):
RackspaceMockHttp.type = 'MISSING'
@@ -170,7 +174,6 @@ class DeploymentTests(unittest.TestCase)
else:
self.fail('Exception was not thrown')
-
def test_ssh_client_connect_success(self):
mock_ssh_client = Mock()
mock_ssh_client.return_value = None
@@ -328,6 +331,7 @@ class DeploymentTests(unittest.TestCase)
node = self.driver.deploy_node(deploy=Mock())
self.assertEqual(self.node.id, node.id)
+
class RackspaceMockHttp(MockHttp):
fixtures = ComputeFileFixtures('openstack')
Modified: libcloud/trunk/test/compute/test_openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/test_openstack.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/test/compute/test_openstack.py (original)
+++ libcloud/trunk/test/compute/test_openstack.py Thu Feb 16 07:05:43 2012
@@ -14,7 +14,6 @@
# limitations under the License.
import sys
import unittest
-import types
try:
import simplejson as json
@@ -82,16 +81,26 @@ class OpenStack_1_0_Tests(unittest.TestC
return self.driver_type(*self.driver_args, **self.driver_kwargs)
def setUp(self):
+ # monkeypatch get_endpoint because the base openstack driver doesn't actually
+ # work with old devstack but this class/tests are still used by the rackspace
+ # driver
+ def get_endpoint(*args, **kwargs):
+ return "https://servers.api.rackspacecloud.com/v1.0/slug"
+ self.driver_klass.connectionCls.get_endpoint = get_endpoint
+
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()
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
clear_pricing_data()
def test_auth(self):
OpenStackMockHttp.type = 'UNAUTHORIZED'
try:
self.driver = self.create_driver()
+ self.driver.list_nodes()
except InvalidCredsError:
e = sys.exc_info()[1]
self.assertEqual(True, isinstance(e, InvalidCredsError))
@@ -102,6 +111,7 @@ class OpenStack_1_0_Tests(unittest.TestC
OpenStackMockHttp.type = 'UNAUTHORIZED_MISSING_KEY'
try:
self.driver = self.create_driver()
+ self.driver.list_nodes()
except MalformedResponseError:
e = sys.exc_info()[1]
self.assertEqual(True, isinstance(e, MalformedResponseError))
@@ -112,6 +122,7 @@ class OpenStack_1_0_Tests(unittest.TestC
OpenStackMockHttp.type = 'INTERNAL_SERVER_ERROR'
try:
self.driver = self.create_driver()
+ self.driver.list_nodes()
except MalformedResponseError:
e = sys.exc_info()[1]
self.assertEqual(True, isinstance(e, MalformedResponseError))
@@ -384,7 +395,7 @@ class OpenStackMockHttp(MockHttpTestCase
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])
+ return(httplib.NO_CONTENT, "", "", httplib.responses[httplib.NO_CONTENT])
def _v1_0_slug_images(self, method, url, body, headers):
if method != "POST":
@@ -485,13 +496,14 @@ 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'}
+ driver_kwargs = {'ex_force_auth_version': '2.0'}
@classmethod
def create_driver(self):
@@ -500,13 +512,27 @@ class OpenStack_1_1_Tests(unittest.TestC
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_klass.connectionCls.conn_classes = (OpenStack_2_0_MockHttp, OpenStack_2_0_MockHttp)
+ self.driver_klass.connectionCls.auth_url = "https://auth.api.example.com/v2.0/"
+ OpenStack_2_0_MockHttp.type = None
self.driver = self.create_driver()
+
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
clear_pricing_data()
self.node = self.driver.list_nodes()[1]
+ def test_ex_force_base_url(self):
+ # change base url and trash the current auth token so we can re-authenticate
+ self.driver.connection._ex_force_base_url = 'http://ex_force_base_url.com:666/forced_url'
+ self.driver.connection.auth_token = None
+ self.driver.connection._populate_hosts_and_request_paths()
+
+ # assert that we use the base url and not the auth url
+ self.assertEqual(self.driver.connection.host, 'ex_force_base_url.com')
+ self.assertEqual(self.driver.connection.port, '666')
+ self.assertEqual(self.driver.connection.request_path, '/forced_url')
+
def test_list_nodes(self):
nodes = self.driver.list_nodes()
self.assertEqual(len(nodes), 2)
@@ -534,9 +560,9 @@ class OpenStack_1_1_Tests(unittest.TestC
def test_list_sizes_with_specified_pricing(self):
- pricing = dict((str(i), i*5.0) for i in range(1, 9))
+ pricing = dict((str(i), i * 5.0) for i in range(1, 9))
- set_pricing(driver_type='compute', driver_name='openstack', pricing=pricing)
+ set_pricing(driver_type='compute', driver_name=self.driver.api_name, pricing=pricing)
sizes = self.driver.list_sizes()
self.assertEqual(len(sizes), 8, 'Wrong sizes count')
@@ -544,6 +570,7 @@ class OpenStack_1_1_Tests(unittest.TestC
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')
@@ -687,13 +714,15 @@ class OpenStack_1_1_Tests(unittest.TestC
self.assertEqual(image_id, '1d4a8ea9-aae7-4242-a42d-5ff4702f2f14')
self.assertEqual(image_id_two, '13')
+
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',)
- driver_kwargs = {'ex_force_auth_version': '1.0'}
+ driver_kwargs = {'ex_force_auth_version': '2.0'}
+
class OpenStack_1_1_MockHttp(MockHttpTestCase):
fixtures = ComputeFileFixtures('openstack_v1.1')
@@ -815,32 +844,22 @@ class OpenStack_1_1_MockHttp(MockHttpTes
else:
raise NotImplementedError()
-class OpenStack_1_1_Auth_2_0_MockHttp(OpenStack_1_1_MockHttp):
- fixtures = ComputeFileFixtures('openstack_v1.1')
- auth_fixtures = OpenStackFixtures()
- json_content_headers = {'content-type': 'application/json; charset=UTF-8'}
+# This exists because the nova compute url in devstack has v2 in there but the v1.1 fixtures
+# work fine.
+class OpenStack_2_0_MockHttp(OpenStack_1_1_MockHttp):
def __init__(self, *args, **kwargs):
- super(OpenStack_1_1_Auth_2_0_MockHttp, self).__init__(*args, **kwargs)
+ super(OpenStack_2_0_MockHttp, self).__init__(*args, **kwargs)
- # TODO Figure out why 1.1 tests are using some 1.0 endpoints
- methods1 = OpenStackMockHttp.__dict__
- methods2 = OpenStack_1_1_MockHttp.__dict__
+ methods1 = OpenStack_1_1_MockHttp.__dict__
- names1 = [m for m in methods1 if m.find('_v1_0') == 0]
- names2 = [m for m in methods2 if m.find('_v1_1') == 0]
+ names1 = [m for m in methods1 if m.find('_v1_1') == 0]
for name in names1:
method = methods1[name]
- new_name = name.replace('_v1_0_slug_', '_v1_0_1337_')
+ new_name = name.replace('_v1_1_slug_', '_v2_1337_')
setattr(self, new_name, method_type(method, self,
- OpenStack_1_1_Auth_2_0_MockHttp))
-
- for name in names2:
- method = methods2[name]
- new_name = name.replace('_v1_1_slug_', '_v1_0_1337_')
- setattr(self, new_name, method_type(method, self,
- OpenStack_1_1_Auth_2_0_MockHttp))
+ OpenStack_2_0_MockHttp))
class OpenStack_1_1_Auth_2_0_Tests(OpenStack_1_1_Tests):
@@ -849,24 +868,14 @@ class OpenStack_1_1_Auth_2_0_Tests(OpenS
def setUp(self):
self.driver_klass.connectionCls.conn_classes = \
- (OpenStack_1_1_Auth_2_0_MockHttp, OpenStack_1_1_Auth_2_0_MockHttp)
+ (OpenStack_2_0_MockHttp, OpenStack_2_0_MockHttp)
self.driver_klass.connectionCls.auth_url = "https://auth.api.example.com/v2.0/"
OpenStack_1_1_MockHttp.type = None
self.driver = self.create_driver()
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
clear_pricing_data()
self.node = self.driver.list_nodes()[1]
- server_url = 'https://servers.api.rackspacecloud.com/v1.0/1337'
- auth_token = 'aaaaaaaaaaaa-bbb-cccccccccccccc'
- tenant_compute = '1337'
- tenant_object_store = 'MossoCloudFS_11111-111111111-1111111111-1111111'
-
- self.assertEqual(self.driver.connection.server_url, server_url)
- self.assertEqual(self.driver.connection.auth_token, auth_token)
- self.assertEqual(self.driver.connection.tenant_ids,
- {'compute': tenant_compute, 'object-store': tenant_object_store})
-
-
-
if __name__ == '__main__':
sys.exit(unittest.main())
Added: libcloud/trunk/test/compute/test_rackspacenova.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/test_rackspacenova.py?rev=1244862&view=auto
==============================================================================
--- libcloud/trunk/test/compute/test_rackspacenova.py (added)
+++ libcloud/trunk/test/compute/test_rackspacenova.py Thu Feb 16 07:05:43 2012
@@ -0,0 +1,92 @@
+# 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.
+import sys
+import unittest
+
+from libcloud.utils.py3 import method_type
+
+from libcloud.compute.drivers.rackspacenova import RackspaceNovaBetaNodeDriver, \
+ RackspaceNovaDfwNodeDriver
+from test.compute.test_openstack import OpenStack_1_1_Tests, OpenStack_1_1_MockHttp
+from libcloud.pricing import clear_pricing_data
+
+from test.secrets import RACKSPACE_NOVA_PARAMS
+
+
+class RackspaceNovaMockHttp(OpenStack_1_1_MockHttp):
+ def __init__(self, *args, **kwargs):
+ super(RackspaceNovaMockHttp, self).__init__(*args, **kwargs)
+
+ methods1 = OpenStack_1_1_MockHttp.__dict__
+
+ names1 = [m for m in methods1 if m.find('_v1_1') == 0]
+
+ for name in names1:
+ method = methods1[name]
+ new_name = name.replace('_v1_1_slug_', '_v2_1337_')
+ setattr(self, new_name, method_type(method, self,
+ RackspaceNovaMockHttp))
+
+
+class RackspaceNovaBetaTests(OpenStack_1_1_Tests):
+
+ driver_klass = RackspaceNovaBetaNodeDriver
+ driver_type = RackspaceNovaBetaNodeDriver
+ driver_args = RACKSPACE_NOVA_PARAMS + ('1.1',)
+ driver_kwargs = {'ex_force_auth_version': '2.0'}
+
+ @classmethod
+ def create_driver(self):
+ return self.driver_type(*self.driver_args, **self.driver_kwargs)
+
+ def setUp(self):
+ self.driver_klass.connectionCls.conn_classes = (RackspaceNovaMockHttp, RackspaceNovaMockHttp)
+ self.driver_klass.connectionCls.auth_url = "https://auth.api.example.com/v2.0/"
+ self.driver = self.create_driver()
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
+ clear_pricing_data()
+ self.node = self.driver.list_nodes()[1]
+
+ def test_service_catalog(self):
+ self.assertEqual('https://preprod.dfw.servers.api.rackspacecloud.com/v2/1337', self.driver.connection.get_endpoint())
+
+
+class RackspaceNovaDfwTests(OpenStack_1_1_Tests):
+
+ driver_klass = RackspaceNovaDfwNodeDriver
+ driver_type = RackspaceNovaDfwNodeDriver
+ driver_args = RACKSPACE_NOVA_PARAMS + ('1.1',)
+ driver_kwargs = {'ex_force_auth_version': '2.0'}
+
+ @classmethod
+ def create_driver(self):
+ return self.driver_type(*self.driver_args, **self.driver_kwargs)
+
+ def setUp(self):
+ self.driver_klass.connectionCls.conn_classes = (RackspaceNovaMockHttp, RackspaceNovaMockHttp)
+ self.driver_klass.connectionCls.auth_url = "https://auth.api.example.com/v2.0/"
+ self.driver = self.create_driver()
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
+ clear_pricing_data()
+ self.node = self.driver.list_nodes()[1]
+
+ def test_service_catalog(self):
+ self.assertEqual('https://dfw.servers.api.rackspacecloud.com/v2/1337', self.driver.connection.get_endpoint())
+
+
+if __name__ == '__main__':
+ sys.exit(unittest.main())
Modified: libcloud/trunk/test/dns/test_rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/test_rackspace.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/test/dns/test_rackspace.py (original)
+++ libcloud/trunk/test/dns/test_rackspace.py Thu Feb 16 07:05:43 2012
@@ -37,6 +37,8 @@ class RackspaceUSTests(unittest.TestCase
RackspaceMockHttp.type = None
self.driver = self.klass(*DNS_PARAMS_RACKSPACE)
self.driver.connection.poll_interval = 0.0
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
def test_list_record_types(self):
record_types = self.driver.list_record_types()
Modified: libcloud/trunk/test/loadbalancer/test_rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/test_rackspace.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/test/loadbalancer/test_rackspace.py (original)
+++ libcloud/trunk/test/loadbalancer/test_rackspace.py Thu Feb 16 07:05:43 2012
@@ -45,6 +45,8 @@ class RackspaceLBTests(unittest.TestCase
RackspaceLBMockHttp.type = None
self.driver = RackspaceLBDriver('user', 'key')
self.driver.connection.poll_interval = 0.0
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
def test_list_protocols(self):
protocols = self.driver.list_protocols()
@@ -323,7 +325,7 @@ class RackspaceLBTests(unittest.TestCase
address="10.45.13.5/12"
)
- balancer= self.driver.ex_destroy_balancer_access_rule(balancer, rule)
+ balancer = self.driver.ex_destroy_balancer_access_rule(balancer, rule)
rule_ids = [r.id for r in balancer.extra['accessList']]
@@ -775,6 +777,9 @@ class RackspaceUKLBTests(RackspaceLBTest
RackspaceLBMockHttp)
RackspaceLBMockHttp.type = None
self.driver = RackspaceUKLBDriver('user', 'key')
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
+
class RackspaceLBMockHttp(MockHttpTestCase):
fixtures = LoadBalancerFileFixtures('rackspace')
Modified: libcloud/trunk/test/secrets.py-dist
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/secrets.py-dist?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/test/secrets.py-dist (original)
+++ libcloud/trunk/test/secrets.py-dist Thu Feb 16 07:05:43 2012
@@ -29,6 +29,7 @@ OPENSTACK_PARAMS = ('user_name', 'api_ke
OPENNEBULA_PARAMS = ('user', 'key')
OPSOURCE_PARAMS = ('user', 'password')
RACKSPACE_PARAMS = ('user', 'key')
+RACKSPACE_NOVA_PARAMS = ('user_name', 'api_key', False, 'host', 8774)
SLICEHOST_PARAMS = ('key',)
SOFTLAYER_PARAMS = ('user', 'api_key')
VCLOUD_PARAMS = ('user', 'secret')
Modified: libcloud/trunk/test/storage/test_cloudfiles.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/storage/test_cloudfiles.py?rev=1244862&r1=1244861&r2=1244862&view=diff
==============================================================================
--- libcloud/trunk/test/storage/test_cloudfiles.py (original)
+++ libcloud/trunk/test/storage/test_cloudfiles.py Thu Feb 16 07:05:43 2012
@@ -42,6 +42,7 @@ from test.file_fixtures import StorageFi
current_hash = None
+
class CloudFilesTests(unittest.TestCase):
def setUp(self):
@@ -52,6 +53,8 @@ class CloudFilesTests(unittest.TestCase)
CloudFilesMockHttp.type = None
CloudFilesMockRawResponse.type = None
self.driver = CloudFilesStorageDriver('dummy', 'dummy')
+ # normally authentication happens lazily, but we force it here
+ self.driver.connection._populate_hosts_and_request_paths()
self._remove_test_file()
def tearDown(self):
@@ -162,7 +165,7 @@ class CloudFilesTests(unittest.TestCase)
'Container already exists but an exception was not thrown')
def test_create_container_invalid_name_too_long(self):
- name = ''.join([ 'x' for x in range(0, 257)])
+ name = ''.join(['x' for x in range(0, 257)])
try:
self.driver.create_container(container_name=name)
except InvalidContainerNameError:
@@ -272,7 +275,7 @@ class CloudFilesTests(unittest.TestCase)
file_path = os.path.abspath(__file__)
container = Container(name='foo_bar_container', extra={}, driver=self)
object_name = 'foo_test_upload'
- extra = {'meta_data': { 'some-value': 'foobar'}}
+ extra = {'meta_data': {'some-value': 'foobar'}}
obj = self.driver.upload_object(file_path=file_path, container=container,
extra=extra, object_name=object_name)
self.assertEqual(obj.name, 'foo_test_upload')