You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2015/08/30 14:32:57 UTC

[09/21] libcloud git commit: [LIBCLOUD-737] Added create_listener to create the pool, add the nodes to the pool and create a virtual listener on the big-ip. Added docstrings to some of the methods. todo - complete unit tests for extended methods

[LIBCLOUD-737] Added create_listener to create the pool, add the nodes to the pool and create a virtual listener on the big-ip. Added docstrings to some of the methods. todo - complete unit tests for extended methods


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/2709109c
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/2709109c
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/2709109c

Branch: refs/heads/trunk
Commit: 2709109c7e015220f4871e93eb345f78241c31b3
Parents: b4ed5ea
Author: Anthony Shaw <an...@gmail.com>
Authored: Wed Aug 26 20:51:19 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Wed Aug 26 20:51:19 2015 +1000

----------------------------------------------------------------------
 libcloud/loadbalancer/drivers/dimensiondata.py | 272 +++++++++++++++++++-
 1 file changed, 263 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/2709109c/libcloud/loadbalancer/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
index e44b77e..dc6d728 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -84,7 +84,56 @@ class DimensionDataLBDriver(Driver):
         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
+        :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`
+        """
+        # TODO: Figure out which location is used...
+        network_domain_id=None
+        
+        # Create a pool first 
+        pool_id=self.ex_create_pool(
+            network_domain_id=network_domain_id,
+            name=name,
+            ex_description=None,
+            balancer_method=_ALGORITHM_TO_VALUE_MAP.get(algorithm)
+            )
         
+        # Attach the members to the pool as nodes
+        for member in members:
+            node_id=self.ex_create_node(
+                network_domain_id=network_domain_id,
+                name=member.name,
+                ip=member.ip,
+                ex_description=None
+                )
+            self.ex_create_pool_member(
+                pool_id=pool_id,
+                node_id=node_id,
+                port=port)
+            
+        # Create the virtual listener (balancer)
+        self.ex_create_virtual_listener(
+                       network_domain_id=network_domain_id,
+                       name=name,
+                       ex_description=None,
+                       port=port)
         return True
 
     def list_balancers(self):
@@ -124,7 +173,7 @@ class DimensionDataLBDriver(Driver):
 
         :rtype: ``list`` of ``str``
         """
-        return ['dns', 'ftp', 'http', 'https', 'tcp', 'udp']
+        return ['http', 'https', 'tcp', 'udp']
 
     def balancer_list_members(self, balancer):
         """
@@ -152,37 +201,240 @@ class DimensionDataLBDriver(Driver):
         return members
 
     def balancer_attach_member(self, balancer, member):
-        return True
+        """
+        Attach a member to balancer
 
-    def balancer_attach_compute_node(self, balancer, node):
+        :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`
+        """
+        
+        nodeId= self.ex_create_node(
+            network_domain_id=balancer.extra['network_domain_id'],
+            name=member.name,
+            ip=member.ip,
+            ex_description=member.description
+        )
+        if nodeId == false:
+            return False
+        
+        poolMemberId = self.ex_create_pool_member(balancer.extra['pool_id'],
+                                                  nodeId,
+                                                  member.port)
+        
         return True
 
     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': SERVER_NS,
+                                                        'id': member.id})
+
+        self.connection.request_with_orgId_api_2(
+            'networkDomainVip/removePoolMember',
+            method='POST',
+            data=ET.tostring(create_pool_m)).object
+        
         return True
 
     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': SERVER_NS,
+                                                               'id': balancer.id})
+
+        self.connection.request_with_orgId_api_2(
+            'networkDomainVip/deleteVirtualListener',
+            method='POST',
+            data=ET.tostring(delete_listener)).object
         return True
 
+    def ex_create_pool_member(self, pool_id, node_id, port):
+        """
+        Create a new member in an existing pool from an existing node
+
+        :param pool_id: ID of the pool (required)
+        :type  name: ``str``
+
+        :param node_id: ID of the node (required)
+        :type  name: ``str``
+
+        :param port: Port the the service will listen on
+        :type  port: ``str``
+
+        :return: ID of the node member, ``False`` if failed to add. 
+        :rtype: ``str``
+        """
+        create_pool_m = ET.Element('addPoolMember', {'xmlns': SERVER_NS})
+        ET.SubElement(create_pool_m, "poolId").text = pool_id
+        ET.SubElement(create_pool_m, "nodeId").text = node_id
+        ET.SubElement(create_pool_m, "port").text = port
+
+        response = self.connection.request_with_orgId_api_2(
+            'networkDomainVip/addPoolMember',
+            method='POST',
+            data=ET.tostring(create_pool_m)).object
+        
+        for info in findall(response, 'info', TYPES_URN):
+            if info.name == 'poolMemberId':
+                return info.value
+        
+        return False
+
     def ex_create_node(self,
                        network_domain_id,
                        name,
                        ip,
                        ex_description,
-                       connectionLimit=25000,
-                       connectionRateLimit=2000):
+                       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
+        :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: ID of the node, ``False`` if failed to add. 
+        :rtype: ``str``
+        """
         create_node_elm = ET.Element('createNode', {'xmlns': SERVER_NS})
         ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
         ET.SubElement(create_node_elm, "description").text = ex_description
         ET.SubElement(create_node_elm, "name").text = name
         ET.SubElement(create_node_elm, "ipv4Address").text = ip
