Author: tomaz
Date: Mon Dec 12 18:53:24 2011
New Revision: 1213364

URL: http://svn.apache.org/viewvc?rev=1213364&view=rev
Log:
Add many improvements to the Rackspace LoadBalancer driver. This patch has been
contributed by Dave King and is part of GH-43.

Added:
    
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_accesslist.json
    
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_errorpage.json
    
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94692_weighted_round_robin.json
    
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94693_weighted_least_connections.json
    
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94694_unknown_algorithm.json
    
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94695_full_details.json
    
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94696_http_health_monitor.json
    
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94697_https_health_monitor.json
    
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_algorithms.json
Modified:
    libcloud/trunk/CHANGES
    libcloud/trunk/libcloud/loadbalancer/base.py
    libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py
    libcloud/trunk/libcloud/loadbalancer/types.py
    libcloud/trunk/test/loadbalancer/test_cloudstack.py
    libcloud/trunk/test/loadbalancer/test_gogrid.py
    libcloud/trunk/test/loadbalancer/test_rackspace.py

Modified: libcloud/trunk/CHANGES
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1213364&r1=1213363&r2=1213364&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Mon Dec 12 18:53:24 2011
@@ -15,6 +15,21 @@ Changes with Apache Libcloud in developm
       virtual IP addresses in the Rackspace driver.
       [Dave King]
 
+    - Add list_supported_algorithms() method to the base LoadBalancer class.
+      This method returns a list of supported algorithms by the provider.
+      [Dave King]
+
+    - Update Rackspace driver:
+      - Add two new supported algorithms: WEIGHTED_ROUND_ROBIN,
+        WEIGHTED_LEAST_CONNECTIONS
+      - Add ex_list_algorithm_names method
+      - Add ex_get_balancer_error_page method
+      - Add ex_balancer_access_list method
+      - Populate LoadBalancer extra dictionary with more attributes
+      - Add support for health monitors and connection throttling
+      - Add more balancer states
+      [Dave King]
+
 Changes with Apache Libcloud 0.7.1:
 
   *) General:

Modified: libcloud/trunk/libcloud/loadbalancer/base.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/loadbalancer/base.py?rev=1213364&r1=1213363&r2=1213364&view=diff
==============================================================================
--- libcloud/trunk/libcloud/loadbalancer/base.py (original)
+++ libcloud/trunk/libcloud/loadbalancer/base.py Mon Dec 12 18:53:24 2011
@@ -40,6 +40,8 @@ class Algorithm(object):
     RANDOM = 0
     ROUND_ROBIN = 1
     LEAST_CONNECTIONS = 2
+    WEIGHTED_ROUND_ROBIN = 3
+    WEIGHTED_LEAST_CONNECTIONS = 4
 
 DEFAULT_ALGORITHM = Algorithm.ROUND_ROBIN
 
@@ -226,3 +228,9 @@ class Driver(BaseDriver):
         except KeyError:
             raise LibcloudError(value='Invalid algorithm: %s' % (algorithm),
                                 driver=self)
+
+    def list_supported_algorithms(self):
+        """
+        Return algorithms supported by this driver.
+        """
+        return list(self._ALGORITHM_TO_VALUE_MAP.keys())

Modified: libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py?rev=1213364&r1=1213363&r2=1213364&view=diff
==============================================================================
--- libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py (original)
+++ libcloud/trunk/libcloud/loadbalancer/drivers/rackspace.py Mon Dec 12 
18:53:24 2011
@@ -42,6 +42,119 @@ class RackspaceResponse(JsonResponse):
         return 200 <= int(self.status) <= 299
 
 
