You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by pq...@apache.org on 2011/09/18 01:35:46 UTC

svn commit: r1172148 - in /libcloud/trunk: libcloud/ libcloud/common/ libcloud/compute/ libcloud/compute/drivers/ libcloud/loadbalancer/drivers/ libcloud/storage/drivers/ test/ test/compute/ test/loadbalancer/ test/openstack/ test/openstack/fixtures/ t...

Author: pquerna
Date: Sat Sep 17 23:35:45 2011
New Revision: 1172148

URL: http://svn.apache.org/viewvc?rev=1172148&view=rev
Log:
Refactoring of how OpenStack based drivers authenticate and find their base URLs.  This also changed how other drivers did 'secure' port selection, and make Connection.port the actual port we are connecting on, and Connection.secure to just be an indiciator if we should use SSL or not, rather than changing the port.

Added:
    libcloud/trunk/test/openstack/
    libcloud/trunk/test/openstack/fixtures/
    libcloud/trunk/test/openstack/fixtures/_v1_1__auth.json
    libcloud/trunk/test/openstack/fixtures/_v1_1__auth_mssing_token.json
    libcloud/trunk/test/openstack/fixtures/_v1_1__auth_unauthorized.json
Modified:
    libcloud/trunk/libcloud/__init__.py
    libcloud/trunk/libcloud/common/base.py
    libcloud/trunk/libcloud/common/openstack.py
    libcloud/trunk/libcloud/common/rackspace.py
    libcloud/trunk/libcloud/compute/base.py
    libcloud/trunk/libcloud/compute/drivers/openstack.py
    libcloud/trunk/libcloud/compute/drivers/rackspace.py
    libcloud/trunk/libcloud/compute/drivers/rimuhosting.py
    libcloud/trunk/libcloud/compute/drivers/vcloud.py
    libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py
    libcloud/trunk/libcloud/storage/drivers/cloudfiles.py
    libcloud/trunk/test/compute/test_deployment.py
    libcloud/trunk/test/compute/test_openstack.py
    libcloud/trunk/test/file_fixtures.py
    libcloud/trunk/test/loadbalancer/test_rackspace.py
    libcloud/trunk/test/storage/test_cloudfiles.py

Modified: libcloud/trunk/libcloud/__init__.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/__init__.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/__init__.py (original)
+++ libcloud/trunk/libcloud/__init__.py Sat Sep 17 23:35:45 2011
@@ -32,12 +32,12 @@ def enable_debug(fo):
     @param fo: Where to append debugging information
     @type fo: File like object, only write operations are used.
     """
-    from libcloud.base import (ConnectionKey,
+    from libcloud.common.base import (Connection,
                                LoggingHTTPConnection,
                                LoggingHTTPSConnection)
     LoggingHTTPSConnection.log = fo
     LoggingHTTPConnection.log = fo
-    ConnectionKey.conn_classes = (LoggingHTTPConnection,
+    Connection.conn_classes = (LoggingHTTPConnection,
                                   LoggingHTTPSConnection)
 
 

Modified: libcloud/trunk/libcloud/common/base.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/common/base.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/common/base.py (original)
+++ libcloud/trunk/libcloud/common/base.py Sat Sep 17 23:35:45 2011
@@ -19,8 +19,10 @@ import StringIO
 import ssl
 
 from pipes import quote as pquote
+import urlparse
 
 import libcloud
+from libcloud.common.types import LibcloudError
 
 from libcloud.httplib_ssl import LibcloudHTTPSConnection
 from httplib import HTTPConnection as LibcloudHTTPConnection
@@ -222,7 +224,7 @@ class LoggingHTTPConnection(LoggingConne
         return LibcloudHTTPConnection.request(self, method, url,
                                                body, headers)
 
-class ConnectionKey(object):
+class Connection(object):
     """
     A Base Connection class to derive from.
     """
@@ -233,26 +235,57 @@ class ConnectionKey(object):
     rawResponseCls = RawResponse
     connection = None
     host = '127.0.0.1'
-    port = (80, 443)
+    port = 443
     secure = 1
     driver = None
     action = None
 
-    def __init__(self, key, secure=True, host=None, force_port=None):
-        """
-        Initialize `user_id` and `key`; set `secure` to an C{int} based on
-        passed value.
-        """
-        self.key = key
+    def __init__(self, secure=True, host=None, port=None, url=None):
         self.secure = secure and 1 or 0
         self.ua = []
+
+        self.request_path = ''
+
         if host:
             self.host = host
 
-        if force_port:
-            self.port = (force_port, force_port)
+        if port != None:
+            self.port = port
+        else:
+            if self.secure == 1:
+                self.port = 443
+            else:
+                self.port = 80
+
+        if url:
+            (self.host, self.port, self.secure, self.request_path) = self._tuple_from_url(url)
+
+    def _tuple_from_url(self, url):
+        secure = 1
+        port = None
+        scheme, netloc, request_path, param, query, fragment = urlparse.urlparse(url)
+
+        if scheme not in ['http', 'https']:
+            raise LibcloudError('Invalid scheme: %s in url %s' % (scheme, url))
 
-    def connect(self, host=None, port=None):
+        if scheme == "http":
+            secure = 0
+
+        if ":" in netloc:
+            netloc, port = netloc.rsplit(":")
+            port = port
+
+        if not port:
+            if scheme == "http":
+                port = 80
+            else:
+                port = 443
+
+        host = netloc
+
+        return (host, port, secure, request_path)
+
+    def connect(self, host=None, port=None, base_url = None):
         """
         Establish a connection with the API server.
 
