http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/httplib_ssl.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/httplib_ssl.py b/apache-libcloud-1.0.0rc2/libcloud/httplib_ssl.py deleted file mode 100644 index b3e3101..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/httplib_ssl.py +++ /dev/null @@ -1,344 +0,0 @@ -# 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. -""" -Subclass for httplib.HTTPSConnection with optional certificate name -verification, depending on libcloud.security settings. -""" -import os -import sys -import socket -import ssl -import base64 -import warnings - -import libcloud.security -from libcloud.utils.py3 import b -from libcloud.utils.py3 import httplib -from libcloud.utils.py3 import urlparse -from libcloud.utils.py3 import urlunquote -from libcloud.utils.py3 import match_hostname -from libcloud.utils.py3 import CertificateError - - -__all__ = [ - 'LibcloudBaseConnection', - 'LibcloudHTTPConnection', - 'LibcloudHTTPSConnection' -] - -HTTP_PROXY_ENV_VARIABLE_NAME = 'http_proxy' - -# Error message which is thrown when establishing SSL / TLS connection fails -UNSUPPORTED_TLS_VERSION_ERROR_MSG = """ -Failed to establish SSL / TLS connection (%s). It is possible that the server \ -doesn't support requested SSL / TLS version (%s). -For information on how to work around this issue, please see \ -https://libcloud.readthedocs.org/en/latest/other/\ -ssl-certificate-validation.html#changing-used-ssl-tls-version -""".strip() - -# Maps ssl.PROTOCOL_* constant to the actual SSL / TLS version name -SSL_CONSTANT_TO_TLS_VERSION_MAP = { - 0: 'SSL v2', - 2: 'SSLv3, TLS v1.0, TLS v1.1, TLS v1.2', - 3: 'TLS v1.0', - 4: 'TLS v1.1', - 5: 'TLS v1.2' -} - - -class LibcloudBaseConnection(object): - """ - Base connection class to inherit from. - - Note: This class should not be instantiated directly. - """ - - proxy_scheme = None - proxy_host = None - proxy_port = None - - proxy_username = None - proxy_password = None - - http_proxy_used = False - - def set_http_proxy(self, proxy_url): - """ - Set a HTTP proxy which will be used with this connection. - - :param proxy_url: Proxy URL (e.g. http://<hostname>:<port> without - authentication and - http://<username>:<password>@<hostname>:<port> for - basic auth authentication information. - :type proxy_url: ``str`` - """ - result = self._parse_proxy_url(proxy_url=proxy_url) - scheme = result[0] - host = result[1] - port = result[2] - username = result[3] - password = result[4] - - self.proxy_scheme = scheme - self.proxy_host = host - self.proxy_port = port - self.proxy_username = username - self.proxy_password = password - self.http_proxy_used = True - - self._setup_http_proxy() - - def _parse_proxy_url(self, proxy_url): - """ - Parse and validate a proxy URL. - - :param proxy_url: Proxy URL (e.g. http://hostname:3128) - :type proxy_url: ``str`` - - :rtype: ``tuple`` (``scheme``, ``hostname``, ``port``) - """ - parsed = urlparse.urlparse(proxy_url) - - if parsed.scheme != 'http': - raise ValueError('Only http proxies are supported') - - if not parsed.hostname or not parsed.port: - raise ValueError('proxy_url must be in the following format: ' - 'http://<proxy host>:<proxy port>') - - proxy_scheme = parsed.scheme - proxy_host, proxy_port = parsed.hostname, parsed.port - - netloc = parsed.netloc - - if '@' in netloc: - username_password = netloc.split('@', 1)[0] - split = username_password.split(':', 1) - - if len(split) < 2: - raise ValueError('URL is in an invalid format') - - proxy_username, proxy_password = split[0], split[1] - else: - proxy_username = None - proxy_password = None - - return (proxy_scheme, proxy_host, proxy_port, proxy_username, - proxy_password) - - def _setup_http_proxy(self): - """ - Set up HTTP proxy. - - :param proxy_url: Proxy URL (e.g. http://<host>:3128) - :type proxy_url: ``str`` - """ - headers = {} - - if self.proxy_username and self.proxy_password: - # Include authentication header - user_pass = '%s:%s' % (self.proxy_username, self.proxy_password) - encoded = base64.encodestring(b(urlunquote(user_pass))).strip() - auth_header = 'Basic %s' % (encoded.decode('utf-8')) - headers['Proxy-Authorization'] = auth_header - - if hasattr(self, 'set_tunnel'): - # Python 2.7 and higher - # pylint: disable=no-member - self.set_tunnel(host=self.host, port=self.port, headers=headers) - elif hasattr(self, '_set_tunnel'): - # Python 2.6 - # pylint: disable=no-member - self._set_tunnel(host=self.host, port=self.port, headers=headers) - else: - raise ValueError('Unsupported Python version') - - self._set_hostport(host=self.proxy_host, port=self.proxy_port) - - def _activate_http_proxy(self, sock): - self.sock = sock - self._tunnel() # pylint: disable=no-member - - def _set_hostport(self, host, port): - """ - Backported from Python stdlib so Proxy support also works with - Python 3.4. - """ - if port is None: - i = host.rfind(':') - j = host.rfind(']') # ipv6 addresses have [...] - if i > j: - try: - port = int(host[i + 1:]) - except ValueError: - msg = "nonnumeric port: '%s'" % (host[i + 1:]) - raise httplib.InvalidURL(msg) - host = host[:i] - else: - port = self.default_port # pylint: disable=no-member - if host and host[0] == '[' and host[-1] == ']': - host = host[1:-1] - self.host = host - self.port = port - - -class LibcloudHTTPConnection(httplib.HTTPConnection, LibcloudBaseConnection): - def __init__(self, *args, **kwargs): - # Support for HTTP proxy - proxy_url_env = os.environ.get(HTTP_PROXY_ENV_VARIABLE_NAME, None) - proxy_url = kwargs.pop('proxy_url', proxy_url_env) - - super(LibcloudHTTPConnection, self).__init__(*args, **kwargs) - - if proxy_url: - self.set_http_proxy(proxy_url=proxy_url) - - -class LibcloudHTTPSConnection(httplib.HTTPSConnection, LibcloudBaseConnection): - """ - LibcloudHTTPSConnection - - Subclass of HTTPSConnection which verifies certificate names - if and only if CA certificates are available. - """ - verify = True # verify by default - ca_cert = None # no default CA Certificate - - def __init__(self, *args, **kwargs): - """ - Constructor - """ - self._setup_verify() - # Support for HTTP proxy - proxy_url_env = os.environ.get(HTTP_PROXY_ENV_VARIABLE_NAME, None) - proxy_url = kwargs.pop('proxy_url', proxy_url_env) - - super(LibcloudHTTPSConnection, self).__init__(*args, **kwargs) - - if proxy_url: - self.set_http_proxy(proxy_url=proxy_url) - - def _setup_verify(self): - """ - Setup Verify SSL or not - - Reads security module's VERIFY_SSL_CERT and toggles whether - the class overrides the connect() class method or runs the - inherited httplib.HTTPSConnection connect() - """ - self.verify = libcloud.security.VERIFY_SSL_CERT - - if self.verify: - self._setup_ca_cert() - else: - warnings.warn(libcloud.security.VERIFY_SSL_DISABLED_MSG) - - def _setup_ca_cert(self): - """ - Setup CA Certs - - Search in CA_CERTS_PATH for valid candidates and - return first match. Otherwise, complain about certs - not being available. - """ - if not self.verify: - return - - ca_certs_available = [cert - for cert in libcloud.security.CA_CERTS_PATH - if os.path.exists(cert) and os.path.isfile(cert)] - if ca_certs_available: - # use first available certificate - self.ca_cert = ca_certs_available[0] - else: - raise RuntimeError( - libcloud.security.CA_CERTS_UNAVAILABLE_ERROR_MSG) - - def connect(self): - """ - Connect - - Checks if verification is toggled; if not, just call - httplib.HTTPSConnection's connect - """ - if not self.verify: - return httplib.HTTPSConnection.connect(self) - - # otherwise, create a connection and verify the hostname - # use socket.create_connection (in 2.6+) if possible - if getattr(socket, 'create_connection', None): - sock = socket.create_connection((self.host, self.port), - self.timeout) - else: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect((self.host, self.port)) - - # Activate the HTTP proxy - if self.http_proxy_used: - self._activate_http_proxy(sock=sock) - - ssl_version = libcloud.security.SSL_VERSION - - try: - self.sock = ssl.wrap_socket( - sock, - self.key_file, - self.cert_file, - cert_reqs=ssl.CERT_REQUIRED, - ca_certs=self.ca_cert, - ssl_version=ssl_version) - except socket.error: - exc = sys.exc_info()[1] - # Re-throw an exception with a more friendly error message - exc = get_socket_error_exception(ssl_version=ssl_version, exc=exc) - raise exc - - cert = self.sock.getpeercert() - try: - match_hostname(cert, self.host) - except CertificateError: - e = sys.exc_info()[1] - raise ssl.SSLError('Failed to verify hostname: %s' % (str(e))) - - -def get_socket_error_exception(ssl_version, exc): - """ - Function which intercepts socket.error exceptions and re-throws an - exception with a more user-friendly message in case server doesn't support - requested SSL version. - """ - exc_msg = str(exc) - - # Re-throw an exception with a more friendly error message - if 'connection reset by peer' in exc_msg.lower(): - ssl_version_name = SSL_CONSTANT_TO_TLS_VERSION_MAP[ssl_version] - msg = (UNSUPPORTED_TLS_VERSION_ERROR_MSG % - (exc_msg, ssl_version_name)) - - # Note: In some cases arguments are (errno, message) and in - # other it's just (message,) - exc_args = getattr(exc, 'args', []) - - if len(exc_args) == 2: - new_exc_args = [exc.args[0], msg] - else: - new_exc_args = [msg] - - new_exc = socket.error(*new_exc_args) - new_exc.original_exc = exc - return new_exc - else: - return exc
http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/__init__.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/__init__.py b/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/__init__.py deleted file mode 100644 index 7089177..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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. - -""" -Module for working with Load Balancers -""" - -__all__ = [ - 'base', - 'providers', - 'types', - 'drivers' -] http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/base.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/base.py b/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/base.py deleted file mode 100644 index 171b6bf..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/base.py +++ /dev/null @@ -1,349 +0,0 @@ -# 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. - -from libcloud.common.base import ConnectionKey, BaseDriver -from libcloud.common.types import LibcloudError - -__all__ = [ - 'Member', - 'LoadBalancer', - 'Algorithm', - 'Driver', - 'DEFAULT_ALGORITHM' -] - - -class Member(object): - """ - Represents a load balancer member. - """ - - def __init__(self, id, ip, port, balancer=None, extra=None): - """ - :param id: Member ID. - :type id: ``str`` - - :param ip: IP address of this member. - :param ip: ``str`` - - :param port: Port of this member - :param port: ``str`` - - :param balancer: Balancer this member is attached to. (optional) - :param balancer: :class:`.LoadBalancer` - - :param extra: Provider specific attributes. - :type extra: ``dict`` - """ - self.id = str(id) if id else None - self.ip = ip - self.port = port - self.balancer = balancer - self.extra = extra or {} - - def __repr__(self): - return ('<Member: id=%s, address=%s:%s>' % (self.id, - self.ip, self.port)) - - -class LoadBalancer(object): - """ - Provide a common interface for handling Load Balancers. - """ - - def __init__(self, id, name, state, ip, port, driver, extra=None): - """ - :param id: Load balancer ID. - :type id: ``str`` - - :param name: Load balancer name. - :type name: ``str`` - - :param state: State this loadbalancer is in. - :type state: :class:`libcloud.loadbalancer.types.State` - - :param ip: IP address of this loadbalancer. - :type ip: ``str`` - - :param port: Port of this loadbalancer. - :type port: ``int`` - - :param driver: Driver this loadbalancer belongs to. - :type driver: :class:`.Driver` - - :param extra: Provider specific attributes. (optional) - :type extra: ``dict`` - """ - self.id = str(id) if id else None - self.name = name - self.state = state - self.ip = ip - self.port = port - self.driver = driver - self.extra = extra or {} - - def attach_compute_node(self, node): - return self.driver.balancer_attach_compute_node(balancer=self, - node=node) - - def attach_member(self, member): - return self.driver.balancer_attach_member(balancer=self, - member=member) - - def detach_member(self, member): - return self.driver.balancer_detach_member(balancer=self, - member=member) - - def list_members(self): - return self.driver.balancer_list_members(balancer=self) - - def destroy(self): - return self.driver.destroy_balancer(balancer=self) - - def __repr__(self): - return ('<LoadBalancer: id=%s, name=%s, state=%s, ip=%s, ' - 'port=%s>' % (self.id, self.name, self.state, self.ip, - self.port)) - - -class Algorithm(object): - """ - Represents a load balancing algorithm. - """ - - RANDOM = 0 - ROUND_ROBIN = 1 - LEAST_CONNECTIONS = 2 - WEIGHTED_ROUND_ROBIN = 3 - WEIGHTED_LEAST_CONNECTIONS = 4 - SHORTEST_RESPONSE = 5 - PERSISTENT_IP = 6 - -DEFAULT_ALGORITHM = Algorithm.ROUND_ROBIN - - -class Driver(BaseDriver): - """ - A base Driver class to derive from - - This class is always subclassed by a specific driver. - """ - - name = None - website = None - - connectionCls = ConnectionKey - _ALGORITHM_TO_VALUE_MAP = {} - _VALUE_TO_ALGORITHM_MAP = {} - - 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, **kwargs) - - def list_protocols(self): - """ - Return a list of supported protocols. - - :rtype: ``list`` of ``str`` - """ - raise NotImplementedError( - 'list_protocols not implemented for this driver') - - def list_balancers(self): - """ - List all loadbalancers - - :rtype: ``list`` of :class:`LoadBalancer` - """ - raise NotImplementedError( - 'list_balancers not implemented for this driver') - - def create_balancer(self, name, port, protocol, algorithm, members): - """ - Create a new load balancer instance - - :param name: Name of the new load balancer (required) - :type name: ``str`` - - :param port: Port the load balancer should listen on, defaults to 80 - :type port: ``str`` - - :param protocol: Loadbalancer protocol, defaults to http. - :type protocol: ``str`` - - :param members: list of Members to attach to balancer - :type members: ``list`` of :class:`Member` - - :param algorithm: Load balancing algorithm, defaults to ROUND_ROBIN. - :type algorithm: :class:`.Algorithm` - - :rtype: :class:`LoadBalancer` - """ - raise NotImplementedError( - 'create_balancer not implemented for this driver') - - def destroy_balancer(self, balancer): - """ - Destroy a load balancer - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :return: ``True`` if the destroy was successful, otherwise ``False``. - :rtype: ``bool`` - """ - - raise NotImplementedError( - 'destroy_balancer not implemented for this driver') - - def get_balancer(self, balancer_id): - """ - Return a :class:`LoadBalancer` object. - - :param balancer_id: id of a load balancer you want to fetch - :type balancer_id: ``str`` - - :rtype: :class:`LoadBalancer` - """ - - raise NotImplementedError( - 'get_balancer not implemented for this driver') - - def update_balancer(self, balancer, **kwargs): - """ - Sets the name, algorithm, protocol, or port on a load balancer. - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :param name: New load balancer name - :type name: ``str`` - - :param algorithm: New load balancer algorithm - :type algorithm: :class:`.Algorithm` - - :param protocol: New load balancer protocol - :type protocol: ``str`` - - :param port: New load balancer port - :type port: ``int`` - - :rtype: :class:`LoadBalancer` - """ - raise NotImplementedError( - 'update_balancer not implemented for this driver') - - def balancer_attach_compute_node(self, balancer, node): - """ - Attach a compute node as a member to the load balancer. - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :param node: Node to join to the balancer - :type node: :class:`Node` - - :return: Member after joining the balancer. - :rtype: :class:`Member` - """ - - member = Member(id=None, ip=node.public_ips[0], port=balancer.port) - return self.balancer_attach_member(balancer, member) - - def balancer_attach_member(self, balancer, member): - """ - Attach a member to balancer - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :param member: Member to join to the balancer - :type member: :class:`Member` - - :return: Member after joining the balancer. - :rtype: :class:`Member` - """ - - raise NotImplementedError( - 'balancer_attach_member not implemented for this driver') - - def balancer_detach_member(self, balancer, member): - """ - Detach member from balancer - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :param member: Member which should be used - :type member: :class:`Member` - - :return: ``True`` if member detach was successful, otherwise ``False``. - :rtype: ``bool`` - """ - - raise NotImplementedError( - 'balancer_detach_member not implemented for this driver') - - def balancer_list_members(self, balancer): - """ - Return list of members attached to balancer - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :rtype: ``list`` of :class:`Member` - """ - - raise NotImplementedError( - 'balancer_list_members not implemented for this driver') - - def list_supported_algorithms(self): - """ - Return algorithms supported by this driver. - - :rtype: ``list`` of ``str`` - """ - return list(self._ALGORITHM_TO_VALUE_MAP.keys()) - - def _value_to_algorithm(self, value): - """ - Return :class:`.Algorithm` based on the value. - - :param value: Algorithm name (e.g. http, tcp, ...). - :type value: ``str`` - - :rtype: :class:`.Algorithm` - """ - try: - return self._VALUE_TO_ALGORITHM_MAP[value] - except KeyError: - raise LibcloudError(value='Invalid value: %s' % (value), - driver=self) - - def _algorithm_to_value(self, algorithm): - """ - Return string value for the provided algorithm. - - :param value: Algorithm enum. - :type value: :class:`Algorithm` - - :rtype: ``str`` - """ - try: - return self._ALGORITHM_TO_VALUE_MAP[algorithm] - except KeyError: - raise LibcloudError(value='Invalid algorithm: %s' % (algorithm), - driver=self) http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/__init__.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/__init__.py b/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/__init__.py deleted file mode 100644 index f4fdb86..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# 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. - -__all__ = [ - 'rackspace', - 'gogrid' -] http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/brightbox.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/brightbox.py b/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/brightbox.py deleted file mode 100644 index 9788a1e..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/brightbox.py +++ /dev/null @@ -1,138 +0,0 @@ -# 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. - - -from libcloud.utils.py3 import httplib -from libcloud.common.brightbox import BrightboxConnection -from libcloud.loadbalancer.base import Driver, Algorithm, Member -from libcloud.loadbalancer.base import LoadBalancer -from libcloud.loadbalancer.types import State -from libcloud.utils.misc import reverse_dict - -API_VERSION = '1.0' - - -class BrightboxLBDriver(Driver): - connectionCls = BrightboxConnection - - name = 'Brightbox' - website = 'http://www.brightbox.co.uk/' - - LB_STATE_MAP = { - 'creating': State.PENDING, - 'active': State.RUNNING, - 'deleting': State.UNKNOWN, - 'deleted': State.UNKNOWN, - 'failing': State.UNKNOWN, - 'failed': State.UNKNOWN, - } - - _VALUE_TO_ALGORITHM_MAP = { - 'round-robin': Algorithm.ROUND_ROBIN, - 'least-connections': Algorithm.LEAST_CONNECTIONS - } - - _ALGORITHM_TO_VALUE_MAP = reverse_dict(_VALUE_TO_ALGORITHM_MAP) - - def list_protocols(self): - return ['tcp', 'http'] - - def list_balancers(self): - data = self.connection.request('/%s/load_balancers' % API_VERSION) \ - .object - - return list(map(self._to_balancer, data)) - - def create_balancer(self, name, port, protocol, algorithm, members): - response = self._post( - '/%s/load_balancers' % API_VERSION, - {'name': name, - 'nodes': list(map(self._member_to_node, members)), - 'policy': self._algorithm_to_value(algorithm), - 'listeners': [{'in': port, 'out': port, 'protocol': protocol}], - 'healthcheck': {'type': protocol, 'port': port}} - ) - - return self._to_balancer(response.object) - - def destroy_balancer(self, balancer): - response = self.connection.request('/%s/load_balancers/%s' % - (API_VERSION, balancer.id), - method='DELETE') - - return response.status == httplib.ACCEPTED - - def get_balancer(self, balancer_id): - data = self.connection.request( - '/%s/load_balancers/%s' % (API_VERSION, balancer_id)).object - return self._to_balancer(data) - - def balancer_attach_compute_node(self, balancer, node): - return self.balancer_attach_member(balancer, node) - - def balancer_attach_member(self, balancer, member): - path = '/%s/load_balancers/%s/add_nodes' % (API_VERSION, balancer.id) - - self._post(path, {'nodes': [self._member_to_node(member)]}) - - return member - - def balancer_detach_member(self, balancer, member): - path = '/%s/load_balancers/%s/remove_nodes' % (API_VERSION, - balancer.id) - - response = self._post(path, {'nodes': [self._member_to_node(member)]}) - - return response.status == httplib.ACCEPTED - - def balancer_list_members(self, balancer): - path = '/%s/load_balancers/%s' % (API_VERSION, balancer.id) - - data = self.connection.request(path).object - - def func(data): - return self._node_to_member(data, balancer) - - return list(map(func, data['nodes'])) - - def _post(self, path, data={}): - headers = {'Content-Type': 'application/json'} - - return self.connection.request(path, data=data, headers=headers, - method='POST') - - def _to_balancer(self, data): - return LoadBalancer( - id=data['id'], - name=data['name'], - state=self.LB_STATE_MAP.get(data['status'], State.UNKNOWN), - ip=self._public_ip(data), - port=data['listeners'][0]['in'], - driver=self.connection.driver - ) - - def _member_to_node(self, member): - return {'node': member.id} - - def _node_to_member(self, data, balancer): - return Member(id=data['id'], ip=None, port=None, balancer=balancer) - - def _public_ip(self, data): - if len(data['cloud_ips']) > 0: - ip = data['cloud_ips'][0]['public_ip'] - else: - ip = None - - return ip http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/cloudstack.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/cloudstack.py b/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/cloudstack.py deleted file mode 100644 index a8d5485..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/cloudstack.py +++ /dev/null @@ -1,209 +0,0 @@ -# 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. - -from libcloud.common.cloudstack import CloudStackDriverMixIn -from libcloud.loadbalancer.base import LoadBalancer, Member, Driver, Algorithm -from libcloud.loadbalancer.base import DEFAULT_ALGORITHM -from libcloud.loadbalancer.types import Provider -from libcloud.loadbalancer.types import State -from libcloud.utils.misc import reverse_dict - - -class CloudStackLBDriver(CloudStackDriverMixIn, Driver): - """Driver for CloudStack load balancers.""" - - api_name = 'cloudstack_lb' - name = 'CloudStack' - website = 'http://cloudstack.org/' - type = Provider.CLOUDSTACK - - _VALUE_TO_ALGORITHM_MAP = { - 'roundrobin': Algorithm.ROUND_ROBIN, - 'leastconn': Algorithm.LEAST_CONNECTIONS - } - _ALGORITHM_TO_VALUE_MAP = reverse_dict(_VALUE_TO_ALGORITHM_MAP) - - LB_STATE_MAP = { - 'Active': State.RUNNING, - } - - def __init__(self, key, secret=None, secure=True, host=None, - path=None, port=None, *args, **kwargs): - """ - @inherits: :class:`Driver.__init__` - """ - host = host if host else self.host - path = path if path else self.path - - if path is not None: - self.path = path - - if host is not None: - self.host = host - - if (self.type == Provider.CLOUDSTACK) and (not host or not path): - raise Exception('When instantiating CloudStack driver directly ' + - 'you also need to provide host and path argument') - - super(CloudStackLBDriver, self).__init__(key=key, secret=secret, - secure=secure, - host=host, port=port) - - def list_protocols(self): - """ - We don't actually have any protocol awareness beyond TCP. - - :rtype: ``list`` of ``str`` - """ - return ['tcp'] - - def list_balancers(self): - balancers = self._sync_request(command='listLoadBalancerRules', - method='GET') - balancers = balancers.get('loadbalancerrule', []) - return [self._to_balancer(balancer) for balancer in balancers] - - def get_balancer(self, balancer_id): - balancer = self._sync_request(command='listLoadBalancerRules', - params={'id': balancer_id}, - method='GET') - balancer = balancer.get('loadbalancerrule', []) - if not balancer: - raise Exception("no such load balancer: " + str(balancer_id)) - return self._to_balancer(balancer[0]) - - def create_balancer(self, name, members, protocol='http', port=80, - algorithm=DEFAULT_ALGORITHM, location=None, - private_port=None, network_id=None, vpc_id=None): - """ - @inherits: :class:`Driver.create_balancer` - - :param location: Location - :type location: :class:`NodeLocation` - - :param private_port: Private port - :type private_port: ``int`` - - :param network_id: The guest network this rule will be created for. - :type network_id: ``str`` - """ - - args = {} - ip_args = {} - - if location is None: - locations = self._sync_request(command='listZones', method='GET') - location = locations['zone'][0]['id'] - else: - location = location.id - if private_port is None: - private_port = port - - if network_id is not None: - args['networkid'] = network_id - ip_args['networkid'] = network_id - - if vpc_id is not None: - ip_args['vpcid'] = vpc_id - - ip_args.update({'zoneid': location, - 'networkid': network_id, - 'vpc_id': vpc_id}) - - result = self._async_request(command='associateIpAddress', - params=ip_args, - method='GET') - public_ip = result['ipaddress'] - - args.update({'algorithm': self._ALGORITHM_TO_VALUE_MAP[algorithm], - 'name': name, - 'privateport': private_port, - 'publicport': port, - 'publicipid': public_ip['id']}) - - result = self._sync_request( - command='createLoadBalancerRule', - params=args, - method='GET') - - listbalancers = self._sync_request( - command='listLoadBalancerRules', - params=args, - method='GET') - - listbalancers = [rule for rule in listbalancers['loadbalancerrule'] if - rule['id'] == result['id']] - if len(listbalancers) != 1: - return None - - balancer = self._to_balancer(listbalancers[0]) - - for member in members: - balancer.attach_member(member) - - return balancer - - def destroy_balancer(self, balancer): - self._async_request(command='deleteLoadBalancerRule', - params={'id': balancer.id}, - - method='GET') - self._async_request(command='disassociateIpAddress', - params={'id': balancer.ex_public_ip_id}, - method='GET') - - def balancer_attach_member(self, balancer, member): - member.port = balancer.ex_private_port - self._async_request(command='assignToLoadBalancerRule', - params={'id': balancer.id, - 'virtualmachineids': member.id}, - method='GET') - return True - - def balancer_detach_member(self, balancer, member): - self._async_request(command='removeFromLoadBalancerRule', - params={'id': balancer.id, - 'virtualmachineids': member.id}, - method='GET') - return True - - def balancer_list_members(self, balancer): - members = self._sync_request(command='listLoadBalancerRuleInstances', - params={'id': balancer.id}, - method='GET') - members = members['loadbalancerruleinstance'] - return [self._to_member(m, balancer.ex_private_port, balancer) - for m in members] - - def _to_balancer(self, obj): - balancer = LoadBalancer( - id=obj['id'], - name=obj['name'], - state=self.LB_STATE_MAP.get(obj['state'], State.UNKNOWN), - ip=obj['publicip'], - port=obj['publicport'], - driver=self.connection.driver - ) - balancer.ex_private_port = obj['privateport'] - balancer.ex_public_ip_id = obj['publicipid'] - return balancer - - def _to_member(self, obj, port, balancer): - return Member( - id=obj['id'], - ip=obj['nic'][0]['ipaddress'], - port=port, - balancer=balancer - ) http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/dimensiondata.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/dimensiondata.py b/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/dimensiondata.py deleted file mode 100644 index 9fd0143..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/loadbalancer/drivers/dimensiondata.py +++ /dev/null @@ -1,1126 +0,0 @@ -# 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 withv -# 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. - -try: - from lxml import etree as ET -except ImportError: - from xml.etree import ElementTree as ET - -from libcloud.common.dimensiondata import DimensionDataConnection -from libcloud.common.dimensiondata import DimensionDataPool -from libcloud.common.dimensiondata import DimensionDataPoolMember -from libcloud.common.dimensiondata import DimensionDataVirtualListener -from libcloud.common.dimensiondata import DimensionDataVIPNode -from libcloud.common.dimensiondata import DimensionDataDefaultHealthMonitor -from libcloud.common.dimensiondata import DimensionDataPersistenceProfile -from libcloud.common.dimensiondata import \ - DimensionDataVirtualListenerCompatibility -from libcloud.common.dimensiondata import DimensionDataDefaultiRule -from libcloud.common.dimensiondata import API_ENDPOINTS -from libcloud.common.dimensiondata import DEFAULT_REGION -from libcloud.common.dimensiondata import TYPES_URN -from libcloud.utils.misc import reverse_dict -from libcloud.utils.xml import fixxpath, findtext, findall -from libcloud.loadbalancer.types import State -from libcloud.loadbalancer.base import Algorithm, Driver, LoadBalancer -from libcloud.loadbalancer.base import Member -from libcloud.loadbalancer.types import Provider - - -class DimensionDataLBDriver(Driver): - """ - DimensionData node driver. - """ - - selected_region = None - connectionCls = DimensionDataConnection - name = 'Dimension Data Load Balancer' - website = 'https://cloud.dimensiondata.com/' - type = Provider.DIMENSIONDATA - api_version = 1.0 - - network_domain_id = None - - _VALUE_TO_ALGORITHM_MAP = { - 'ROUND_ROBIN': Algorithm.ROUND_ROBIN, - 'LEAST_CONNECTIONS': Algorithm.LEAST_CONNECTIONS, - 'SHORTEST_RESPONSE': Algorithm.SHORTEST_RESPONSE, - 'PERSISTENT_IP': Algorithm.PERSISTENT_IP - } - _ALGORITHM_TO_VALUE_MAP = reverse_dict(_VALUE_TO_ALGORITHM_MAP) - - _VALUE_TO_STATE_MAP = { - 'NORMAL': State.RUNNING, - 'PENDING_ADD': State.PENDING, - 'PENDING_CHANGE': State.PENDING, - 'PENDING_DELETE': State.PENDING, - 'FAILED_ADD': State.ERROR, - 'FAILED_CHANGE': State.ERROR, - 'FAILED_DELETE': State.ERROR, - 'REQUIRES_SUPPORT': State.ERROR - } - - def __init__(self, key, secret=None, secure=True, host=None, port=None, - api_version=None, region=DEFAULT_REGION, **kwargs): - - if region not in API_ENDPOINTS: - raise ValueError('Invalid region: %s' % (region)) - - self.selected_region = API_ENDPOINTS[region] - - super(DimensionDataLBDriver, self).__init__(key=key, secret=secret, - secure=secure, host=host, - port=port, - api_version=api_version, - region=region, - **kwargs) - - def _ex_connection_class_kwargs(self): - """ - Add the region to the kwargs before the connection is instantiated - """ - - kwargs = super(DimensionDataLBDriver, - self)._ex_connection_class_kwargs() - kwargs['region'] = self.selected_region - return kwargs - - def create_balancer(self, name, port, protocol, algorithm, members): - """ - Create a new load balancer instance - - :param name: Name of the new load balancer (required) - :type name: ``str`` - - :param port: Port the load balancer should listen on, - defaults to 80 (required) - :type port: ``str`` - - :param protocol: Loadbalancer protocol, defaults to http. - :type protocol: ``str`` - - :param members: list of Members to attach to balancer (optional) - :type members: ``list`` of :class:`Member` - - :param algorithm: Load balancing algorithm, defaults to ROUND_ROBIN. - :type algorithm: :class:`.Algorithm` - - :rtype: :class:`LoadBalancer` - """ - network_domain_id = self.network_domain_id - if port is None: - port = 80 - if protocol is None: - protocol = 'http' - if algorithm is None: - algorithm = Algorithm.ROUND_ROBIN - - # Create a pool first - pool = self.ex_create_pool( - network_domain_id=network_domain_id, - name=name, - ex_description=None, - balancer_method=self._ALGORITHM_TO_VALUE_MAP[algorithm]) - - # Attach the members to the pool as nodes - if members is not None: - for member in members: - node = self.ex_create_node( - network_domain_id=network_domain_id, - name=member.ip, - ip=member.ip, - ex_description=None) - self.ex_create_pool_member( - pool=pool, - node=node, - port=port) - - # Create the virtual listener (balancer) - listener = self.ex_create_virtual_listener( - network_domain_id=network_domain_id, - name=name, - ex_description=name, - port=port, - pool=pool) - - return LoadBalancer( - id=listener.id, - name=listener.name, - state=State.RUNNING, - ip=listener.ip, - port=port, - driver=self, - extra={'pool_id': pool.id, - 'network_domain_id': network_domain_id} - ) - - def list_balancers(self): - """ - List all loadbalancers inside a geography. - - In Dimension Data terminology these are known as virtual listeners - - :rtype: ``list`` of :class:`LoadBalancer` - """ - - return self._to_balancers( - self.connection - .request_with_orgId_api_2('networkDomainVip/virtualListener') - .object) - - def get_balancer(self, balancer_id): - """ - Return a :class:`LoadBalancer` object. - - :param balancer_id: id of a load balancer you want to fetch - :type balancer_id: ``str`` - - :rtype: :class:`LoadBalancer` - """ - - bal = self.connection \ - .request_with_orgId_api_2('networkDomainVip/virtualListener/%s' - % balancer_id).object - return self._to_balancer(bal) - - def list_protocols(self): - """ - Return a list of supported protocols. - - Since all protocols are support by Dimension Data, this is a list - of common protocols. - - :rtype: ``list`` of ``str`` - """ - return ['http', 'https', 'tcp', 'udp'] - - def balancer_list_members(self, balancer): - """ - Return list of members attached to balancer. - - In Dimension Data terminology these are the members of the pools - within a virtual listener. - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :rtype: ``list`` of :class:`Member` - """ - pool_members = self.ex_get_pool_members(balancer.extra['pool_id']) - members = [] - for pool_member in pool_members: - members.append(Member( - id=pool_member.id, - ip=pool_member.ip, - port=pool_member.port, - balancer=balancer, - extra=None - )) - return members - - def balancer_attach_member(self, balancer, member): - """ - Attach a member to balancer - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :param member: Member to join to the balancer - :type member: :class:`Member` - - :return: Member after joining the balancer. - :rtype: :class:`Member` - """ - node = self.ex_create_node( - network_domain_id=balancer.extra['network_domain_id'], - name='Member.' + member.ip, - ip=member.ip, - ex_description='' - ) - if node is False: - return False - pool = self.ex_get_pool(balancer.extra['pool_id']) - pool_member = self.ex_create_pool_member( - pool=pool, - node=node, - port=member.port) - member.id = pool_member.id - return member - - def balancer_detach_member(self, balancer, member): - """ - Detach member from balancer - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :param member: Member which should be used - :type member: :class:`Member` - - :return: ``True`` if member detach was successful, otherwise ``False``. - :rtype: ``bool`` - """ - create_pool_m = ET.Element('removePoolMember', {'xmlns': TYPES_URN, - 'id': member.id}) - - result = self.connection.request_with_orgId_api_2( - 'networkDomainVip/removePoolMember', - method='POST', - data=ET.tostring(create_pool_m)).object - response_code = findtext(result, 'responseCode', TYPES_URN) - return response_code in ['IN_PROGRESS', 'OK'] - - def destroy_balancer(self, balancer): - """ - Destroy a load balancer (virtual listener) - - :param balancer: LoadBalancer which should be used - :type balancer: :class:`LoadBalancer` - - :return: ``True`` if the destroy was successful, otherwise ``False``. - :rtype: ``bool`` - """ - delete_listener = ET.Element('deleteVirtualListener', - {'xmlns': TYPES_URN, - 'id': balancer.id}) - - result = self.connection.request_with_orgId_api_2( - 'networkDomainVip/deleteVirtualListener', - method='POST', - data=ET.tostring(delete_listener)).object - response_code = findtext(result, 'responseCode', TYPES_URN) - return response_code in ['IN_PROGRESS', 'OK'] - - def ex_set_current_network_domain(self, network_domain_id): - """ - Set the network domain (part of the network) of the driver - - :param network_domain_id: ID of the pool (required) - :type network_domain_id: ``str`` - """ - self.network_domain_id = network_domain_id - - def ex_get_current_network_domain(self): - """ - Get the current network domain ID of the driver. - - :return: ID of the network domain - :rtype: ``str`` - """ - return self.network_domain_id - - def ex_create_pool_member(self, pool, node, port=None): - """ - Create a new member in an existing pool from an existing node - - :param pool: Instance of ``DimensionDataPool`` (required) - :type pool: ``DimensionDataPool`` - - :param node: Instance of ``DimensionDataVIPNode`` (required) - :type node: ``DimensionDataVIPNode`` - - :param port: Port the the service will listen on - :type port: ``str`` - - :return: The node member, instance of ``DimensionDataPoolMember`` - :rtype: ``DimensionDataPoolMember`` - """ - create_pool_m = ET.Element('addPoolMember', {'xmlns': TYPES_URN}) - ET.SubElement(create_pool_m, "poolId").text = pool.id - ET.SubElement(create_pool_m, "nodeId").text = node.id - if port is not None: - ET.SubElement(create_pool_m, "port").text = str(port) - ET.SubElement(create_pool_m, "status").text = 'ENABLED' - - response = self.connection.request_with_orgId_api_2( - 'networkDomainVip/addPoolMember', - method='POST', - data=ET.tostring(create_pool_m)).object - - member_id = None - node_name = None - for info in findall(response, 'info', TYPES_URN): - if info.get('name') == 'poolMemberId': - member_id = info.get('value') - if info.get('name') == 'nodeName': - node_name = info.get('value') - - return DimensionDataPoolMember( - id=member_id, - name=node_name, - status=State.RUNNING, - ip=node.ip, - port=port, - node_id=node.id - ) - - def ex_create_node(self, - network_domain_id, - name, - ip, - ex_description, - connection_limit=25000, - connection_rate_limit=2000): - """ - Create a new node - - :param network_domain_id: Network Domain ID (required) - :type name: ``str`` - - :param name: name of the node (required) - :type name: ``str`` - - :param ip: IPv4 address of the node (required) - :type ip: ``str`` - - :param ex_description: Description of the node (required) - :type ex_description: ``str`` - - :param connection_limit: Maximum number - of concurrent connections per sec - :type connection_limit: ``int`` - - :param connection_rate_limit: Maximum number of concurrent sessions - :type connection_rate_limit: ``int`` - - :return: Instance of ``DimensionDataVIPNode`` - :rtype: ``DimensionDataVIPNode`` - """ - create_node_elm = ET.Element('createNode', {'xmlns': TYPES_URN}) - ET.SubElement(create_node_elm, "networkDomainId") \ - .text = network_domain_id - ET.SubElement(create_node_elm, "name").text = name - ET.SubElement(create_node_elm, "description").text \ - = str(ex_description) - ET.SubElement(create_node_elm, "ipv4Address").text = ip - ET.SubElement(create_node_elm, "status").text = 'ENABLED' - ET.SubElement(create_node_elm, "connectionLimit") \ - .text = str(connection_limit) - ET.SubElement(create_node_elm, "connectionRateLimit") \ - .text = str(connection_rate_limit) - - response = self.connection.request_with_orgId_api_2( - action='networkDomainVip/createNode', - method='POST', - data=ET.tostring(create_node_elm)).object - - node_id = None - node_name = None - for info in findall(response, 'info', TYPES_URN): - if info.get('name') == 'nodeId': - node_id = info.get('value') - if info.get('name') == 'name': - node_name = info.get('value') - return DimensionDataVIPNode( - id=node_id, - name=node_name, - status=State.RUNNING, - ip=ip - ) - - def ex_update_node(self, node): - """ - Update the properties of a node - - :param pool: The instance of ``DimensionDataNode`` to update - :type pool: ``DimensionDataNode`` - - :return: The instance of ``DimensionDataNode`` - :rtype: ``DimensionDataNode`` - """ - create_node_elm = ET.Element('editNode', {'xmlns': TYPES_URN}) - ET.SubElement(create_node_elm, "connectionLimit") \ - .text = str(node.connection_limit) - ET.SubElement(create_node_elm, "connectionRateLimit") \ - .text = str(node.connection_rate_limit) - - self.connection.request_with_orgId_api_2( - action='networkDomainVip/createNode', - method='POST', - data=ET.tostring(create_node_elm)).object - return node - - def ex_set_node_state(self, node, enabled): - """ - Change the state of a node (enable/disable) - - :param pool: The instance of ``DimensionDataNode`` to update - :type pool: ``DimensionDataNode`` - - :param enabled: The target state of the node - :type enabled: ``bool`` - - :return: The instance of ``DimensionDataNode`` - :rtype: ``DimensionDataNode`` - """ - create_node_elm = ET.Element('editNode', {'xmlns': TYPES_URN}) - ET.SubElement(create_node_elm, "status") \ - .text = "ENABLED" if enabled is True else "DISABLED" - - self.connection.request_with_orgId_api_2( - action='networkDomainVip/editNode', - method='POST', - data=ET.tostring(create_node_elm)).object - return node - - def ex_create_pool(self, - network_domain_id, - name, - balancer_method, - ex_description, - health_monitors=None, - service_down_action='NONE', - slow_ramp_time=30): - """ - Create a new pool - - :param network_domain_id: Network Domain ID (required) - :type name: ``str`` - - :param name: name of the node (required) - :type name: ``str`` - - :param balancer_method: The load balancer algorithm (required) - :type balancer_method: ``str`` - - :param ex_description: Description of the node (required) - :type ex_description: ``str`` - - :param health_monitors: A list of health monitors to use for the pool. - :type health_monitors: ``list`` of - :class:`DimensionDataDefaultHealthMonitor` - - :param service_down_action: What to do when node - is unavailable NONE, DROP or RESELECT - :type service_down_action: ``str`` - - :param slow_ramp_time: Number of seconds to stagger ramp up of nodes - :type slow_ramp_time: ``int`` - - :return: Instance of ``DimensionDataPool`` - :rtype: ``DimensionDataPool`` - """ - # Names cannot contain spaces. - name.replace(' ', '_') - create_node_elm = ET.Element('createPool', {'xmlns': TYPES_URN}) - ET.SubElement(create_node_elm, "networkDomainId") \ - .text = network_domain_id - ET.SubElement(create_node_elm, "name").text = name - ET.SubElement(create_node_elm, "description").text \ - = str(ex_description) - ET.SubElement(create_node_elm, "loadBalanceMethod") \ - .text = str(balancer_method) - - if health_monitors is not None: - for monitor in health_monitors: - ET.SubElement(create_node_elm, "healthMonitorId") \ - .text = str(monitor.id) - - ET.SubElement(create_node_elm, "serviceDownAction") \ - .text = service_down_action - ET.SubElement(create_node_elm, "slowRampTime").text \ - = str(slow_ramp_time) - - response = self.connection.request_with_orgId_api_2( - action='networkDomainVip/createPool', - method='POST', - data=ET.tostring(create_node_elm)).object - - pool_id = None - for info in findall(response, 'info', TYPES_URN): - if info.get('name') == 'poolId': - pool_id = info.get('value') - - return DimensionDataPool( - id=pool_id, - name=name, - description=ex_description, - status=State.RUNNING, - load_balance_method=str(balancer_method), - health_monitor_id=None, - service_down_action=service_down_action, - slow_ramp_time=str(slow_ramp_time) - ) - - def ex_create_virtual_listener(self, - network_domain_id, - name, - ex_description, - port, - pool, - listener_ip_address=None, - persistence_profile=None, - fallback_persistence_profile=None, - irule=None, - protocol='TCP', - connection_limit=25000, - connection_rate_limit=2000, - source_port_preservation='PRESERVE'): - """ - Create a new virtual listener (load balancer) - - :param network_domain_id: Network Domain ID (required) - :type name: ``str`` - - :param name: name of the listener (required) - :type name: ``str`` - - :param ex_description: Description of the node (required) - :type ex_description: ``str`` - - :param port: Description of the node (required) - :type port: ``str`` - - :param pool: The pool to use for the listener - :type pool: :class:`DimensionDataPool` - - :param listener_ip_address: The IPv4 Address of the virtual listener - :type listener_ip_address: ``str`` - - :param persistence_profile: Persistence profile - :type persistence_profile: :class:`DimensionDataPersistenceProfile` - - :param fallback_persistence_profile: Fallback persistence profile - :type fallback_persistence_profile: - :class:`DimensionDataPersistenceProfile` - - :param irule: The iRule to apply - :type irule: :class:`DimensionDataDefaultiRule` - - :param protocol: For STANDARD type, ANY, TCP or UDP - for PERFORMANCE_LAYER_4 choice of ANY, TCP, UDP, HTTP - :type protcol: ``str`` - - :param connection_limit: Maximum number - of concurrent connections per sec - :type connection_limit: ``int`` - - :param connection_rate_limit: Maximum number of concurrent sessions - :type connection_rate_limit: ``int`` - - :param source_port_preservation: Choice of PRESERVE, - PRESERVE_STRICT or CHANGE - :type source_port_preservation: ``str`` - - :return: Instance of the listener - :rtype: ``DimensionDataVirtualListener`` - """ - if port is 80 or 443: - listener_type = 'PERFORMANCE_LAYER_4' - protocol = 'HTTP' - else: - listener_type = 'STANDARD' - - create_node_elm = ET.Element('createVirtualListener', - {'xmlns': TYPES_URN}) - ET.SubElement(create_node_elm, "networkDomainId") \ - .text = network_domain_id - ET.SubElement(create_node_elm, "name").text = name - ET.SubElement(create_node_elm, "description").text = \ - str(ex_description) - ET.SubElement(create_node_elm, "type").text = listener_type - ET.SubElement(create_node_elm, "protocol") \ - .text = protocol - if listener_ip_address is not None: - ET.SubElement(create_node_elm, "listenerIpAddress").text = \ - str(listener_ip_address) - ET.SubElement(create_node_elm, "port").text = str(port) - ET.SubElement(create_node_elm, "enabled").text = 'true' - ET.SubElement(create_node_elm, "connectionLimit") \ - .text = str(connection_limit) - ET.SubElement(create_node_elm, "connectionRateLimit") \ - .text = str(connection_rate_limit) - ET.SubElement(create_node_elm, "sourcePortPreservation") \ - .text = source_port_preservation - ET.SubElement(create_node_elm, "poolId") \ - .text = pool.id - if persistence_profile is not None: - ET.SubElement(create_node_elm, "persistenceProfileId") \ - .text = persistence_profile.id - if fallback_persistence_profile is not None: - ET.SubElement(create_node_elm, "fallbackPersistenceProfileId") \ - .text = fallback_persistence_profile.id - if irule is not None: - ET.SubElement(create_node_elm, "iruleId") \ - .text = irule.id - - response = self.connection.request_with_orgId_api_2( - action='networkDomainVip/createVirtualListener', - method='POST', - data=ET.tostring(create_node_elm)).object - - virtual_listener_id = None - virtual_listener_ip = None - for info in findall(response, 'info', TYPES_URN): - if info.get('name') == 'virtualListenerId': - virtual_listener_id = info.get('value') - if info.get('name') == 'listenerIpAddress': - virtual_listener_ip = info.get('value') - - return DimensionDataVirtualListener( - id=virtual_listener_id, - name=name, - ip=virtual_listener_ip, - status=State.RUNNING - ) - - def ex_get_pools(self): - """ - Get all of the pools inside the current geography - - :return: Returns a ``list`` of type ``DimensionDataPool`` - :rtype: ``list`` of ``DimensionDataPool`` - """ - pools = self.connection \ - .request_with_orgId_api_2('networkDomainVip/pool').object - return self._to_pools(pools) - - def ex_get_pool(self, pool_id): - """ - Get a specific pool inside the current geography - - :param pool_id: The identifier of the pool - :type pool_id: ``str`` - - :return: Returns an instance of ``DimensionDataPool`` - :rtype: ``DimensionDataPool`` - """ - pool = self.connection \ - .request_with_orgId_api_2('networkDomainVip/pool/%s' - % pool_id).object - return self._to_pool(pool) - - def ex_update_pool(self, pool): - """ - Update the properties of an existing pool - only method, serviceDownAction and slowRampTime are updated - - :param pool: The instance of ``DimensionDataPool`` to update - :type pool: ``DimensionDataPool`` - - :return: ``True`` for success, ``False`` for failure - :rtype: ``bool`` - """ - create_node_elm = ET.Element('editPool', {'xmlns': TYPES_URN}) - - ET.SubElement(create_node_elm, "loadBalanceMethod") \ - .text = str(pool.load_balance_method) - ET.SubElement(create_node_elm, "serviceDownAction") \ - .text = pool.service_down_action - ET.SubElement(create_node_elm, "slowRampTime").text \ - = str(pool.slow_ramp_time) - - response = self.connection.request_with_orgId_api_2( - action='networkDomainVip/editPool', - method='POST', - data=ET.tostring(create_node_elm)).object - response_code = findtext(response, 'responseCode', TYPES_URN) - return response_code in ['IN_PROGRESS', 'OK'] - - def ex_destroy_pool(self, pool): - """ - Destroy an existing pool - - :param pool: The instance of ``DimensionDataPool`` to destroy - :type pool: ``DimensionDataPool`` - - :return: ``True`` for success, ``False`` for failure - :rtype: ``bool`` - """ - destroy_request = ET.Element('deletePool', - {'xmlns': TYPES_URN, - 'id': pool.id}) - - result = self.connection.request_with_orgId_api_2( - action='networkDomainVip/deletePool', - method='POST', - data=ET.tostring(destroy_request)).object - response_code = findtext(result, 'responseCode', TYPES_URN) - return response_code in ['IN_PROGRESS', 'OK'] - - def ex_get_pool_members(self, pool_id): - """ - Get the members of a pool - - :param pool: The instance of a pool - :type pool: ``DimensionDataPool`` - - :return: Returns an ``list`` of ``DimensionDataPoolMember`` - :rtype: ``list`` of ``DimensionDataPoolMember`` - """ - members = self.connection \ - .request_with_orgId_api_2('networkDomainVip/poolMember?poolId=%s' - % pool_id).object - return self._to_members(members) - - def ex_get_pool_member(self, pool_member_id): - """ - Get a specific member of a pool - - :param pool: The id of a pool member - :type pool: ``str`` - - :return: Returns an instance of ``DimensionDataPoolMember`` - :rtype: ``DimensionDataPoolMember`` - """ - member = self.connection \ - .request_with_orgId_api_2('networkDomainVip/poolMember/%s' - % pool_member_id).object - return self._to_member(member) - - def ex_set_pool_member_state(self, member, enabled=True): - request = ET.Element('editPoolMember', - {'xmlns': TYPES_URN, - 'id': member.id}) - state = "ENABLED" if enabled is True else "DISABLED" - ET.SubElement(request, 'status').text = state - - result = self.connection.request_with_orgId_api_2( - action='networkDomainVip/editPoolMember', - method='POST', - data=ET.tostring(request)).object - - response_code = findtext(result, 'responseCode', TYPES_URN) - return response_code in ['IN_PROGRESS', 'OK'] - - def ex_destroy_pool_member(self, member, destroy_node=False): - """ - Destroy a specific member of a pool - - :param pool: The instance of a pool member - :type pool: ``DimensionDataPoolMember`` - - :param destroy_node: Also destroy the associated node - :type destroy_node: ``bool`` - - :return: ``True`` for success, ``False`` for failure - :rtype: ``bool`` - """ - # remove the pool member - destroy_request = ET.Element('removePoolMember', - {'xmlns': TYPES_URN, - 'id': member.id}) - - result = self.connection.request_with_orgId_api_2( - action='networkDomainVip/removePoolMember', - method='POST', - data=ET.tostring(destroy_request)).object - - if member.node_id is not None and destroy_node is True: - return self.ex_destroy_node(member.node_id) - else: - response_code = findtext(result, 'responseCode', TYPES_URN) - return response_code in ['IN_PROGRESS', 'OK'] - - def ex_get_nodes(self): - """ - Get the nodes within this geography - - :return: Returns an ``list`` of ``DimensionDataVIPNode`` - :rtype: ``list`` of ``DimensionDataVIPNode`` - """ - nodes = self.connection \ - .request_with_orgId_api_2('networkDomainVip/node').object - return self._to_nodes(nodes) - - def ex_get_node(self, node_id): - """ - Get the node specified by node_id - - :return: Returns an instance of ``DimensionDataVIPNode`` - :rtype: Instance of ``DimensionDataVIPNode`` - """ - nodes = self.connection \ - .request_with_orgId_api_2('networkDomainVip/node/%s' - % node_id).object - return self._to_node(nodes) - - def ex_destroy_node(self, node_id): - """ - Destroy a specific node - - :param node_id: The ID of of a ``DimensionDataVIPNode`` - :type node_id: ``str`` - - :return: ``True`` for success, ``False`` for failure - :rtype: ``bool`` - """ - # Destroy the node - destroy_request = ET.Element('deleteNode', - {'xmlns': TYPES_URN, - 'id': node_id}) - - result = self.connection.request_with_orgId_api_2( - action='networkDomainVip/deleteNode', - method='POST', - data=ET.tostring(destroy_request)).object - response_code = findtext(result, 'responseCode', TYPES_URN) - return response_code in ['IN_PROGRESS', 'OK'] - - def ex_wait_for_state(self, state, func, poll_interval=2, - timeout=60, *args, **kwargs): - """ - Wait for the function which returns a instance - with field status to match - - Keep polling func until one of the desired states is matched - - :param state: Either the desired state (`str`) or a `list` of states - :type state: ``str`` or ``list`` - - :param func: The function to call, e.g. ex_get_vlan - :type func: ``function`` - - :param poll_interval: The number of seconds to wait between checks - :type poll_interval: `int` - - :param timeout: The total number of seconds to wait to reach a state - :type timeout: `int` - - :param args: The arguments for func - :type args: Positional arguments - - :param kwargs: The arguments for func - :type kwargs: Keyword arguments - """ - return self.connection.wait_for_state(state, func, poll_interval, - timeout, *args, **kwargs) - - def ex_get_default_health_monitors(self, network_domain_id): - """ - Get the default health monitors available for a network domain - - :param network_domain_id: The ID of of a ``DimensionDataNetworkDomain`` - :type network_domain_id: ``str`` - - :rtype: `list` of :class:`DimensionDataDefaultHealthMonitor` - """ - result = self.connection.request_with_orgId_api_2( - action='networkDomainVip/defaultHealthMonitor', - params={'networkDomainId': network_domain_id}, - method='GET').object - return self._to_health_monitors(result) - - def ex_get_default_persistence_profiles(self, network_domain_id): - """ - Get the default persistence profiles available for a network domain - - :param network_domain_id: The ID of of a ``DimensionDataNetworkDomain`` - :type network_domain_id: ``str`` - - :rtype: `list` of :class:`DimensionDataPersistenceProfile` - """ - result = self.connection.request_with_orgId_api_2( - action='networkDomainVip/defaultPersistenceProfile', - params={'networkDomainId': network_domain_id}, - method='GET').object - return self._to_persistence_profiles(result) - - def ex_get_default_irules(self, network_domain_id): - """ - Get the default iRules available for a network domain - - :param network_domain_id: The ID of of a ``DimensionDataNetworkDomain`` - :type network_domain_id: ``str`` - - :rtype: `list` of :class:`DimensionDataDefaultiRule` - """ - result = self.connection.request_with_orgId_api_2( - action='networkDomainVip/defaultIrule', - params={'networkDomainId': network_domain_id}, - method='GET').object - return self._to_irules(result) - - def _to_irules(self, object): - irules = [] - matches = object.findall( - fixxpath('defaultIrule', TYPES_URN)) - for element in matches: - irules.append(self._to_irule(element)) - return irules - - def _to_irule(self, element): - compatible = [] - matches = element.findall( - fixxpath('virtualListenerCompatibility', TYPES_URN)) - for match_element in matches: - compatible.append( - DimensionDataVirtualListenerCompatibility( - type=match_element.get('type'), - protocol=match_element.get('protocol', None))) - irule_element = element.find(fixxpath('irule', TYPES_URN)) - return DimensionDataDefaultiRule( - id=irule_element.get('id'), - name=irule_element.get('name'), - compatible_listeners=compatible - ) - - def _to_persistence_profiles(self, object): - profiles = [] - matches = object.findall( - fixxpath('defaultPersistenceProfile', TYPES_URN)) - for element in matches: - profiles.append(self._to_persistence_profile(element)) - return profiles - - def _to_persistence_profile(self, element): - compatible = [] - matches = element.findall( - fixxpath('virtualListenerCompatibility', TYPES_URN)) - for match_element in matches: - compatible.append( - DimensionDataVirtualListenerCompatibility( - type=match_element.get('type'), - protocol=match_element.get('protocol', None))) - - return DimensionDataPersistenceProfile( - id=element.get('id'), - fallback_compatible=bool( - element.get('fallbackCompatible') == "true"), - name=findtext(element, 'name', TYPES_URN), - compatible_listeners=compatible - ) - - def _to_health_monitors(self, object): - monitors = [] - matches = object.findall(fixxpath('defaultHealthMonitor', TYPES_URN)) - for element in matches: - monitors.append(self._to_health_monitor(element)) - return monitors - - def _to_health_monitor(self, element): - return DimensionDataDefaultHealthMonitor( - id=element.get('id'), - name=findtext(element, 'name', TYPES_URN), - node_compatible=bool( - findtext(element, 'nodeCompatible', TYPES_URN) == "true"), - pool_compatible=bool( - findtext(element, 'poolCompatible', TYPES_URN) == "true"), - ) - - def _to_nodes(self, object): - nodes = [] - for element in object.findall(fixxpath("node", TYPES_URN)): - nodes.append(self._to_node(element)) - - return nodes - - def _to_node(self, element): - ipaddress = findtext(element, 'ipv4Address', TYPES_URN) - if ipaddress is None: - ipaddress = findtext(element, 'ipv6Address', TYPES_URN) - - name = findtext(element, 'name', TYPES_URN) - - node = DimensionDataVIPNode( - id=element.get('id'), - name=name, - status=self._VALUE_TO_STATE_MAP.get( - findtext(element, 'state', TYPES_URN), - State.UNKNOWN), - connection_rate_limit=findtext(element, - 'connectionRateLimit', TYPES_URN), - connection_limit=findtext(element, 'connectionLimit', TYPES_URN), - ip=ipaddress) - - return node - - def _to_balancers(self, object): - loadbalancers = [] - for element in object.findall(fixxpath("virtualListener", TYPES_URN)): - loadbalancers.append(self._to_balancer(element)) - - return loadbalancers - - def _to_balancer(self, element): - ipaddress = findtext(element, 'listenerIpAddress', TYPES_URN) - name = findtext(element, 'name', TYPES_URN) - port = findtext(element, 'port', TYPES_URN) - extra = {} - - pool_element = element.find(fixxpath( - 'pool', - TYPES_URN)) - if pool_element is None: - extra['pool_id'] = None - - else: - extra['pool_id'] = pool_element.get('id') - - extra['network_domain_id'] = findtext(element, 'networkDomainId', - TYPES_URN) - - balancer = LoadBalancer( - id=element.get('id'), - name=name, - state=self._VALUE_TO_STATE_MAP.get( - findtext(element, 'state', TYPES_URN), - State.UNKNOWN), - ip=ipaddress, - port=port, - driver=self.connection.driver, - extra=extra - ) - - return balancer - - def _to_members(self, object): - members = [] - for element in object.findall(fixxpath("poolMember", TYPES_URN)): - members.append(self._to_member(element)) - - return members - - def _to_member(self, element): - port = findtext(element, 'port', TYPES_URN) - if port is not None: - port = int(port) - pool_member = DimensionDataPoolMember( - id=element.get('id'), - name=element.find(fixxpath( - 'node', - TYPES_URN)).get('name'), - status=findtext(element, 'state', TYPES_URN), - node_id=element.find(fixxpath( - 'node', - TYPES_URN)).get('id'), - ip=element.find(fixxpath( - 'node', - TYPES_URN)).get('ipAddress'), - port=port - ) - return pool_member - - def _to_pools(self, object): - pools = [] - for element in object.findall(fixxpath("pool", TYPES_URN)): - pools.append(self._to_pool(element)) - - return pools - - def _to_pool(self, element): - pool = DimensionDataPool( - id=element.get('id'), - name=findtext(element, 'name', TYPES_URN), - status=findtext(element, 'state', TYPES_URN), - description=findtext(element, 'description', TYPES_URN), - load_balance_method=findtext(element, 'loadBalanceMethod', - TYPES_URN), - health_monitor_id=findtext(element, 'healthMonitorId', TYPES_URN), - service_down_action=findtext(element, 'serviceDownAction', - TYPES_URN), - slow_ramp_time=findtext(element, 'slowRampTime', TYPES_URN), - ) - return pool