+class RackspaceHealthMonitor(object):
+    """
+    @param type: type of load balancer.  currently CONNECT (connection
+                 monitoring), HTTP, HTTPS (connection and HTTP
+                 monitoring) are supported.
+    @type type: C{str}
+
+    @param delay: minimum seconds to wait before executing the health
+                  monitor.  (Must be between 1 and 3600)
+    @type delay: C{int}
+
+    @param timeout: maximum seconds to wait when establishing a
+                    connection before timing out.  (Must be between 1
+                    and 3600)
+    @type timeout: C{int}
+
+    @param attempts_before_deactivation: Number of monitor failures
+                                         before removing a node from
+                                         rotation. (Must be between 1
+                                         and 10)
+    @type attempts_before_deactivation: C{int}
+    """
+
+    def __init__(self, type, delay, timeout, attempts_before_deactivation):
+        self.type = type
+        self.delay = delay
+        self.timeout = timeout
+        self.attempts_before_deactivation = attempts_before_deactivation
+
+
+class RackspaceHTTPHealthMonitor(RackspaceHealthMonitor):
+    """
+    A HTTP health monitor adds extra features to a Rackspace health monitor.
+
+    @param path: the HTTP path to monitor.
+    @type path: C{str}
+
+    @param body_regex: Regular expression used to evaluate the body of
+                       the HTTP response.
+    @type body_regex: C{str}
+
+    @param status_regex: Regular expression used to evaluate the HTTP
+                         status code of the response.
+    @type status_regex: C{str}
+    """
+
+    def __init__(self, type, delay, timeout, attempts_before_deactivation,
+                 path, body_regex, status_regex):
+        super(RackspaceHTTPHealthMonitor, self).__init__(type, delay, timeout,
+            attempts_before_deactivation)
+        self.path = path
+        self.body_regex = body_regex
+        self.status_regex = status_regex
+
+
+class RackspaceConnectionThrottle(object):
+    """
+    @param min_connections: Minimum number of connections per IP address
+                            before applying throttling.
+    @type min_connections: C{int}
+
+    @param max_connections: Maximum number of of connections per IP address.
+                            (Must be between 0 and 100000, 0 allows an 
+                            unlimited number of connections.)
+    @type max_connections: C{int}
+
+    @param max_connection_rate: Maximum number of connections allowed
+                                from a single IP address within the
+                                given rate_interval_seconds.  (Must be
+                                between 0 and 100000, 0 allows an
+                                unlimited number of connections.)
+    @type max_connection_rate: C{int}
+
+    @param rate_interval_seconds: Interval at which the
+                                  max_connection_rate is enforced.
+                                  (Must be between 1 and 3600.)
+    @type rate_interval_seconds: C{int}
+    """
+
+    def __init__(self, min_connections, max_connections,
+                 max_connection_rate, rate_interval_seconds):
+        self.min_connections = min_connections
+        self.max_connections = max_connections
+        self.max_connection_rate = max_connection_rate
+        self.rate_interval_seconds = rate_interval_seconds
+
+
+class RackspaceAccessRuleType(object):
+    ALLOW = 0
+    DENY = 1
+
+
+class RackspaceAccessRule(object):
+    """
+    An access rule allows or denies traffic to a Load Balancer based on the
+    incoming IPs.
+
+    @param id: Unique identifier to refer to this rule by.
+    @type id: C{str}
+
+    @param rule_type: ALLOW or DENY.
+    @type id: C{RackspaceAccessRuleType}
+
+    @param address: IP address or cidr (can be IPv4 or IPv6).
+    @type address: C{str}
+    """
+
+    def __init__(self, id, rule_type, address):
+        self.id = id
+        self.rule_type = rule_type
+        self.address = address
+
+
 class RackspaceConnection(OpenStackBaseConnection):
     responseCls = RackspaceResponse
     auth_url = AUTH_URL_US