@@ -264,17 +297,21 @@ class ConnectionKey(object):
 
         @returns: A connection
         """
-        host = host or self.host
-
-        # port might be included in service url, so pick it if it's present
-        if ":" in host:
-            host, port = host.split(":")
+        # prefer the attribute base_url if its set or sent
+        connection = None
+        secure = self.secure
+
+        if getattr(self, 'base_url', None) and base_url == None:
+            (host, port, secure, request_path) = self._tuple_from_url(self.base_url)
+        elif base_url != None:
+            (host, port, secure, request_path) = self._tuple_from_url(base_url)
         else:
-            port = port or self.port[self.secure]
+            host = host or self.host
+            port = port or self.port
 
         kwargs = {'host': host, 'port': int(port)}
 
-        connection = self.conn_classes[self.secure](**kwargs)
+        connection = self.conn_classes[secure](**kwargs)
         # You can uncoment this line, if you setup a reverse proxy server
         # which proxies to your endpoint, and lets you easily capture
         # connections in cleartext when you setup the proxy to do SSL
@@ -307,8 +344,7 @@ class ConnectionKey(object):
                 data='',
                 headers=None,
                 method='GET',
-                raw=False,
-                host=None):
+                raw=False):
         """
         Request a given `action`.
 
@@ -337,10 +373,6 @@ class ConnectionKey(object):
                      and use the rawResponseCls class. This is used with
                      storage API when uploading a file.
 
-        @type host: C{str}
-        @param host: To which host to send the request. If not specified,
-                     self.host is used.
-
         @return: An instance of type I{responseCls}
         """
         if params is None:
@@ -348,6 +380,7 @@ class ConnectionKey(object):
         if headers is None:
             headers = {}
 
+        action = self.morph_action_hook(action)
         self.action = action
         self.method = method
         # Extend default parameters
@@ -356,8 +389,7 @@ class ConnectionKey(object):
         headers = self.add_default_headers(headers)
         # We always send a user-agent header
         headers.update({'User-Agent': self._user_agent()})
-        host = host or self.host
-        headers.update({'Host': host})
+        headers.update({'Host': self.host})
         # Encode data if necessary
         if data != '' and data != None:
             data = self.encode_data(data)
@@ -374,7 +406,7 @@ class ConnectionKey(object):
 
         # Removed terrible hack...this a less-bad hack that doesn't execute a
         # request twice, but it's still a hack.
-        self.connect(host=host)
+        self.connect()
         try:
             # @TODO: Should we just pass File object as body to request method
             # instead of dealing with splitting and sending the file ourselves?
@@ -399,6 +431,9 @@ class ConnectionKey(object):
         response.connection = self
         return response
 
+    def morph_action_hook(self, action):
+        return self.request_path  + action
+
     def add_default_params(self, params):
         """
         Adds default parameters (such as API key, version, etc.)
@@ -438,6 +473,18 @@ class ConnectionKey(object):
         Override in a provider's subclass.
         """
         return data
+    
+class ConnectionKey(Connection):
+    """
+    A Base Connection class to derive from, which includes a
+    """
+    def __init__(self, key, secure=True, host=None, port=None, url=None):
+        """
+        Initialize `user_id` and `key`; set `secure` to an C{int} based on
+        passed value.
+        """
+        super(ConnectionKey, self).__init__(secure=secure, host=host, port=port, url=url)
+        self.key = key
 
 class ConnectionUserAndKey(ConnectionKey):
     """
