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])