Skip to content

Commit

Permalink
Add a new mixin class and make all the OpenStack based drivers inheri…
Browse files Browse the repository at this point in the history
…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
Kami committed Mar 16, 2012
1 parent abe09bb commit cf90e1e
Show file tree
Hide file tree
Showing 14 changed files with 183 additions and 35 deletions.
2 changes: 1 addition & 1 deletion libcloud/common/base.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ class BaseDriver(object):
connectionCls = ConnectionKey connectionCls = ConnectionKey


def __init__(self, key, secret=None, secure=True, host=None, port=None, def __init__(self, key, secret=None, secure=True, host=None, port=None,
api_version=None): api_version=None, **kwargs):
""" """
@keyword key: API key or username to used @keyword key: API key or username to used
@type key: str @type key: str
Expand Down
21 changes: 21 additions & 0 deletions libcloud/common/openstack.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -418,3 +418,24 @@ def _add_cache_busting_to_params(self, params):
params['cache-busting'] = cache_busting_number params['cache-busting'] = cache_busting_number
else: else:
params.append(('cache-busting', cache_busting_number)) 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
4 changes: 2 additions & 2 deletions libcloud/compute/base.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -392,10 +392,10 @@ class NodeDriver(BaseDriver):
NODE_STATE_MAP = {} NODE_STATE_MAP = {}


def __init__(self, key, secret=None, secure=True, host=None, port=None, def __init__(self, key, secret=None, secure=True, host=None, port=None,
api_version=None): api_version=None, **kwargs):
super(NodeDriver, self).__init__(key=key, secret=secret, secure=secure, super(NodeDriver, self).__init__(key=key, secret=secret, secure=secure,
host=host, port=port, host=host, port=port,
api_version=api_version) api_version=api_version, **kwargs)


def create_node(self, **kwargs): def create_node(self, **kwargs):
"""Create a new node instance. """Create a new node instance.
Expand Down
24 changes: 7 additions & 17 deletions libcloud/compute/drivers/openstack.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@


from xml.etree import ElementTree as ET 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.common.types import MalformedResponseError, LibcloudError
from libcloud.compute.types import NodeState, Provider from libcloud.compute.types import NodeState, Provider
from libcloud.compute.base import NodeSize, NodeImage from libcloud.compute.base import NodeSize, NodeImage
Expand Down Expand Up @@ -156,7 +156,7 @@ def request(self, action, params=None, data='', headers=None,
method=method, headers=headers) method=method, headers=headers)




class OpenStackNodeDriver(NodeDriver): class OpenStackNodeDriver(NodeDriver, OpenStackDriverMixin):
""" """
Base OpenStack node driver. Should not be used directly. Base OpenStack node driver. Should not be used directly.
""" """
Expand Down Expand Up @@ -193,6 +193,10 @@ def __new__(cls, key, secret=None, secure=True, host=None, port=None,
(api_version)) (api_version))
return super(OpenStackNodeDriver, cls).__new__(cls) 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): def destroy_node(self, node):
uri = '/servers/%s' % (node.id) uri = '/servers/%s' % (node.id)
resp = self.connection.request(uri, method='DELETE') resp = self.connection.request(uri, method='DELETE')
Expand Down Expand Up @@ -222,14 +226,7 @@ def list_locations(self):
return [NodeLocation(0, '', '', self)] return [NodeLocation(0, '', '', self)]


def _ex_connection_class_kwargs(self): def _ex_connection_class_kwargs(self):
rv = {} return self.openstack_connection_kwargs()
if self._ex_force_base_url:
rv['ex_force_base_url'] = self._ex_force_base_url
if self._ex_force_auth_url:
rv['ex_force_auth_url'] = self._ex_force_auth_url
if self._ex_force_auth_version:
rv['ex_force_auth_version'] = self._ex_force_auth_version
return rv


def ex_get_node_details(self, node_id): def ex_get_node_details(self, node_id):
# @TODO: Remove this if in 0.6 # @TODO: Remove this if in 0.6
Expand Down Expand Up @@ -284,9 +281,6 @@ class OpenStack_1_0_NodeDriver(OpenStackNodeDriver):
features = {"create_node": ["generates_password"]} features = {"create_node": ["generates_password"]}