@@ -446,6 +493,7 @@ class ConnectionUserAndKey(ConnectionKey
 
     user_id = None
 
-    def __init__(self, user_id, key, secure=True, host=None, port=None):
-        super(ConnectionUserAndKey, self).__init__(key, secure, host, port)
+    def __init__(self, user_id, key, secure=True, host=None, port=None, url=None):
+        super(ConnectionUserAndKey, self).__init__(key, secure=secure,
+                                                   host=host, port=port, url=url)
         self.user_id = user_id

Modified: libcloud/trunk/libcloud/common/openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/common/openstack.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/common/openstack.py (original)
+++ libcloud/trunk/libcloud/common/openstack.py Sat Sep 17 23:35:45 2011
@@ -18,65 +18,163 @@ Common utilities for OpenStack
 """
 import httplib
 from urllib2 import urlparse
-from libcloud.common.base import ConnectionUserAndKey
-from libcloud.compute.types import InvalidCredsError, MalformedResponseError
+from libcloud.common.base import ConnectionUserAndKey, Response
+from libcloud.compute.types import LibcloudError, InvalidCredsError, MalformedResponseError
+
+try:
+    import simplejson as json
+except ImportError:
+    import json
 
 AUTH_API_VERSION = 'v1.0'
 
 __all__ = [
     "OpenStackBaseConnection",
+    "OpenStackAuthConnection",
     ]
 
+
+# @TODO: Refactor for re-use by other openstack drivers
+class OpenStackAuthResponse(Response):
+    def success(self):
+        return True
+
+    def parse_body(self):
+        if not self.body:
+            return None
+
+        if 'content-type' in self.headers:
+            key = 'content-type'
+        elif 'Content-Type' in self.headers:
+            key = 'Content-Type'
+        else:
+            raise LibcloudError('Missing content-type header', driver=OpenStackAuthConnection)
+
+        content_type = self.headers[key]
+        if content_type.find(';') != -1:
+            content_type = content_type.split(';')[0]
+
+        if content_type == 'application/json':
+            try:
+                data = json.loads(self.body)
+            except:
+                raise MalformedResponseError('Failed to parse JSON',
+                                             body=self.body,
+                                             driver=OpenStackAuthConnection)
+        elif content_type == 'text/plain':
+            data = self.body
+        else:
+            data = self.body
+
+        return data
+
+class OpenStackAuthConnection(ConnectionUserAndKey):
+
+    responseCls = OpenStackAuthResponse
+    name = 'OpenStack Auth'
+
+    def __init__(self, parent_conn, auth_url, user_id, key):
+        self.parent_conn = parent_conn
+        # enable tests to use the same mock connection classes.
+        self.conn_classes = parent_conn.conn_classes
+
+        super(OpenStackAuthConnection, self).__init__(
+            user_id, key, url=auth_url)
+
+        self.auth_url = auth_url
+        self.urls = {}
+        self.driver = self.parent_conn.driver
+
+    def add_default_headers(self, headers):
+        headers['Accept'] = 'application/json'
+        headers['Content-Type'] = 'application/json; charset=UTF-8'
+        return headers
+
+    def authenticate(self):
+        reqbody = json.dumps({'credentials': {'username': self.user_id, 'key': self.key}})
+        resp = self.request("/auth",
+                    data=reqbody,
+                    headers={
+                        'X-Auth-User': self.user_id,
+                        'X-Auth-Key': self.key,
+                    },
+                    method='POST')
+
+        if resp.status == httplib.UNAUTHORIZED:
+            # HTTP UNAUTHORIZED (401): auth failed
+            raise InvalidCredsError()
+        elif resp.status != httplib.OK:
+            raise MalformedResponseError('Malformed response',
+                    body='code: %s body:%s' % (resp.status, resp.body),
+                    driver=self.driver)
+        else:
+            try:
+                body = json.loads(resp.body)
+            except Exception, e:
+                raise MalformedResponseError('Failed to parse JSON', e)
+            try:
+                self.auth_token = body['auth']['token']['id']
+                self.urls = body['auth']['serviceCatalog']
+            except KeyError, e:
+                raise MalformedResponseError('Auth JSON response is missing required elements', e)
+
 class OpenStackBaseConnection(ConnectionUserAndKey):
 
-    auth_host = None
+    auth_url = None
 
-    def __init__(self, user_id, key, secure, host=None, port=None):
+    def __init__(self, user_id, key, secure=True,
+                 host=None, port=None, ex_force_base_url=None):
+        self.server_url = None
         self.cdn_management_url = None
         self.storage_url = None
+        self.lb_url = None
         self.auth_token = None
-        if host is not None:
-            self.auth_host = host
-        if port is not None:
-            self.port = (port, port)
-
+        self._force_base_url = ex_force_base_url
         super(OpenStackBaseConnection, self).__init__(
-            user_id, key, secure=secure)
+            user_id, key)
 
     def add_default_headers(self, headers):
         headers['X-Auth-Token'] = self.auth_token
         headers['Accept'] = self.accept_format
         return headers
 
-    @property
-    def request_path(self):
-        return self._get_request_path(url_key=self._url_key)
-
-    @property
-    def host(self):
-        # Default to server_host
-        return self._get_host(url_key=self._url_key)
-
-    def _get_request_path(self, url_key):
-        value_key = '__request_path_%s' % (url_key)
-        value = getattr(self, value_key, None)
+    def morph_action(self, action):
+        key = self._url_key
 
+        value = getattr(self, key, None)
         if not value:
             self._populate_hosts_and_request_paths()
-            value = getattr(self, value_key, None)
 
-        return value
+        request_path = getattr(self, '__request_path_%s' % (key), '')
+        action = request_path + action
+        return action
 
-    def _get_host(self, url_key):
-        value_key = '__%s' % (url_key)
-        value = getattr(self, value_key, None)
+    @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, value_key, None)
-
+            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):
+            for i in arr:
+                if i.get('v1Default', False):
+                    return i['publicURL']
+            # uber lame
+            return arr[0]
+        return None
+
+    def request(self, **kwargs):
+        self._populate_hosts_and_request_paths()
+        return super(OpenStackBaseConnection, self).request(**kwargs)
+
     def _populate_hosts_and_request_paths(self):
         """
         OpenStack uses a separate host for API calls which is only provided
@@ -84,50 +182,36 @@ class OpenStackBaseConnection(Connection
         request yet, do it here. Otherwise, just return the management host.
         """
         if not self.auth_token:
-            # Initial connection used for authentication
-            conn = self.conn_classes[self.secure](
-                self.auth_host, self.port[self.secure])
-            conn.request(
-                method='GET',
-                url='/%s' % (AUTH_API_VERSION),
-                headers={
-                    'X-Auth-User': self.user_id,
-                    'X-Auth-Key': self.key
-                }
-            )
-
-            resp = conn.getresponse()
-
-            if resp.status == httplib.NO_CONTENT:
-                # HTTP NO CONTENT (204): auth successful
-                headers = dict(resp.getheaders())
-
-                try:
-                    self.server_url = headers['x-server-management-url']
-                    self.storage_url = headers['x-storage-url']
-                    self.cdn_management_url = headers['x-cdn-management-url']
-                    self.lb_url = self.server_url.replace("servers", "ord.loadbalancers")
-                    self.auth_token = headers['x-auth-token']
-                except KeyError, e:
-                    # Returned 204 but has missing information in the header, something is wrong
-                    raise MalformedResponseError('Malformed response',
-                                                 body='Missing header: %s' % (str(e)),
-                                                 driver=self.driver)
-            elif resp.status == httplib.UNAUTHORIZED:
-                # HTTP UNAUTHORIZED (401): auth failed
-                raise InvalidCredsError()
-            else:
-                # Any response code != 401 or 204, something is wrong
-                raise MalformedResponseError('Malformed response',
-                        body='code: %s body:%s' % (resp.status, ''.join(resp.body.readlines())),
-                        driver=self.driver)
+            if self.auth_url == None:
+                raise LibcloudError('OpenStack instance must have auth_url set')
+
+            osa = OpenStackAuthConnection(self, self.auth_url, self.user_id, self.key)
+
+            # may throw InvalidCreds, etc
+            osa.authenticate()
+
+            self.auth_token = osa.auth_token
+
+            # TODO: Multi-region support
+            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")
 
             for key in ['server_url', 'storage_url', 'cdn_management_url',
                         'lb_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(getattr(self, key)))
+                    urlparse.urlparse(base_url))
                 # Set host to where we want to make further requests to
                 setattr(self, '__%s' % (key), server)
                 setattr(self, '__request_path_%s' % (key), request_path)
 
-            conn.close()
+            (self.host, self.port, self.secure, self.request_path) = self._tuple_from_url(self.base_url)

Modified: libcloud/trunk/libcloud/common/rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/common/rackspace.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/common/rackspace.py (original)
+++ libcloud/trunk/libcloud/common/rackspace.py Sat Sep 17 23:35:45 2011
@@ -17,10 +17,10 @@
 Common settings for Rackspace Cloud Servers and Cloud Files
 """
 
-AUTH_HOST_US = 'auth.api.rackspacecloud.com'
-AUTH_HOST_UK = 'lon.auth.api.rackspacecloud.com'
+AUTH_URL_US = 'https://auth.api.rackspacecloud.com/v1.1/'
+AUTH_URL_UK = 'https://lon.auth.api.rackspacecloud.com/v1.1/'
 
 __all__ = [
-    "AUTH_HOST_US",
-    "AUTH_HOST_UK",
+    "AUTH_URL_US",
+    "AUTH_URL_UK",
     ]

Modified: libcloud/trunk/libcloud/compute/base.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/base.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/base.py (original)
+++ libcloud/trunk/libcloud/compute/base.py Sat Sep 17 23:35:45 2011
@@ -382,11 +382,14 @@ class NodeDriver(object):
         if port != None:
             args.append(port)
 
-        self.connection = self.connectionCls(*args)
+        self.connection = self.connectionCls(*args, **self._ex_connection_class_kwargs())
 
         self.connection.driver = self
         self.connection.connect()
 
+    def _ex_connection_class_kwargs(self):
+        return {}
+
     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=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/openstack.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/openstack.py Sat Sep 17 23:35:45 2011
@@ -89,9 +89,9 @@ class OpenStackConnection(OpenStackBaseC
     responseCls = OpenStackResponse
     _url_key = "server_url"
 
-    def __init__(self, user_id, key, secure, host=None, port=None):
+    def __init__(self, user_id, key, secure=True, host=None, port=None, ex_force_base_url=None):
         super(OpenStackConnection, self).__init__(
-            user_id, key, secure=secure, host=host, port=port)
+            user_id, key, host=host, port=port, ex_force_base_url=ex_force_base_url)
         self.api_version = 'v1.0'
         self.accept_format = 'application/xml'
 
@@ -101,9 +101,7 @@ class OpenStackConnection(OpenStackBaseC
             headers = {}
         if not params:
             params = {}
-        # Due to first-run authentication request, we may not have a path
-        if self.server_url:
-            action = self.server_url + action
+
         if method in ("POST", "PUT"):
             headers = {'Content-Type': 'application/xml; charset=UTF-8'}
         if method == "GET":
@@ -149,6 +147,16 @@ class OpenStackNodeDriver(NodeDriver):
                       'DELETE_IP': NodeState.PENDING,
                       'UNKNOWN': NodeState.UNKNOWN}
 
+    def __init__(self, *args, **kwargs):
+        self._ex_force_base_url = kwargs.pop('ex_force_base_url', None)
+        super(OpenStackNodeDriver, self).__init__(*args, **kwargs)
+
+    def _ex_connection_class_kwargs(self):
+        if self._ex_force_base_url:
+            return {'ex_force_base_url': self._ex_force_base_url}
+        return {}
+
+
     def list_nodes(self):
         return self._to_nodes(self.connection.request('/servers/detail')
                                              .object)

Modified: libcloud/trunk/libcloud/compute/drivers/rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/rackspace.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/rackspace.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/rackspace.py Sat Sep 17 23:35:45 2011
@@ -20,7 +20,7 @@ from libcloud.compute.base import NodeLo
 from libcloud.compute.drivers.openstack import OpenStackConnection, OpenStackNodeDriver, OpenStackResponse
 
 from libcloud.common.rackspace import (
-    AUTH_HOST_US, AUTH_HOST_UK)
+    AUTH_URL_US, AUTH_URL_UK)
 
 
 class RackspaceConnection(OpenStackConnection):
@@ -29,7 +29,7 @@ class RackspaceConnection(OpenStackConne
     """
 
     responseCls = OpenStackResponse
-    auth_host = AUTH_HOST_US
+    auth_url = AUTH_URL_US
 
 
 class RackspaceNodeDriver(OpenStackNodeDriver):
@@ -51,7 +51,7 @@ class RackspaceUKConnection(RackspaceCon
     """
     Connection class for the Rackspace UK driver
     """
-    auth_host = AUTH_HOST_UK
+    auth_url = AUTH_URL_UK
 
 
 class RackspaceUKNodeDriver(RackspaceNodeDriver):

Modified: libcloud/trunk/libcloud/compute/drivers/rimuhosting.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/rimuhosting.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/rimuhosting.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/rimuhosting.py Sat Sep 17 23:35:45 2011
@@ -28,8 +28,6 @@ from libcloud.compute.base import NodeIm
 
 API_CONTEXT = '/r'
 API_HOST = 'rimuhosting.com'
-API_PORT = (80,443)
-API_SECURE = True
 
 class RimuHostingException(Exception):
     """
@@ -78,7 +76,7 @@ class RimuHostingConnection(ConnectionKe
 
     api_context = API_CONTEXT
     host = API_HOST
-    port = API_PORT
+    port = 443
     responseCls = RimuHostingResponse
 
     def __init__(self, key, secure=True):
@@ -113,8 +111,8 @@ class RimuHostingNodeDriver(NodeDriver):
     name = 'RimuHosting'
     connectionCls = RimuHostingConnection
 
-    def __init__(self, key, host=API_HOST, port=API_PORT,
-                 api_context=API_CONTEXT, secure=API_SECURE):
+    def __init__(self, key, host=API_HOST, port=443,
+                 api_context=API_CONTEXT, secure=True):
         # Pass in some extra vars so that
         self.key = key
         self.secure = secure

Modified: libcloud/trunk/libcloud/compute/drivers/vcloud.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/vcloud.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/vcloud.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/vcloud.py Sat Sep 17 23:35:45 2011
@@ -244,7 +244,7 @@ class VCloudConnection(ConnectionUserAnd
     def _get_auth_token(self):
         if not self.token:
             conn = self.conn_classes[self.secure](self.host,
-                                                  self.port[self.secure])
+                                                  self.port)
             conn.request(method='POST', url='/api/v0.8/login',
                          headers=self._get_auth_headers())
 

Modified: libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py (original)
+++ libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py Sat Sep 17 23:35:45 2011
@@ -27,7 +27,7 @@ from libcloud.loadbalancer.base import D
 from libcloud.loadbalancer.types import State
 from libcloud.common.openstack import OpenStackBaseConnection
 from libcloud.common.rackspace import (
-        AUTH_HOST_US, AUTH_HOST_UK)
+        AUTH_URL_US, AUTH_URL_UK)
 
 class RackspaceResponse(Response):
 
@@ -43,7 +43,7 @@ class RackspaceResponse(Response):
 
 class RackspaceConnection(OpenStackBaseConnection):
     responseCls = RackspaceResponse
-    auth_host = AUTH_HOST_US
+    auth_url = AUTH_URL_US
     _url_key = "lb_url"
 
     def __init__(self, user_id, key, secure=True):
@@ -56,8 +56,7 @@ class RackspaceConnection(OpenStackBaseC
             headers = {}
         if not params:
             params = {}
-        if self.lb_url:
-            action = self.lb_url + action
+
         if method in ('POST', 'PUT'):
             headers['Content-Type'] = 'application/json'
         if method == 'GET':
@@ -68,7 +67,7 @@ class RackspaceConnection(OpenStackBaseC
 
 
 class RackspaceUKConnection(RackspaceConnection):
-    auth_host = AUTH_HOST_UK
+    auth_url = AUTH_URL_UK
 
 
 class RackspaceLBDriver(Driver):

Modified: libcloud/trunk/libcloud/storage/drivers/cloudfiles.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/storage/drivers/cloudfiles.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/libcloud/storage/drivers/cloudfiles.py (original)
+++ libcloud/trunk/libcloud/storage/drivers/cloudfiles.py Sat Sep 17 23:35:45 2011
@@ -37,7 +37,7 @@ from libcloud.common.types import LazyLi
 from libcloud.common.openstack import OpenStackBaseConnection
 
 from libcloud.common.rackspace import (
-    AUTH_HOST_US, AUTH_HOST_UK)
+    AUTH_URL_US, AUTH_URL_UK)
 
 CDN_HOST = 'cdn.clouddrive.com'
 API_VERSION = 'v1.0'
@@ -88,9 +88,9 @@ class CloudFilesConnection(OpenStackBase
     Base connection class for the Cloudfiles driver.
     """
 
+    auth_url = AUTH_URL_US
     responseCls = CloudFilesResponse
     rawResponseCls = CloudFilesRawResponse
-    auth_host = None
     _url_key = "storage_url"
 
     def __init__(self, user_id, key, secure=True):
@@ -110,10 +110,8 @@ class CloudFilesConnection(OpenStackBase
         else:
             host = None
 
-        # Due to first-run authentication request, we may not have a path
-        if self.request_path:
-            action = self.request_path + action
-            params['format'] = 'json'
+        params['format'] = 'json'
+
         if method in [ 'POST', 'PUT' ]:
             headers.update({'Content-Type': 'application/json; charset=UTF-8'})
 
@@ -121,8 +119,7 @@ class CloudFilesConnection(OpenStackBase
             action=action,
             params=params, data=data,
             method=method, headers=headers,
-            raw=raw, host=host
-        )
+            raw=raw)
 
 
 class CloudFilesUSConnection(CloudFilesConnection):
@@ -130,7 +127,7 @@ class CloudFilesUSConnection(CloudFilesC
     Connection class for the Cloudfiles US endpoint.
     """
 
-    auth_host = AUTH_HOST_US
+    auth_url = AUTH_URL_US
 
 
 class CloudFilesUKConnection(CloudFilesConnection):
@@ -138,7 +135,7 @@ class CloudFilesUKConnection(CloudFilesC
     Connection class for the Cloudfiles UK endpoint.
     """
 
-    auth_host = AUTH_HOST_UK
+    auth_url = AUTH_URL_UK
 
 
 class CloudFilesStorageDriver(StorageDriver):
@@ -149,6 +146,7 @@ class CloudFilesStorageDriver(StorageDri
     class.
     """
     name = 'CloudFiles'
+
     connectionCls = CloudFilesConnection
     hash_type = 'md5'
 

Modified: libcloud/trunk/test/compute/test_deployment.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/test_deployment.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/test/compute/test_deployment.py (original)
+++ libcloud/trunk/test/compute/test_deployment.py Sat Sep 17 23:35:45 2011
@@ -27,7 +27,7 @@ from libcloud.compute.ssh import BaseSSH
 from libcloud.compute.drivers.rackspace import RackspaceNodeDriver as Rackspace
 
 from test import MockHttp, XML_HEADERS
-from test.file_fixtures import ComputeFileFixtures
+from test.file_fixtures import ComputeFileFixtures, OpenStackFixtures
 from mock import Mock, patch
 
 from test.secrets import RACKSPACE_PARAMS
@@ -321,6 +321,11 @@ class DeploymentTests(unittest.TestCase)
 class RackspaceMockHttp(MockHttp):
 
     fixtures = ComputeFileFixtures('openstack')
+    auth_fixtures = OpenStackFixtures()
+
+    def _v1_1__auth(self, method, url, body, headers):
+        body = self.auth_fixtures.load('_v1_1__auth.json')
+        return (httplib.OK, body, {'content-type': 'application/json; charset=UTF-8'}, httplib.responses[httplib.OK])
 
     # fake auth token response
     def _v1_0(self, method, url, body, headers):

Modified: libcloud/trunk/test/compute/test_openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/test_openstack.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/test/compute/test_openstack.py (original)
+++ libcloud/trunk/test/compute/test_openstack.py Sat Sep 17 23:35:45 2011
@@ -22,7 +22,7 @@ from libcloud.compute.base import Node, 
 from libcloud.pricing import set_pricing, clear_pricing_data
 
 from test import MockResponse, MockHttpTestCase, XML_HEADERS
-from test.file_fixtures import ComputeFileFixtures
+from test.file_fixtures import ComputeFileFixtures, OpenStackFixtures
 from test.compute import TestCaseMixin
 
 from test.secrets import OPENSTACK_PARAMS
@@ -66,6 +66,7 @@ class OpenStackTests(unittest.TestCase, 
 
     def setUp(self):
         self.driver_type.connectionCls.conn_classes = (OpenStackMockHttp, OpenStackMockHttp)
+        self.driver_type.connectionCls.auth_url = "https://auth.api.example.com/v1.1/"
         OpenStackMockHttp.type = None
         self.driver = self.create_driver()
         clear_pricing_data()
@@ -292,6 +293,8 @@ class OpenStackTests(unittest.TestCase, 
 
 class OpenStackMockHttp(MockHttpTestCase):
     fixtures = ComputeFileFixtures('openstack')
+    auth_fixtures = OpenStackFixtures()
+    json_content_headers = {'content-type': 'application/json; charset=UTF-8'}
 
     # fake auth token response
     def _v1_0(self, method, url, body, headers):
@@ -408,6 +411,22 @@ class OpenStackMockHttp(MockHttpTestCase
         headers.update(XML_HEADERS)
         return (httplib.OK, body, headers, httplib.responses[httplib.OK])
 
+    def _v1_1__auth(self, method, url, body, headers):
+        body = self.auth_fixtures.load('_v1_1__auth.json')
+        return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+
+    def _v1_1__auth_UNAUTHORIZED(self, method, url, body, headers):
+        body = self.auth_fixtures.load('_v1_1__auth_unauthorized.json')
+        return  (httplib.UNAUTHORIZED, body, self.json_content_headers, httplib.responses[httplib.UNAUTHORIZED])
+
+    def _v1_1__auth_UNAUTHORIZED_MISSING_KEY(self, method, url, body, headers):
+        body = self.auth_fixtures.load('_v1_1__auth_mssing_token.json')
+        return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+
+    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])
+
+
 
 if __name__ == '__main__':
     sys.exit(unittest.main())

Modified: libcloud/trunk/test/file_fixtures.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/file_fixtures.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/test/file_fixtures.py (original)
+++ libcloud/trunk/test/file_fixtures.py Sat Sep 17 23:35:45 2011
@@ -22,6 +22,7 @@ FIXTURES_ROOT = {
     'compute': 'compute/fixtures',
     'storage': 'storage/fixtures',
     'loadbalancer': 'loadbalancer/fixtures',
+    'openstack': 'openstack/fixtures',
 }
 
 class FileFixtures(object):
@@ -53,3 +54,8 @@ class LoadBalancerFileFixtures(FileFixtu
     def __init__(self, sub_dir=''):
         super(LoadBalancerFileFixtures, self).__init__(fixtures_type='loadbalancer',
                                                   sub_dir=sub_dir)
+
+class OpenStackFixtures(FileFixtures):
+  def __init__(self, sub_dir=''):
+      super(OpenStackFixtures, self).__init__(fixtures_type='openstack',
+                                                sub_dir=sub_dir)

Modified: libcloud/trunk/test/loadbalancer/test_rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/test_rackspace.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/test/loadbalancer/test_rackspace.py (original)
+++ libcloud/trunk/test/loadbalancer/test_rackspace.py Sat Sep 17 23:35:45 2011
@@ -27,7 +27,7 @@ from libcloud.loadbalancer.drivers.racks
 from libcloud.loadbalancer.drivers.rackspace import RackspaceUKLBDriver
 
 from test import MockHttpTestCase
-from test.file_fixtures import LoadBalancerFileFixtures
+from test.file_fixtures import LoadBalancerFileFixtures, OpenStackFixtures
 
 class RackspaceLBTests(unittest.TestCase):
 
@@ -110,6 +110,7 @@ class RackspaceUKLBTests(RackspaceLBTest
 
 class RackspaceLBMockHttp(MockHttpTestCase):
     fixtures = LoadBalancerFileFixtures('rackspace')
+    auth_fixtures = OpenStackFixtures()
 
     def _v1_0(self, method, url, body, headers):
         headers = {'x-server-management-url': 'https://servers.api.rackspacecloud.com/v1.0/slug',
@@ -166,5 +167,10 @@ class RackspaceLBMockHttp(MockHttpTestCa
 
         raise NotImplementedError
 
+    def _v1_1__auth(self, method, url, body, headers):
+        headers = { 'content-type': 'application/json; charset=UTF-8'}
+        body = self.auth_fixtures.load('_v1_1__auth.json')
+        return (httplib.OK, body, headers, httplib.responses[httplib.OK])
+
 if __name__ == "__main__":
     sys.exit(unittest.main())

Added: libcloud/trunk/test/openstack/fixtures/_v1_1__auth.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/openstack/fixtures/_v1_1__auth.json?rev=1172148&view=auto
==============================================================================
--- libcloud/trunk/test/openstack/fixtures/_v1_1__auth.json (added)
+++ libcloud/trunk/test/openstack/fixtures/_v1_1__auth.json Sat Sep 17 23:35:45 2011
@@ -0,0 +1 @@
+{"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}]}}}

Added: libcloud/trunk/test/openstack/fixtures/_v1_1__auth_mssing_token.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/openstack/fixtures/_v1_1__auth_mssing_token.json?rev=1172148&view=auto
==============================================================================
--- libcloud/trunk/test/openstack/fixtures/_v1_1__auth_mssing_token.json (added)
+++ libcloud/trunk/test/openstack/fixtures/_v1_1__auth_mssing_token.json Sat Sep 17 23:35:45 2011
@@ -0,0 +1 @@
+{"auth":{"token":{"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}]}}}

Added: libcloud/trunk/test/openstack/fixtures/_v1_1__auth_unauthorized.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/openstack/fixtures/_v1_1__auth_unauthorized.json?rev=1172148&view=auto
==============================================================================
--- libcloud/trunk/test/openstack/fixtures/_v1_1__auth_unauthorized.json (added)
+++ libcloud/trunk/test/openstack/fixtures/_v1_1__auth_unauthorized.json Sat Sep 17 23:35:45 2011
@@ -0,0 +1 @@
+{"unauthorized":{"message":"Username or api key is invalid","code":401}}
\ No newline at end of file

Modified: libcloud/trunk/test/storage/test_cloudfiles.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/storage/test_cloudfiles.py?rev=1172148&r1=1172147&r2=1172148&view=diff
==============================================================================
--- libcloud/trunk/test/storage/test_cloudfiles.py (original)
+++ libcloud/trunk/test/storage/test_cloudfiles.py Sat Sep 17 23:35:45 2011
@@ -33,7 +33,7 @@ from libcloud.storage.drivers.cloudfiles
 from libcloud.storage.drivers.dummy import DummyIterator
 
 from test import StorageMockHttp, MockRawResponse # pylint: disable-msg=E0611
-from test.file_fixtures import StorageFileFixtures # pylint: disable-msg=E0611
+from test.file_fixtures import StorageFileFixtures, OpenStackFixtures # pylint: disable-msg=E0611
 
 current_hash = None
 
@@ -426,6 +426,7 @@ class CloudFilesTests(unittest.TestCase)
 class CloudFilesMockHttp(StorageMockHttp):
 
     fixtures = StorageFileFixtures('cloudfiles')
+    auth_fixtures = OpenStackFixtures()
     base_headers = { 'content-type': 'application/json; charset=UTF-8'}
 
     # fake auth token response
@@ -625,6 +626,11 @@ class CloudFilesMockHttp(StorageMockHttp
 
         return (status_code, body, headers, httplib.responses[httplib.OK])
 
+    def _v1_1__auth(self, method, url, body, headers):
+        body = self.auth_fixtures.load('_v1_1__auth.json')
+        return (httplib.OK, body, {'content-type': 'application/json; charset=UTF-8'}, httplib.responses[httplib.OK])
+
+
 class CloudFilesMockRawResponse(MockRawResponse):
 
     fixtures = StorageFileFixtures('cloudfiles')