-        ET.SubElement(create_node_elm, "connectionLimit").text = connectionLimit
-        ET.SubElement(create_node_elm, "connectionRateLimit").text = connectionRateLimit
+        ET.SubElement(create_node_elm, "connectionLimit").text = connection_limit
+        ET.SubElement(create_node_elm, "connectionRateLimit").text = connection_rate_limit
 
-        self.connection.request_with_orgId_api_2(
+        response = self.connection.request_with_orgId_api_2(
             'networkDomainVip/createNode',
             method='POST',
             data=ET.tostring(create_node_elm)).object
-        return True
+        
+        for info in findall(response, 'info', TYPES_URN):
+            if info.name == 'nodeId':
+                return info.value
+        
+        return None
+
+    def ex_create_pool(self,
+                       network_domain_id,
+                       name,
+                       balancer_method,
+                       ex_description,
+                       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
+        :type  ex_description: ``str``
+        
+        :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: ID of the pool, ``False`` if failed to add. 
+        :rtype: ``str``
+        """
+        create_node_elm = ET.Element('createPool', {'xmlns': SERVER_NS})
+        ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
+        ET.SubElement(create_node_elm, "description").text = ex_description
+        ET.SubElement(create_node_elm, "name").text = name
+        ET.SubElement(create_node_elm, "loadBalancerMethod").text = balancer_method
+        ET.SubElement(create_node_elm, "serviceDownAction").text = service_down_action
+        ET.SubElement(create_node_elm, "slowRampTime").text = slow_ramp_time
+
+        response = self.connection.request_with_orgId_api_2(
+            'networkDomainVip/createPool',
+            method='POST',
+            data=ET.tostring(create_node_elm)).object
+        
+        for info in findall(response, 'info', TYPES_URN):
+            if info.name == 'poolId':
+                return info.value
+        
+        return False
+
+    def ex_create_virtual_listener(self,
+                       network_domain_id,
+                       name,
+                       ex_description,
+                       port,
+                       listener_type='STANDARD',
+                       protocol='ANY',
+                       connection_limit=25000,
+                       connection_rate_limit=2000,
+                       source_port_preservation='PRESERVE'):
+        create_node_elm = ET.Element('createVirtualListener', {'xmlns': SERVER_NS})
+        ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
+        ET.SubElement(create_node_elm, "description").text = ex_description
+        ET.SubElement(create_node_elm, "name").text = name
+        ET.SubElement(create_node_elm, "port").text = port
+        ET.SubElement(create_node_elm, "type").text = listener_type
+        ET.SubElement(create_node_elm, "connectionLimit").text = connection_limit
+        ET.SubElement(create_node_elm, "connectionRateLimit").text = connection_rate_limit
+        ET.SubElement(create_node_elm, "sourcePortPreservation").text = source_port_preservation
+
+        response = self.connection.request_with_orgId_api_2(
+            'networkDomainVip/createVirtualListener',
+            method='POST',
+            data=ET.tostring(create_node_elm)).object
+        
+        for info in findall(response, 'info', TYPES_URN):
+            if info.name == 'poolId':
+                return info.value
+        
+        return False
 
     def ex_get_pools(self):
         pools = self.connection \
@@ -223,6 +475,8 @@ class DimensionDataLBDriver(Driver):
         extra['pool_id'] = element.find(fixxpath(
                 'pool',
                 TYPES_URN)).get('id')
+        extra['network_domain_id'] = findtext(element, 'networkDomainId',
+                                              TYPES_URN)
         
         balancer = LoadBalancer(
             id=element.get('id'),