def __init__(self, *args, **kwargs): 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', self._ex_force_api_version = str(kwargs.pop('ex_force_api_version',
None)) None))
self.XML_NAMESPACE = self.connectionCls.XML_NAMESPACE self.XML_NAMESPACE = self.connectionCls.XML_NAMESPACE
Expand Down Expand Up @@ -802,10 +796,6 @@ class OpenStack_1_1_NodeDriver(OpenStackNodeDriver):
features = {"create_node": ["generates_password"]} features = {"create_node": ["generates_password"]}


def __init__(self, *args, **kwargs): 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', self._ex_force_api_version = str(kwargs.pop('ex_force_api_version',
None)) None))
super(OpenStack_1_1_NodeDriver, self).__init__(*args, **kwargs) super(OpenStack_1_1_NodeDriver, self).__init__(*args, **kwargs)
Expand Down
4 changes: 2 additions & 2 deletions libcloud/dns/base.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ class DNSDriver(BaseDriver):
connectionCls = ConnectionUserAndKey connectionCls = ConnectionUserAndKey
name = None 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, super(DNSDriver, self).__init__(key=key, secret=secret, secure=secure,
host=host, port=port) host=host, port=port, **kwargs)


def list_record_types(self): def list_record_types(self):
""" """
Expand Down
10 changes: 9 additions & 1 deletion libcloud/dns/drivers/rackspace.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from libcloud.common.openstack import OpenStackDriverMixin


__all__ = [ __all__ = [
'RackspaceUSDNSDriver', 'RackspaceUSDNSDriver',
Expand Down Expand Up @@ -118,7 +119,14 @@ class RackspaceUKDNSConnection(RackspaceDNSConnection):
auth_url = AUTH_URL_UK 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 = { RECORD_TYPE_MAP = {
RecordType.A: 'A', RecordType.A: 'A',
Expand Down
4 changes: 2 additions & 2 deletions libcloud/loadbalancer/base.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ class Driver(BaseDriver):
_ALGORITHM_TO_VALUE_MAP = {} _ALGORITHM_TO_VALUE_MAP = {}
_VALUE_TO_ALGORITHM_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, super(Driver, self).__init__(key=key, secret=secret, secure=secure,
host=host, port=port) host=host, port=port, **kwargs)


def list_protocols(self): def list_protocols(self):
""" """
Expand Down
11 changes: 9 additions & 2 deletions libcloud/loadbalancer/drivers/rackspace.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from libcloud.common.types import LibcloudError from libcloud.common.types import LibcloudError
from libcloud.common.base import JsonResponse, PollingConnection from libcloud.common.base import JsonResponse, PollingConnection
from libcloud.loadbalancer.types import State, MemberCondition 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 ( from libcloud.common.rackspace import (
AUTH_URL_US, AUTH_URL_UK) AUTH_URL_US, AUTH_URL_UK)


Expand Down Expand Up @@ -286,7 +286,7 @@ class RackspaceUKConnection(RackspaceConnection):
auth_url = AUTH_URL_UK auth_url = AUTH_URL_UK




class RackspaceLBDriver(Driver): class RackspaceLBDriver(Driver, OpenStackDriverMixin):
connectionCls = RackspaceConnection connectionCls = RackspaceConnection
api_name = 'rackspace_lb' api_name = 'rackspace_lb'
name = 'Rackspace LB' name = 'Rackspace LB'
Expand Down Expand Up @@ -318,6 +318,13 @@ class RackspaceLBDriver(Driver):


_ALGORITHM_TO_VALUE_MAP = reverse_dict(_VALUE_TO_ALGORITHM_MAP) _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): def list_protocols(self):
return self._to_protocols( return self._to_protocols(
self.connection.request('/loadbalancers/protocols').object) self.connection.request('/loadbalancers/protocols').object)
Expand Down
4 changes: 2 additions & 2 deletions libcloud/storage/base.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ class StorageDriver(BaseDriver):
hash_type = 'md5' hash_type = 'md5'
supports_chunked_encoding = False 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, super(StorageDriver, self).__init__(key=key, secret=secret, secure=secure,
host=host, port=port) host=host, port=port, **kwargs)


def list_containters(self): def list_containters(self):
""" """
Expand Down
22 changes: 17 additions & 5 deletions libcloud/storage/drivers/cloudfiles.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
from libcloud.storage.types import ObjectHashMismatchError from libcloud.storage.types import ObjectHashMismatchError
from libcloud.storage.types import InvalidContainerNameError from libcloud.storage.types import InvalidContainerNameError
from libcloud.common.types import LazyList from libcloud.common.types import LazyList
from libcloud.common.openstack import OpenStackBaseConnection from libcloud.common.openstack import OpenStackBaseConnection, OpenStackDriverMixin


from libcloud.common.rackspace import ( from libcloud.common.rackspace import (
AUTH_URL_US, AUTH_URL_UK) AUTH_URL_US, AUTH_URL_UK)
Expand Down Expand Up @@ -139,12 +139,14 @@ def request(self, action, params=None, data='', headers=None, method='GET',
params = {} params = {}


# FIXME: Massive hack. # 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 # passed to request(). As such, we have to manually check and reset connection
# params each request # params each request
self._populate_hosts_and_request_paths() self._populate_hosts_and_request_paths()
ep = self.get_endpoint(cdn_request) if not self._ex_force_base_url:
(self.host, self.port, self.secure, self.request_path) = self._ex_force_base_url or self._tuple_from_url(ep) self._reset_connection_params(self.get_endpoint(cdn_request))
else:
self._reset_connection_params(self._ex_force_base_url)


params['format'] = 'json' params['format'] = 'json'


Expand All @@ -157,6 +159,9 @@ def request(self, action, params=None, data='', headers=None, method='GET',
method=method, headers=headers, method=method, headers=headers,
raw=raw) 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): class CloudFilesUSConnection(CloudFilesConnection):
""" """
Expand All @@ -174,7 +179,7 @@ class CloudFilesUKConnection(CloudFilesConnection):
auth_url = AUTH_URL_UK auth_url = AUTH_URL_UK




class CloudFilesStorageDriver(StorageDriver): class CloudFilesStorageDriver(StorageDriver, OpenStackDriverMixin):
""" """
Base CloudFiles driver. Base CloudFiles driver.
Expand All @@ -187,6 +192,10 @@ class CloudFilesStorageDriver(StorageDriver):
hash_type = 'md5' hash_type = 'md5'
supports_chunked_encoding = True supports_chunked_encoding = True


def __init__(self, *args, **kwargs):
OpenStackDriverMixin.__init__(self, *args, **kwargs)
super(CloudFilesStorageDriver, self).__init__(*args, **kwargs)

def list_containers(self): def list_containers(self):
response = self.connection.request('') response = self.connection.request('')


Expand Down Expand Up @@ -539,6 +548,9 @@ def _headers_to_object(self, name, container, headers):
meta_data=meta_data, container=container, driver=self) meta_data=meta_data, container=container, driver=self)
return obj return obj


