| # 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 BaseDriver, ConnectionKey |
| from libcloud.common.types import LibcloudError |
| |
| __all__ = ["Member", "LoadBalancer", "Algorithm", "Driver", "DEFAULT_ALGORITHM"] |
| |
| |
| class Member: |
| """ |
| 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={}, address={}:{}>".format(self.id, self.ip, self.port) |
| |
| |
| class LoadBalancer: |
| """ |
| 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: |
| """ |
| 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 |
| LEAST_CONNECTIONS_MEMBER = 7 |
| LEAST_CONNECTIONS_NODE = 8 |
| OBSERVED_MEMBER = 9 |
| OBSERVED_NODE = 10 |
| PREDICTIVE_MEMBER = 11 |
| PREDICTIVE_NODE = 12 |
| |
| |
| 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().__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) |