Skip to content
Browse files

Add a new mixin class and make all the OpenStack based drivers inheri…

…t from it.

This way all the OpenStack based drivers accept the same extenstion keyword
arguments. This patch has been contributed by Dave King and is part of
LIBCLOUD-167.


git-svn-id: https://svn.apache.org/repos/asf/libcloud/trunk@1301741 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information...
1 parent abe09bb commit cf90e1e71d93cd339191336e8d63161e9d93429b @Kami Kami committed Mar 16, 2012
View
2 libcloud/common/base.py
@@ -769,7 +769,7 @@ class BaseDriver(object):
connectionCls = ConnectionKey
def __init__(self, key, secret=None, secure=True, host=None, port=None,
- api_version=None):
+ api_version=None, **kwargs):
"""
@keyword key: API key or username to used
@type key: str
View
21 libcloud/common/openstack.py
@@ -418,3 +418,24 @@ def _add_cache_busting_to_params(self, params):
params['cache-busting'] = cache_busting_number
else:
params.append(('cache-busting', cache_busting_number))
+
+
+class OpenStackDriverMixin(object):
+
+ def __init__(self, *args, **kwargs):
+ self._ex_force_base_url = kwargs.get('ex_force_base_url', None)
+ self._ex_force_auth_url = kwargs.get('ex_force_auth_url', None)
+ self._ex_force_auth_version = kwargs.get('ex_force_auth_version', None)
+ self._ex_force_auth_token = kwargs.get('ex_force_auth_token', None)
+
+ def openstack_connection_kwargs(self):
+ rv = {}
+ if self._ex_force_base_url:
+ rv['ex_force_base_url'] = self._ex_force_base_url
+ if self._ex_force_auth_token:
+ rv['ex_force_auth_token'] = self._ex_force_auth_token
+ 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
View
4 libcloud/compute/base.py
@@ -392,10 +392,10 @@ class NodeDriver(BaseDriver):
NODE_STATE_MAP = {}
def __init__(self, key, secret=None, secure=True, host=None, port=None,
- api_version=None):
+ api_version=None, **kwargs):
super(NodeDriver, self).__init__(key=key, secret=secret, secure=secure,
host=host, port=port,
- api_version=api_version)
+ api_version=api_version, **kwargs)
def create_node(self, **kwargs):
"""Create a new node instance.
View
24 libcloud/compute/drivers/openstack.py
@@ -36,7 +36,7 @@
from xml.etree import ElementTree as ET
-from libcloud.common.openstack import OpenStackBaseConnection
+from libcloud.common.openstack import OpenStackBaseConnection, OpenStackDriverMixin
from libcloud.common.types import MalformedResponseError, LibcloudError
from libcloud.compute.types import NodeState, Provider
from libcloud.compute.base import NodeSize, NodeImage
@@ -156,7 +156,7 @@ def request(self, action, params=None, data='', headers=None,
method=method, headers=headers)
-class OpenStackNodeDriver(NodeDriver):
+class OpenStackNodeDriver(NodeDriver, OpenStackDriverMixin):
"""
Base OpenStack node driver. Should not be used directly.
"""
@@ -193,6 +193,10 @@ def __new__(cls, key, secret=None, secure=True, host=None, port=None,
(api_version))
return super(OpenStackNodeDriver, cls).__new__(cls)
+ def __init__(self, *args, **kwargs):
+ OpenStackDriverMixin.__init__(self, **kwargs)
+ super(OpenStackNodeDriver, self).__init__(*args, **kwargs)
+
def destroy_node(self, node):
uri = '/servers/%s' % (node.id)
resp = self.connection.request(uri, method='DELETE')
@@ -222,14 +226,7 @@ def list_locations(self):
return [NodeLocation(0, '', '', self)]
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
+ return self.openstack_connection_kwargs()
def ex_get_node_details(self, node_id):
# @TODO: Remove this if in 0.6
@@ -284,9 +281,6 @@ class OpenStack_1_0_NodeDriver(OpenStackNodeDriver):
features = {"create_node": ["generates_password"]}
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
@@ -802,10 +796,6 @@ class OpenStack_1_1_NodeDriver(OpenStackNodeDriver):
features = {"create_node": ["generates_password"]}
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)
View
4 libcloud/dns/base.py
@@ -132,9 +132,9 @@ class DNSDriver(BaseDriver):
connectionCls = ConnectionUserAndKey
name = None
- def __init__(self, key, secret=None, secure=True, host=None, port=None):
+ def __init__(self, key, secret=None, secure=True, host=None, port=None, **kwargs):
super(DNSDriver, self).__init__(key=key, secret=secret, secure=secure,
- host=host, port=port)
+ host=host, port=port, **kwargs)
def list_record_types(self):
"""
View
10 libcloud/dns/drivers/rackspace.py
@@ -12,6 +12,7 @@
# 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.
+from libcloud.common.openstack import OpenStackDriverMixin
__all__ = [
'RackspaceUSDNSDriver',
@@ -118,7 +119,14 @@ class RackspaceUKDNSConnection(RackspaceDNSConnection):
auth_url = AUTH_URL_UK
-class RackspaceDNSDriver(DNSDriver):
+class RackspaceDNSDriver(DNSDriver, OpenStackDriverMixin):
+
+ def __init__(self, *args, **kwargs):
+ OpenStackDriverMixin.__init__(self, *args, **kwargs)
+ super(RackspaceDNSDriver, self).__init__(*args, **kwargs)
+
+ def _ex_connection_class_kwargs(self):
+ return self.openstack_connection_kwargs()
RECORD_TYPE_MAP = {
RecordType.A: 'A',
View
4 libcloud/loadbalancer/base.py
@@ -96,9 +96,9 @@ class Driver(BaseDriver):
_ALGORITHM_TO_VALUE_MAP = {}
_VALUE_TO_ALGORITHM_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, **kwargs):
super(Driver, self).__init__(key=key, secret=secret, secure=secure,
- host=host, port=port)
+ host=host, port=port, **kwargs)
def list_protocols(self):
"""
View
11 libcloud/loadbalancer/drivers/rackspace.py
@@ -29,7 +29,7 @@
from libcloud.common.types import LibcloudError
from libcloud.common.base import JsonResponse, PollingConnection
from libcloud.loadbalancer.types import State, MemberCondition
-from libcloud.common.openstack import OpenStackBaseConnection
+from libcloud.common.openstack import OpenStackBaseConnection, OpenStackDriverMixin
from libcloud.common.rackspace import (
AUTH_URL_US, AUTH_URL_UK)
@@ -286,7 +286,7 @@ class RackspaceUKConnection(RackspaceConnection):
auth_url = AUTH_URL_UK
-class RackspaceLBDriver(Driver):
+class RackspaceLBDriver(Driver, OpenStackDriverMixin):
connectionCls = RackspaceConnection
api_name = 'rackspace_lb'
name = 'Rackspace LB'
@@ -318,6 +318,13 @@ class RackspaceLBDriver(Driver):
_ALGORITHM_TO_VALUE_MAP = reverse_dict(_VALUE_TO_ALGORITHM_MAP)
+ def __init__(self, *args, **kwargs):
+ OpenStackDriverMixin.__init__(self, *args, **kwargs)
+ super(RackspaceLBDriver, self).__init__(*args, **kwargs)
+
+ def _ex_connection_class_kwargs(self):
+ return self.openstack_connection_kwargs()
+
def list_protocols(self):
return self._to_protocols(
self.connection.request('/loadbalancers/protocols').object)
View
4 libcloud/storage/base.py
@@ -164,9 +164,9 @@ class StorageDriver(BaseDriver):
hash_type = 'md5'
supports_chunked_encoding = False
- def __init__(self, key, secret=None, secure=True, host=None, port=None):
+ def __init__(self, key, secret=None, secure=True, host=None, port=None, **kwargs):
super(StorageDriver, self).__init__(key=key, secret=secret, secure=secure,
- host=host, port=port)
+ host=host, port=port, **kwargs)
def list_containters(self):
"""
View
22 libcloud/storage/drivers/cloudfiles.py
@@ -40,7 +40,7 @@
from libcloud.storage.types import ObjectHashMismatchError
from libcloud.storage.types import InvalidContainerNameError
from libcloud.common.types import LazyList
-from libcloud.common.openstack import OpenStackBaseConnection
+from libcloud.common.openstack import OpenStackBaseConnection, OpenStackDriverMixin
from libcloud.common.rackspace import (
AUTH_URL_US, AUTH_URL_UK)
@@ -139,12 +139,14 @@ def request(self, action, params=None, data='', headers=None, method='GET',
params = {}
# FIXME: Massive hack.
- # This driver dynamically changes the url in it's connection, based on arguments
+ # This driver dynamically changes the url in its 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)
+ if not self._ex_force_base_url:
+ self._reset_connection_params(self.get_endpoint(cdn_request))
+ else:
+ self._reset_connection_params(self._ex_force_base_url)
params['format'] = 'json'
@@ -157,6 +159,9 @@ def request(self, action, params=None, data='', headers=None, method='GET',
method=method, headers=headers,
raw=raw)
+ def _reset_connection_params(self, endpoint_url):
+ (self.host, self.port, self.secure, self.request_path) = self._tuple_from_url(endpoint_url)
+
class CloudFilesUSConnection(CloudFilesConnection):
"""
@@ -174,7 +179,7 @@ class CloudFilesUKConnection(CloudFilesConnection):
auth_url = AUTH_URL_UK
-class CloudFilesStorageDriver(StorageDriver):
+class CloudFilesStorageDriver(StorageDriver, OpenStackDriverMixin):
"""
Base CloudFiles driver.
@@ -187,6 +192,10 @@ class CloudFilesStorageDriver(StorageDriver):
hash_type = 'md5'
supports_chunked_encoding = True
+ def __init__(self, *args, **kwargs):
+ OpenStackDriverMixin.__init__(self, *args, **kwargs)
+ super(CloudFilesStorageDriver, self).__init__(*args, **kwargs)
+
def list_containers(self):
response = self.connection.request('')
@@ -539,6 +548,9 @@ def _headers_to_object(self, name, container, headers):
meta_data=meta_data, container=container, driver=self)
return obj
+ def _ex_connection_class_kwargs(self):
+ return self.openstack_connection_kwargs()
+
class CloudFilesUSStorageDriver(CloudFilesStorageDriver):
"""
Cloudfiles storage driver for the US endpoint.
View
33 test/compute/test_openstack.py
@@ -24,7 +24,8 @@
from libcloud.utils.py3 import method_type
from libcloud.utils.py3 import u
-from libcloud.common.types import InvalidCredsError, MalformedResponseError
+from libcloud.common.types import InvalidCredsError, MalformedResponseError, \
+ LibcloudError
from libcloud.compute.types import Provider
from libcloud.compute.providers import get_driver
from libcloud.compute.drivers.openstack import (
@@ -574,6 +575,36 @@ def test_set_auth_token_populates_host_port_and_request_path(self):
self.assertEqual(self.driver.connection.port, '1222')
self.assertEqual(self.driver.connection.request_path, '/some-service')
+ def test_auth_token_without_base_url_raises_exception(self):
+ kwargs = {
+ 'ex_force_auth_version': '2.0',
+ 'ex_force_auth_token': 'preset-auth-token'
+ }
+ try:
+ self.driver_type(*self.driver_args, **kwargs)
+ self.fail('Expected failure setting auth token without base url')
+ except LibcloudError as e:
+ pass
+ else:
+ self.fail('Expected failure setting auth token without base url')
+
+ def test_ex_force_auth_token_passed_to_connection(self):
+ base_url = 'https://servers.api.rackspacecloud.com/v1.1/slug'
+ kwargs = {
+ 'ex_force_auth_version': '2.0',
+ 'ex_force_auth_token': 'preset-auth-token',
+ 'ex_force_base_url': base_url
+ }
+ driver = self.driver_type(*self.driver_args, **kwargs)
+ driver.list_nodes()
+
+ self.assertEquals(kwargs['ex_force_auth_token'],
+ driver.connection.auth_token)
+ self.assertEquals('servers.api.rackspacecloud.com',
+ driver.connection.host)
+ self.assertEquals('/v1.1/slug', driver.connection.request_path)
+ self.assertEquals(443, driver.connection.port)
+
def test_list_nodes(self):
nodes = self.driver.list_nodes()
self.assertEqual(len(nodes), 2)
View
25 test/dns/test_rackspace.py
@@ -40,6 +40,31 @@ def setUp(self):
# normally authentication happens lazily, but we force it here
self.driver.connection._populate_hosts_and_request_paths()
+ def test_force_auth_token_kwargs(self):
+ kwargs = {
+ 'ex_force_auth_token': 'some-auth-token',
+ 'ex_force_base_url': 'https://dns.api.rackspacecloud.com/v1.0/11111'
+ }
+ driver = self.klass(*DNS_PARAMS_RACKSPACE, **kwargs)
+ driver.list_zones()
+
+ self.assertEquals(kwargs['ex_force_auth_token'],
+ driver.connection.auth_token)
+ self.assertEquals('/v1.0/11111',
+ driver.connection.request_path)
+
+ def test_force_auth_url_kwargs(self):
+ kwargs = {
+ 'ex_force_auth_version': '2.0',
+ 'ex_force_auth_url': 'https://identity.api.rackspace.com'
+ }
+ driver = self.klass(*DNS_PARAMS_RACKSPACE, **kwargs)
+
+ self.assertEquals(kwargs['ex_force_auth_url'],
+ driver.connection._ex_force_auth_url)
+ self.assertEquals(kwargs['ex_force_auth_version'],
+ driver.connection._auth_version)
+
def test_list_record_types(self):
record_types = self.driver.list_record_types()
self.assertEqual(len(record_types), 7)
View
26 test/loadbalancer/test_rackspace.py
@@ -47,6 +47,32 @@ def setUp(self):
# normally authentication happens lazily, but we force it here
self.driver.connection._populate_hosts_and_request_paths()
+ def test_force_auth_token_kwargs(self):
+ base_url = 'https://ord.loadbalancer.api.rackspacecloud.com/v1.0/slug'
+ kwargs = {
+ 'ex_force_auth_token': 'some-auth-token',
+ 'ex_force_base_url': base_url
+ }
+ driver = RackspaceLBDriver('user', 'key', **kwargs)
+ driver.list_balancers()
+
+ self.assertEquals(kwargs['ex_force_auth_token'],
+ driver.connection.auth_token)
+ self.assertEquals('/v1.0/slug',
+ driver.connection.request_path)
+
+ def test_force_auth_url_kwargs(self):
+ kwargs = {
+ 'ex_force_auth_version': '2.0',
+ 'ex_force_auth_url': 'https://identity.api.rackspace.com'
+ }
+ driver = RackspaceLBDriver('user', 'key', **kwargs)
+
+ self.assertEquals(kwargs['ex_force_auth_url'],
+ driver.connection._ex_force_auth_url)
+ self.assertEquals(kwargs['ex_force_auth_version'],
+ driver.connection._auth_version)
+
def test_list_protocols(self):
protocols = self.driver.list_protocols()
View
28 test/storage/test_cloudfiles.py
@@ -60,6 +60,34 @@ def setUp(self):
def tearDown(self):
self._remove_test_file()
+ def test_force_auth_token_kwargs(self):
+ base_url = 'https://cdn2.clouddrive.com/v1/MossoCloudFS'
+ kwargs = {
+ 'ex_force_auth_token': 'some-auth-token',
+ 'ex_force_base_url': base_url
+ }
+ driver = CloudFilesStorageDriver('driver', 'dummy', **kwargs)
+ driver.list_containers()
+
+ self.assertEquals(kwargs['ex_force_auth_token'],
+ driver.connection.auth_token)
+ self.assertEquals('cdn2.clouddrive.com',
+ driver.connection.host)
+ self.assertEquals('/v1/MossoCloudFS',
+ driver.connection.request_path)
+
+ def test_force_auth_url_kwargs(self):
+ kwargs = {
+ 'ex_force_auth_version': '2.0',
+ 'ex_force_auth_url': 'https://identity.api.rackspace.com'
+ }
+ driver = CloudFilesStorageDriver('driver', 'dummy', **kwargs)
+
+ self.assertEquals(kwargs['ex_force_auth_url'],
+ driver.connection._ex_force_auth_url)
+ self.assertEquals(kwargs['ex_force_auth_version'],
+ driver.connection._auth_version)
+
def test_invalid_json_throws_exception(self):
CloudFilesMockHttp.type = 'MALFORMED_JSON'
try:

0 comments on commit cf90e1e

Please sign in to comment.
Something went wrong with that request. Please try again.