def _ex_connection_class_kwargs(self):
return self.openstack_connection_kwargs()

class CloudFilesUSStorageDriver(CloudFilesStorageDriver): class CloudFilesUSStorageDriver(CloudFilesStorageDriver):
""" """
Cloudfiles storage driver for the US endpoint. Cloudfiles storage driver for the US endpoint.
Expand Down
33 changes: 32 additions & 1 deletion test/compute/test_openstack.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
from libcloud.utils.py3 import method_type from libcloud.utils.py3 import method_type
from libcloud.utils.py3 import u 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.types import Provider
from libcloud.compute.providers import get_driver from libcloud.compute.providers import get_driver
from libcloud.compute.drivers.openstack import ( from libcloud.compute.drivers.openstack import (
Expand Down Expand Up @@ -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.port, '1222')
self.assertEqual(self.driver.connection.request_path, '/some-service') 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): def test_list_nodes(self):
nodes = self.driver.list_nodes() nodes = self.driver.list_nodes()
self.assertEqual(len(nodes), 2) self.assertEqual(len(nodes), 2)
Expand Down
25 changes: 25 additions & 0 deletions test/dns/test_rackspace.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -40,6 +40,31 @@ def setUp(self):
# normally authentication happens lazily, but we force it here # normally authentication happens lazily, but we force it here
self.driver.connection._populate_hosts_and_request_paths() 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): def test_list_record_types(self):
record_types = self.driver.list_record_types() record_types = self.driver.list_record_types()
self.assertEqual(len(record_types), 7) self.assertEqual(len(record_types), 7)
Expand Down
26 changes: 26 additions & 0 deletions test/loadbalancer/test_rackspace.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -47,6 +47,32 @@ def setUp(self):
# normally authentication happens lazily, but we force it here # normally authentication happens lazily, but we force it here
self.driver.connection._populate_hosts_and_request_paths() 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): def test_list_protocols(self):
protocols = self.driver.list_protocols() protocols = self.driver.list_protocols()


Expand Down
Loading

0 comments on commit cf90e1e

Please sign in to comment.