@@ -52,7 +165,8 @@ class RackspaceConnection(OpenStackBaseC
         self.api_version = 'v1.0'
         self.accept_format = 'application/json'
 
-    def request(self, action, params=None, data='', headers=None, 
method='GET'):
+    def request(self, action, params=None, data='', headers=None,
+                method='GET'):
         if not headers:
             headers = {}
         if not params:
@@ -76,13 +190,23 @@ class RackspaceLBDriver(Driver):
     api_name = 'rackspace_lb'
     name = 'Rackspace LB'
 
-    LB_STATE_MAP = { 'ACTIVE': State.RUNNING,
-                     'BUILD': State.PENDING }
+    LB_STATE_MAP = {
+        'ACTIVE': State.RUNNING,
+        'BUILD': State.PENDING,
+        'ERROR': State.ERROR,
+        'DELETED': State.DELETED,
+        'PENDING_UPDATE': State.PENDING,
+        'PENDING_DELETE': State.PENDING
+    }
+
     _VALUE_TO_ALGORITHM_MAP = {
         'RANDOM': Algorithm.RANDOM,
         'ROUND_ROBIN': Algorithm.ROUND_ROBIN,
-        'LEAST_CONNECTIONS': Algorithm.LEAST_CONNECTIONS
+        'LEAST_CONNECTIONS': Algorithm.LEAST_CONNECTIONS,
+        'WEIGHTED_ROUND_ROBIN': Algorithm.WEIGHTED_ROUND_ROBIN,
+        'WEIGHTED_LEAST_CONNECTIONS': Algorithm.WEIGHTED_LEAST_CONNECTIONS
     }
+
     _ALGORITHM_TO_VALUE_MAP = reverse_dict(_VALUE_TO_ALGORITHM_MAP)
 
     def list_protocols(self):
@@ -155,8 +279,8 @@ class RackspaceLBDriver(Driver):
 
     def balancer_detach_member(self, balancer, member):
         # Loadbalancer always needs to have at least 1 member.
-        # Last member cannot be detached. You can only disable it or destroy 
the
-        # balancer.
+        # Last member cannot be detached. You can only disable it or destroy
+        # the balancer.
         uri = '/loadbalancers/%s/nodes/%s' % (balancer.id, member.id)
         resp = self.connection.request(uri, method='DELETE')
 
@@ -167,6 +291,26 @@ class RackspaceLBDriver(Driver):
         return self._to_members(
                 self.connection.request(uri).object)
 
+    def ex_list_algorithm_names(self):
+        """
+        Lists algorithms supported by the API.  Returned as strings because
+        this list may change in the future.
+        """
+        response = self.connection.request('/loadbalancers/algorithms')
+        return [a["name"].upper() for a in response.object["algorithms"]]
+
+    def ex_get_balancer_error_page(self, balancer):
+        uri = '/loadbalancers/%s/errorpage' % (balancer.id)
+        resp = self.connection.request(uri)
+
+        return resp.object["errorpage"]["content"]
+
+    def ex_balancer_access_list(self, balancer):
+        uri = '/loadbalancers/%s/accesslist' % (balancer.id)
+        resp = self.connection.request(uri)
+
+        return [self._to_access_rule(el) for el in resp.object["accessList"]]
+
     def _to_protocols(self, object):
         protocols = []
         for item in object["protocols"]:
@@ -174,7 +318,7 @@ class RackspaceLBDriver(Driver):
         return protocols
 
     def _to_balancers(self, object):
-        return [ self._to_balancer(el) for el in object["loadBalancers"] ]
+        return [self._to_balancer(el) for el in object["loadBalancers"]]
 
     def _to_balancer(self, el):
         ip = None
@@ -190,6 +334,33 @@ class RackspaceLBDriver(Driver):
         if 'sourceAddresses' in el:
             sourceAddresses = el['sourceAddresses']
 
+        extra = {
+            "publicVips": self._ex_public_virtual_ips(el),
+            "privateVips": self._ex_private_virtual_ips(el),
+            "ipv6PublicSource": sourceAddresses.get("ipv6Public"),
+            "ipv4PublicSource": sourceAddresses.get("ipv4Public"),
+            "ipv4PrivateSource": sourceAddresses.get("ipv4Servicenet"),
+        }
+
+        if 'algorithm' in el and el["algorithm"] in 
self._VALUE_TO_ALGORITHM_MAP:
+            extra["algorithm"] = self._value_to_algorithm(el["algorithm"])
+
+        if 'healthMonitor' in el:
+            health_monitor = self._to_health_monitor(el)
+            if health_monitor:
+                extra["healthMonitor"] = health_monitor
+
+        if 'connectionThrottle' in el:
+            extra["connectionThrottle"] = self._to_connection_throttle(el)
+
+        if 'sessionPersistence' in el:
+            persistence = el["sessionPersistence"]
+            extra["sessionPersistenceType"] = 
persistence.get("persistenceType")
+
+        if 'connectionLogging' in el:
+            logging = el["connectionLogging"]
+            extra["connectionLoggingEnabled"] = logging.get("enabled")
+
         return LoadBalancer(id=el["id"],
                 name=el["name"],
                 state=self.LB_STATE_MAP.get(
@@ -197,16 +368,10 @@ class RackspaceLBDriver(Driver):
                 ip=ip,
                 port=port,
                 driver=self.connection.driver,
-                extra={
-                    "publicVips": self._ex_public_virtual_ips(el) or [],
-                    "privateVips": self._ex_private_virtual_ips(el) or [],
-                    "ipv6PublicSource": sourceAddresses.get("ipv6Public"),
-                    "ipv4PublicSource": sourceAddresses.get("ipv4Public"),
-                    "ipv4PrivateSource": sourceAddresses.get("ipv4Servicenet")
-                })
+                extra=extra)
 
     def _to_members(self, object):
-        return [ self._to_member(el) for el in object["nodes"] ]
+        return [self._to_member(el) for el in object["nodes"]]
 
     def _to_member(self, el):
         lbmember = Member(id=el["id"],
@@ -229,6 +394,53 @@ class RackspaceLBDriver(Driver):
         public_vips = [ip for ip in el['virtualIps'] if ip['type'] == 'PUBLIC']
         return [vip["address"] for vip in public_vips]
 
+    def _to_health_monitor(self, el):
+        health_monitor_data = el["healthMonitor"]
+
+        type = health_monitor_data.get("type")
+        delay = health_monitor_data.get("delay")
+        timeout = health_monitor_data.get("timeout")
+        attempts_before_deactivation = 
health_monitor_data.get("attemptsBeforeDeactivation")
+
+        if type == "CONNECT":
+            return RackspaceHealthMonitor(type=type, delay=delay,
+                timeout=timeout,
+                attempts_before_deactivation=attempts_before_deactivation)
+
+        if type == "HTTP" or type == "HTTPS":
+            return RackspaceHTTPHealthMonitor(type=type, delay=delay,
+                timeout=timeout,
+                attempts_before_deactivation=attempts_before_deactivation,
+                path=health_monitor_data.get("path"),
+                status_regex=health_monitor_data.get("statusRegex"),
+                body_regex=health_monitor_data.get("bodyRegex"))
+
+        return None
+
+    def _to_connection_throttle(self, el):
+        connection_throttle_data = el["connectionThrottle"]
+
+        min_connections = connection_throttle_data.get("minConnections")
+        max_connections = connection_throttle_data.get("maxConnections")
+        max_connection_rate = connection_throttle_data.get("maxConnectionRate")
+        rate_interval = connection_throttle_data.get("rateInterval")
+
+        return RackspaceConnectionThrottle(min_connections=min_connections,
+            max_connections=max_connections,
+            max_connection_rate=max_connection_rate,
+            rate_interval_seconds=rate_interval)
+
+    def _to_access_rule(self, el):
+        return RackspaceAccessRule(id=el.get("id"),
+            rule_type=self._to_access_rule_type(el.get("type")),
+            address=el.get("address"))
+
+    def _to_access_rule_type(self, type):
+        if type == "ALLOW":
+            return RackspaceAccessRuleType.ALLOW
+        elif type == "DENY":
+            return RackspaceAccessRuleType.DENY
+
 
 class RackspaceUKLBDriver(RackspaceLBDriver):
     connectionCls = RackspaceUKConnection

Modified: libcloud/trunk/libcloud/loadbalancer/types.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/libcloud/loadbalancer/types.py?rev=1213364&r1=1213363&r2=1213364&view=diff
==============================================================================
--- libcloud/trunk/libcloud/loadbalancer/types.py (original)
+++ libcloud/trunk/libcloud/loadbalancer/types.py Mon Dec 12 18:53:24 2011
@@ -49,3 +49,5 @@ class State(object):
     RUNNING = 0
     PENDING = 1
     UNKNOWN = 2
+    ERROR = 3
+    DELETED = 4

Added: 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_accesslist.json
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_accesslist.json?rev=1213364&view=auto
==============================================================================
--- 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_accesslist.json
 (added)
+++ 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_accesslist.json
 Mon Dec 12 18:53:24 2011
@@ -0,0 +1 @@
+{"accessList":[{"address":"0.0.0.0/0","id":2883,"type":"DENY"},{"address":"2001:4801:7901::6/64","id":2884,"type":"ALLOW"}]}
\ No newline at end of file

Added: 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_errorpage.json
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_errorpage.json?rev=1213364&view=auto
==============================================================================
--- 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_errorpage.json
 (added)
+++ 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_18940_errorpage.json
 Mon Dec 12 18:53:24 2011
@@ -0,0 +1 @@
+{"errorpage":{"content":"<html><head><meta http-equiv=\"Content-Type\" 
content=\"text/html;charset=utf-8\"><title>Service Unavailable</title><style 
type=\"text/css\">body, p, h1 {font-family: Verdana, Arial, Helvetica, 
sans-serif;}h2 {font-family: Arial, Helvetica, sans-serif;color: 
#b10b29;}</style></head><body><h2>Service Unavailable</h2><p>The service is 
temporarily unavailable. Please try again later.</p></body></html>"}}
\ No newline at end of file

Added: 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94692_weighted_round_robin.json
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94692_weighted_round_robin.json?rev=1213364&view=auto
==============================================================================
--- 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94692_weighted_round_robin.json
 (added)
+++ 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94692_weighted_round_robin.json
 Mon Dec 12 18:53:24 2011
@@ -0,0 +1 @@
+{"loadBalancer":{"name":"new ord 
balancer","id":18940,"protocol":"HTTP","port":80,"algorithm":"WEIGHTED_ROUND_ROBIN","status":"ACTIVE","cluster":{"name":"ztm-n06.lbaas.ord1.rackspace.net"},"nodes":[{"address":"10.181.231.202","id":94692,"port":80,"status":"ONLINE","condition":"ENABLED","weight":1}],"created":{"time":"2011-12-09T13:30:40Z"},"virtualIps":[{"address":"50.56.49.149","id":2359,"type":"PUBLIC","ipVersion":"IPV4"}],"sourceAddresses":{"ipv6Public":"2001:4801:7901::6/64","ipv4Servicenet":"10.183.252.25","ipv4Public":"184.106.100.25"},"updated":{"time":"2011-12-09T14:39:40Z"},"connectionLogging":{"enabled":false}}}
\ No newline at end of file

Added: 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94693_weighted_least_connections.json
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94693_weighted_least_connections.json?rev=1213364&view=auto
==============================================================================
--- 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94693_weighted_least_connections.json
 (added)
+++ 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94693_weighted_least_connections.json
 Mon Dec 12 18:53:24 2011
@@ -0,0 +1 @@
+{"loadBalancer":{"name":"new ord 
balancer","id":18940,"protocol":"HTTP","port":80,"algorithm":"WEIGHTED_LEAST_CONNECTIONS","status":"PENDING_UPDATE","cluster":{"name":"ztm-n06.lbaas.ord1.rackspace.net"},"nodes":[{"address":"10.181.231.202","id":94692,"port":80,"status":"ONLINE","condition":"ENABLED","weight":1}],"created":{"time":"2011-12-09T13:30:40Z"},"virtualIps":[{"address":"50.56.49.149","id":2359,"type":"PUBLIC","ipVersion":"IPV4"}],"sourceAddresses":{"ipv6Public":"2001:4801:7901::6/64","ipv4Servicenet":"10.183.252.25","ipv4Public":"184.106.100.25"},"updated":{"time":"2011-12-09T15:18:38Z"},"connectionLogging":{"enabled":false}}}

Added: 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94694_unknown_algorithm.json
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94694_unknown_algorithm.json?rev=1213364&view=auto
==============================================================================
--- 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94694_unknown_algorithm.json
 (added)
+++ 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94694_unknown_algorithm.json
 Mon Dec 12 18:53:24 2011
@@ -0,0 +1 @@
+{"loadBalancer":{"name":"new ord 
balancer","id":18940,"protocol":"HTTP","port":80,"algorithm":"UNSPECIFIED_FUTURE_ALGORITHM","status":"PENDING_UPDATE","cluster":{"name":"ztm-n06.lbaas.ord1.rackspace.net"},"nodes":[{"address":"10.181.231.202","id":94692,"port":80,"status":"ONLINE","condition":"ENABLED","weight":1}],"created":{"time":"2011-12-09T13:30:40Z"},"virtualIps":[{"address":"50.56.49.149","id":2359,"type":"PUBLIC","ipVersion":"IPV4"}],"sourceAddresses":{"ipv6Public":"2001:4801:7901::6/64","ipv4Servicenet":"10.183.252.25","ipv4Public":"184.106.100.25"},"updated":{"time":"2011-12-09T15:18:38Z"},"connectionLogging":{"enabled":false}}}

Added: 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94695_full_details.json
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94695_full_details.json?rev=1213364&view=auto
==============================================================================
--- 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94695_full_details.json
 (added)
+++ 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94695_full_details.json
 Mon Dec 12 18:53:24 2011
@@ -0,0 +1 @@
+{"loadBalancer":{"name":"new ord 
balancer","id":18940,"protocol":"HTTP","port":80,"algorithm":"WEIGHTED_LEAST_CONNECTIONS","status":"ACTIVE","cluster":{"name":"ztm-n06.lbaas.ord1.rackspace.net"},"nodes":[{"address":"10.181.231.202","id":94692,"port":80,"status":"OFFLINE","condition":"ENABLED","weight":1}],"created":{"time":"2011-12-09T13:30:40Z"},"healthMonitor":{"type":"CONNECT","delay":10,"timeout":5,"attemptsBeforeDeactivation":2},"sessionPersistence":{"persistenceType":"HTTP_COOKIE"},"virtualIps":[{"address":"50.56.49.149","id":2359,"type":"PUBLIC","ipVersion":"IPV4"}],"sourceAddresses":{"ipv6Public":"2001:4801:7901::6/64","ipv4Servicenet":"10.183.252.25","ipv4Public":"184.106.100.25"},"updated":{"time":"2011-12-09T16:01:36Z"},"connectionThrottle":{"maxConnections":200,"minConnections":50,"maxConnectionRate":50,"rateInterval":10},"connectionLogging":{"enabled":true}}}
\ No newline at end of file

Added: 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94696_http_health_monitor.json
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94696_http_health_monitor.json?rev=1213364&view=auto
==============================================================================
--- 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94696_http_health_monitor.json
 (added)
+++ 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94696_http_health_monitor.json
 Mon Dec 12 18:53:24 2011
@@ -0,0 +1 @@
+{"loadBalancer":{"name":"new ord 
balancer","id":18940,"protocol":"HTTP","port":80,"algorithm":"WEIGHTED_LEAST_CONNECTIONS","status":"ACTIVE","cluster":{"name":"ztm-n06.lbaas.ord1.rackspace.net"},"nodes":[{"address":"10.181.231.202","id":94692,"port":80,"status":"ONLINE","condition":"ENABLED","weight":1}],"created":{"time":"2011-12-09T13:30:40Z"},"healthMonitor":{"type":"HTTP","path":"/","delay":10,"timeout":5,"attemptsBeforeDeactivation":2,"statusRegex":"^[234][0-9][0-9]$","bodyRegex":"Hello
 
World!"},"sessionPersistence":{"persistenceType":"HTTP_COOKIE"},"virtualIps":[{"address":"50.56.49.149","id":2359,"type":"PUBLIC","ipVersion":"IPV4"}],"sourceAddresses":{"ipv6Public":"2001:4801:7901::6/64","ipv4Servicenet":"10.183.252.25","ipv4Public":"184.106.100.25"},"updated":{"time":"2011-12-09T16:51:32Z"},"connectionThrottle":{"maxConnections":100,"minConnections":25,"maxConnectionRate":25,"rateInterval":5},"connectionLogging":{"enabled":true}}}
\ No newline at end of file

Added: 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94697_https_health_monitor.json
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94697_https_health_monitor.json?rev=1213364&view=auto
==============================================================================
--- 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94697_https_health_monitor.json
 (added)
+++ 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_94697_https_health_monitor.json
 Mon Dec 12 18:53:24 2011
@@ -0,0 +1 @@
+{"loadBalancer":{"name":"new ord 
balancer","id":18940,"protocol":"HTTPS","port":443,"algorithm":"WEIGHTED_LEAST_CONNECTIONS","status":"PENDING_UPDATE","cluster":{"name":"ztm-n06.lbaas.ord1.rackspace.net"},"nodes":[{"address":"10.181.231.202","id":94692,"port":80,"status":"OFFLINE","condition":"ENABLED","weight":1}],"created":{"time":"2011-12-09T13:30:40Z"},"healthMonitor":{"type":"HTTPS","path":"/test","delay":15,"timeout":12,"attemptsBeforeDeactivation":5,"statusRegex":"^[234][0-9][0-9]$","bodyRegex":"abcdef"},"virtualIps":[{"address":"50.56.49.149","id":2359,"type":"PUBLIC","ipVersion":"IPV4"}],"sourceAddresses":{"ipv6Public":"2001:4801:7901::6/64","ipv4Servicenet":"10.183.252.25","ipv4Public":"184.106.100.25"},"updated":{"time":"2011-12-09T19:34:34Z"},"accessList":[{"address":"0.0.0.0/0","id":2883,"type":"DENY"},{"address":"2001:4801:7901::6/64","id":2884,"type":"ALLOW"}],"connectionThrottle":{"maxConnections":100,"minConnections":25,"maxConnectionRate":25,"rateInterval":
 5},"connectionLogging":{"enabled":true}}}

Added: 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_algorithms.json
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_algorithms.json?rev=1213364&view=auto
==============================================================================
--- 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_algorithms.json
 (added)
+++ 
libcloud/trunk/test/loadbalancer/fixtures/rackspace/v1_slug_loadbalancers_algorithms.json
 Mon Dec 12 18:53:24 2011
@@ -0,0 +1 @@
+{"algorithms":[{"name":"LEAST_CONNECTIONS"},{"name":"RANDOM"},{"name":"ROUND_ROBIN"},{"name":"WEIGHTED_LEAST_CONNECTIONS"},{"name":"WEIGHTED_ROUND_ROBIN"}]}

Modified: libcloud/trunk/test/loadbalancer/test_cloudstack.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/test_cloudstack.py?rev=1213364&r1=1213363&r2=1213364&view=diff
==============================================================================
--- libcloud/trunk/test/loadbalancer/test_cloudstack.py (original)
+++ libcloud/trunk/test/loadbalancer/test_cloudstack.py Mon Dec 12 18:53:24 2011
@@ -33,6 +33,12 @@ class CloudStackLBTests(unittest.TestCas
         CloudStackMockHttp.fixture_tag = 'default'
         self.driver.connection.poll_interval = 0.0
 
+    def test_list_supported_algorithms(self):
+        algorithms = self.driver.list_supported_algorithms()
+
+        self.assertTrue(Algorithm.ROUND_ROBIN in algorithms)
+        self.assertTrue(Algorithm.LEAST_CONNECTIONS in algorithms)
+
     def test_list_balancers(self):
         balancers = self.driver.list_balancers()
         for balancer in balancers:

Modified: libcloud/trunk/test/loadbalancer/test_gogrid.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/test_gogrid.py?rev=1213364&r1=1213363&r2=1213364&view=diff
==============================================================================
--- libcloud/trunk/test/loadbalancer/test_gogrid.py (original)
+++ libcloud/trunk/test/loadbalancer/test_gogrid.py Mon Dec 12 18:53:24 2011
@@ -36,6 +36,12 @@ class GoGridTests(unittest.TestCase):
         GoGridLBMockHttp.type = None
         self.driver = GoGridLBDriver('user', 'key')
 
+    def test_list_supported_algorithms(self):
+        algorithms = self.driver.list_supported_algorithms()
+
+        self.assertTrue(Algorithm.ROUND_ROBIN in algorithms)
+        self.assertTrue(Algorithm.LEAST_CONNECTIONS in algorithms)
+
     def test_list_protocols(self):
         protocols = self.driver.list_protocols()
 

Modified: libcloud/trunk/test/loadbalancer/test_rackspace.py
URL: 
http://svn.apache.org/viewvc/libcloud/trunk/test/loadbalancer/test_rackspace.py?rev=1213364&r1=1213363&r2=1213364&view=diff
==============================================================================
--- libcloud/trunk/test/loadbalancer/test_rackspace.py (original)
+++ libcloud/trunk/test/loadbalancer/test_rackspace.py Mon Dec 12 18:53:24 2011
@@ -26,10 +26,12 @@ from libcloud.utils.py3 import httplib
 from libcloud.loadbalancer.base import Member, Algorithm
 from libcloud.loadbalancer.drivers.rackspace import RackspaceLBDriver
 from libcloud.loadbalancer.drivers.rackspace import RackspaceUKLBDriver
+from libcloud.loadbalancer.drivers.rackspace import RackspaceAccessRuleType
 
 from test import MockHttpTestCase
 from test.file_fixtures import LoadBalancerFileFixtures, OpenStackFixtures
 
+
 class RackspaceLBTests(unittest.TestCase):
 
     def setUp(self):
@@ -44,6 +46,24 @@ class RackspaceLBTests(unittest.TestCase
         self.assertEqual(len(protocols), 10)
         self.assertTrue('http' in protocols)
 
+    def test_list_supported_algorithms(self):
+        algorithms = self.driver.list_supported_algorithms()
+
+        self.assertTrue(Algorithm.RANDOM in algorithms)
+        self.assertTrue(Algorithm.ROUND_ROBIN in algorithms)
+        self.assertTrue(Algorithm.LEAST_CONNECTIONS in algorithms)
+        self.assertTrue(Algorithm.WEIGHTED_ROUND_ROBIN in algorithms)
+        self.assertTrue(Algorithm.WEIGHTED_LEAST_CONNECTIONS in algorithms)
+
+    def test_ex_list_algorithms(self):
+        algorithms = self.driver.ex_list_algorithm_names()
+
+        self.assertTrue("RANDOM" in algorithms)
+        self.assertTrue("ROUND_ROBIN" in algorithms)
+        self.assertTrue("LEAST_CONNECTIONS" in algorithms)
+        self.assertTrue("WEIGHTED_ROUND_ROBIN" in algorithms)
+        self.assertTrue("WEIGHTED_LEAST_CONNECTIONS" in algorithms)
+
     def test_list_balancers(self):
         balancers = self.driver.list_balancers()
 
@@ -67,7 +87,6 @@ class RackspaceLBTests(unittest.TestCase
         self.assertEquals(balancers[2].name, "Third Loadbalancer")
         self.assertEquals(balancers[2].id, "8")
 
-
     def test_create_balancer(self):
         balancer = self.driver.create_balancer(name='test2',
                 port=80,
@@ -111,12 +130,106 @@ class RackspaceLBTests(unittest.TestCase
 
     def test_get_balancer_extra_public_source_ipv6(self):
         balancer = self.driver.get_balancer(balancer_id='18940')
-        self.assertEquals(balancer.extra["ipv6PublicSource"], 
'2001:4801:7901::6/64')
+        self.assertEquals(balancer.extra["ipv6PublicSource"],
+                          '2001:4801:7901::6/64')
 
     def test_get_balancer_extra_private_source_ipv4(self):
         balancer = self.driver.get_balancer(balancer_id='18940')
         self.assertEquals(balancer.extra["ipv4PrivateSource"], '10.183.252.25')
 
+    def test_get_balancer_algorithm(self):
+        balancer = self.driver.get_balancer(balancer_id='8290')
+        self.assertEquals(balancer.extra["algorithm"], Algorithm.RANDOM)
+
+    def test_get_balancer_weighted_round_robin_algorithm(self):
+        balancer = self.driver.get_balancer(balancer_id='94692')
+        self.assertEquals(balancer.extra["algorithm"],
+                           Algorithm.WEIGHTED_ROUND_ROBIN)
+
+    def test_get_balancer_weighted_least_connections_algorithm(self):
+        balancer = self.driver.get_balancer(balancer_id='94693')
+        self.assertEquals(balancer.extra["algorithm"],
+                           Algorithm.WEIGHTED_LEAST_CONNECTIONS)
+
+    def test_get_balancer_unknown_algorithm(self):
+        balancer = self.driver.get_balancer(balancer_id='94694')
+        self.assertFalse('algorithm' in balancer.extra)
+
+    def test_get_balancer_connect_health_monitor(self):
+        balancer = self.driver.get_balancer(balancer_id='94695')
+        balancer_health_monitor = balancer.extra["healthMonitor"]
+
+        self.assertEquals(balancer_health_monitor.type, "CONNECT")
+        self.assertEquals(balancer_health_monitor.delay, 10)
+        self.assertEquals(balancer_health_monitor.timeout, 5)
+        self.assertEquals(balancer_health_monitor.attempts_before_deactivation,
+                          2)
+
+    def test_get_balancer_http_health_monitor(self):
+        balancer = self.driver.get_balancer(balancer_id='94696')
+        balancer_health_monitor = balancer.extra["healthMonitor"]
+
+        self.assertEquals(balancer_health_monitor.type, "HTTP")
+        self.assertEquals(balancer_health_monitor.delay, 10)
+        self.assertEquals(balancer_health_monitor.timeout, 5)
+        self.assertEquals(balancer_health_monitor.attempts_before_deactivation,
+                          2)
+        self.assertEquals(balancer_health_monitor.path, "/")
+        self.assertEquals(balancer_health_monitor.status_regex,
+                           "^[234][0-9][0-9]$")
+        self.assertEquals(balancer_health_monitor.body_regex,
+                           "Hello World!")
+
+    def test_get_balancer_https_health_monitor(self):
+        balancer = self.driver.get_balancer(balancer_id='94697')
+        balancer_health_monitor = balancer.extra["healthMonitor"]
+
+        self.assertEquals(balancer_health_monitor.type, "HTTPS")
+        self.assertEquals(balancer_health_monitor.delay, 15)
+        self.assertEquals(balancer_health_monitor.timeout, 12)
+        self.assertEquals(balancer_health_monitor.attempts_before_deactivation,
+                          5)
+        self.assertEquals(balancer_health_monitor.path, "/test")
+        self.assertEquals(balancer_health_monitor.status_regex,
+                           "^[234][0-9][0-9]$")
+        self.assertEquals(balancer_health_monitor.body_regex, "abcdef")
+
+    def test_get_balancer_connection_throttle(self):
+        balancer = self.driver.get_balancer(balancer_id='94695')
+        balancer_connection_throttle = balancer.extra["connectionThrottle"]
+
+        self.assertEquals(balancer_connection_throttle.min_connections, 50)
+        self.assertEquals(balancer_connection_throttle.max_connections, 200)
+        self.assertEquals(balancer_connection_throttle.max_connection_rate, 50)
+        self.assertEquals(balancer_connection_throttle.rate_interval_seconds,
+                           10)
+
+    def test_get_session_persistence(self):
+        balancer = self.driver.get_balancer(balancer_id='94695')
+        self.assertEquals(balancer.extra["sessionPersistenceType"],
+                           "HTTP_COOKIE")
+
+    def test_get_connection_logging(self):
+        balancer = self.driver.get_balancer(balancer_id='94695')
+        self.assertEquals(balancer.extra["connectionLoggingEnabled"], True)
+
+    def test_get_error_page(self):
+        balancer = self.driver.get_balancer(balancer_id='18940')
+        error_page = self.driver.ex_get_balancer_error_page(balancer)
+        self.assertTrue("The service is temporarily unavailable" in error_page)
+
+    def test_get_access_list(self):
+        balancer = self.driver.get_balancer(balancer_id='18940')
+        deny_rule, allow_rule = self.driver.ex_balancer_access_list(balancer)
+
+        self.assertEquals(deny_rule.id, 2883)
+        self.assertEquals(deny_rule.rule_type, RackspaceAccessRuleType.DENY)
+        self.assertEquals(deny_rule.address, "0.0.0.0/0")
+
+        self.assertEquals(allow_rule.id, 2884)
+        self.assertEquals(allow_rule.address, "2001:4801:7901::6/64")
+        self.assertEquals(allow_rule.rule_type, RackspaceAccessRuleType.ALLOW)
+
     def test_balancer_list_members(self):
         balancer = self.driver.get_balancer(balancer_id='8290')
         members = balancer.list_members()
@@ -166,6 +279,14 @@ class RackspaceLBMockHttp(MockHttpTestCa
         return (httplib.ACCEPTED, body, {},
                 httplib.responses[httplib.ACCEPTED])
 
+    def _v1_0_slug_loadbalancers_algorithms(self, method, url, body, headers):
+        if method == "GET":
+            body = self.fixtures.load('v1_slug_loadbalancers_algorithms.json')
+            return (httplib.ACCEPTED, body, {},
+                    httplib.responses[httplib.ACCEPTED])
+
+        raise NotImplementedError
+
     def _v1_0_slug_loadbalancers(self, method, url, body, headers):
         if method == "GET":
             body = self.fixtures.load('v1_slug_loadbalancers.json')
@@ -185,7 +306,6 @@ class RackspaceLBMockHttp(MockHttpTestCa
         body = self.fixtures.load('v1_slug_loadbalancers_nodeaddress.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
-
     def _v1_0_slug_loadbalancers_8155(self, method, url, body, headers):
         if method == "DELETE":
             return (httplib.ACCEPTED, "", {}, 
httplib.responses[httplib.ACCEPTED])
@@ -227,6 +347,19 @@ class RackspaceLBMockHttp(MockHttpTestCa
 
         raise NotImplementedError
 
+    def _v1_0_slug_loadbalancers_18940_errorpage(self, method, url, body, 
headers):
+        if method == "GET":
+            body = 
self.fixtures.load("v1_slug_loadbalancers_18940_errorpage.json")
+            return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+        raise NotImplementedError
+
+    def _v1_0_slug_loadbalancers_18940_accesslist(self, method, url, body, 
headers):
+        if method == "GET":
+            body = 
self.fixtures.load("v1_slug_loadbalancers_18940_accesslist.json")
+            return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+        raise NotImplementedError
 
     def _v1_0_slug_loadbalancers_18941(self, method, url, body, headers):
         if method == "GET":
@@ -235,8 +368,50 @@ class RackspaceLBMockHttp(MockHttpTestCa
 
         raise NotImplementedError
 
+    def _v1_0_slug_loadbalancers_94692(self, method, url, body, headers):
+        if method == "GET":
+            body = 
self.fixtures.load("v1_slug_loadbalancers_94692_weighted_round_robin.json")
+            return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+        raise NotImplementedError
+
+    def _v1_0_slug_loadbalancers_94693(self, method, url, body, headers):
+        if method == "GET":
+            body = 
self.fixtures.load("v1_slug_loadbalancers_94693_weighted_least_connections.json")
+            return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+        raise NotImplementedError
+
+    def _v1_0_slug_loadbalancers_94694(self, method, url, body, headers):
+        if method == "GET":
+            body = 
self.fixtures.load("v1_slug_loadbalancers_94694_unknown_algorithm.json")
+            return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+        raise NotImplementedError
+
+    def _v1_0_slug_loadbalancers_94695(self, method, url, body, headers):
+        if method == "GET":
+            body = 
self.fixtures.load("v1_slug_loadbalancers_94695_full_details.json")
+            return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+        raise NotImplementedError
+
+    def _v1_0_slug_loadbalancers_94696(self, method, url, body, headers):
+        if method == "GET":
+            body = 
self.fixtures.load("v1_slug_loadbalancers_94696_http_health_monitor.json")
+            return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+        raise NotImplementedError
+
+    def _v1_0_slug_loadbalancers_94697(self, method, url, body, headers):
+        if method == "GET":
+            body = 
self.fixtures.load("v1_slug_loadbalancers_94697_https_health_monitor.json")
+            return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+        raise NotImplementedError
+
     def _v1_1_auth(self, method, url, body, headers):
-        headers = { 'content-type': 'application/json; charset=UTF-8'}
+        headers = { 'content-type': 'application/json; charset=UTF-8' }
         body = self.auth_fixtures.load('_v1_1__auth.json')
         return (httplib.OK, body, headers, httplib.responses[httplib.OK])
 


Reply via email to