mirror of
https://github.com/ansible/awx.git
synced 2026-03-15 07:57:29 -02:30
1657 lines
58 KiB
Python
1657 lines
58 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2012 Rackspace
|
|
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from functools import wraps
|
|
|
|
import six
|
|
|
|
import pyrax
|
|
from pyrax.client import BaseClient
|
|
import pyrax.exceptions as exc
|
|
from pyrax.manager import BaseManager
|
|
from pyrax.resource import BaseResource
|
|
import pyrax.utils as utils
|
|
|
|
|
|
def assure_parent(fnc):
|
|
@wraps(fnc)
|
|
def wrapped(self, *args, **kwargs):
|
|
lb = self.parent
|
|
if not lb:
|
|
exc_class = {Node: exc.UnattachedNode,
|
|
VirtualIP: exc.UnattachedVirtualIP}[self.__class__]
|
|
raise exc_class("No parent Load Balancer for this node could "
|
|
"be determined.")
|
|
return fnc(self, *args, **kwargs)
|
|
return wrapped
|
|
|
|
|
|
def assure_loadbalancer(fnc):
|
|
@wraps(fnc)
|
|
def _wrapped(self, loadbalancer, *args, **kwargs):
|
|
if not isinstance(loadbalancer, CloudLoadBalancer):
|
|
# Must be the ID
|
|
loadbalancer = self._manager.get(loadbalancer)
|
|
return fnc(self, loadbalancer, *args, **kwargs)
|
|
return _wrapped
|
|
|
|
|
|
|
|
class CloudLoadBalancer(BaseResource):
|
|
"""Represents a Cloud Load Balancer instance."""
|
|
def __init__(self, *args, **kwargs):
|
|
self._connection_logging = None
|
|
self._content_caching = None
|
|
self._session_persistence = None
|
|
self._non_display = ["nodes", "virtual_ips"]
|
|
super(CloudLoadBalancer, self).__init__(*args, **kwargs)
|
|
|
|
|
|
def add_nodes(self, nodes):
|
|
"""Adds the nodes to this load balancer."""
|
|
return self.manager.add_nodes(self, nodes)
|
|
|
|
|
|
def add_virtualip(self, vip):
|
|
"""Adds the virtual IP to this load balancer."""
|
|
return self.manager.add_virtualip(self, vip)
|
|
|
|
|
|
def get_usage(self, start=None, end=None):
|
|
"""
|
|
Return the usage records for this load balancer. You may optionally
|
|
include a start datetime or an end datetime, or both, which will limit
|
|
the records to those on or after the start time, and those before or on
|
|
the end time. These times should be Python datetime.datetime objects,
|
|
Python datetime.date objects, or strings in the format:
|
|
"YYYY-MM-DD HH:MM:SS" or "YYYY-MM-DD".
|
|
"""
|
|
return self.manager.get_usage(self, start=start, end=end)
|
|
|
|
|
|
def _add_details(self, info):
|
|
"""Override the base behavior to add Nodes, VirtualIPs, etc."""
|
|
for (key, val) in info.iteritems():
|
|
if key == "nodes":
|
|
val = [Node(parent=self, **nd) for nd in val]
|
|
elif key == "sessionPersistence":
|
|
val = val['persistenceType']
|
|
elif key == "cluster":
|
|
val = val['name']
|
|
elif key == "virtualIps":
|
|
key = "virtual_ips"
|
|
val = [VirtualIP(parent=self, **vip) for vip in val]
|
|
setattr(self, key, val)
|
|
|
|
|
|
def update(self, name=None, algorithm=None, protocol=None, halfClosed=None,
|
|
port=None, timeout=None, httpsRedirect=None):
|
|
"""
|
|
Provides a way to modify the following attributes of a load balancer:
|
|
- name
|
|
- algorithm
|
|
- protocol
|
|
- halfClosed
|
|
- port
|
|
- timeout
|
|
- httpsRedirect
|
|
"""
|
|
return self.manager.update(self, name=name, algorithm=algorithm,
|
|
protocol=protocol, halfClosed=halfClosed, port=port,
|
|
timeout=timeout, httpsRedirect=httpsRedirect)
|
|
|
|
|
|
def delete_node(self, node):
|
|
"""Removes the node from the load balancer."""
|
|
return self.manager.delete_node(self, node)
|
|
|
|
|
|
def update_node(self, node, diff=None):
|
|
"""Updates the node's attributes."""
|
|
return self.manager.update_node(node, diff=diff)
|
|
|
|
|
|
def delete_virtualip(self, vip):
|
|
"""Deletes the VirtualIP from its load balancer."""
|
|
return self.manager.delete_virtualip(self, vip)
|
|
|
|
|
|
def get_access_list(self):
|
|
"""
|
|
Returns the current access list for the load balancer.
|
|
"""
|
|
return self.manager.get_access_list(self)
|
|
|
|
|
|
def add_access_list(self, access_list):
|
|
"""
|
|
Adds the access list provided to the load balancer.
|
|
|
|
The 'access_list' should be a dict in the following format:
|
|
|
|
{"accessList": [
|
|
{"address": "192.0.43.10", "type": "DENY"},
|
|
{"address": "192.0.43.11", "type": "ALLOW"},
|
|
...
|
|
{"address": "192.0.43.99", "type": "DENY"},
|
|
]
|
|
}
|
|
|
|
If no access list exists, it is created. If an access list
|
|
already exists, it is updated with the provided list.
|
|
"""
|
|
return self.manager.add_access_list(self, access_list)
|
|
|
|
|
|
def delete_access_list(self):
|
|
"""
|
|
Removes the access list from this load balancer.
|
|
"""
|
|
return self.manager.delete_access_list(self)
|
|
|
|
|
|
def delete_access_list_items(self, item_ids):
|
|
"""
|
|
Removes the item(s) from the load balancer's access list
|
|
that match the provided IDs. 'item_ids' should be one or
|
|
more access list item IDs.
|
|
"""
|
|
return self.manager.delete_access_list_items(self, item_ids)
|
|
|
|
|
|
def get_health_monitor(self):
|
|
"""
|
|
Returns a dict representing the health monitor for the load
|
|
balancer. If no monitor has been configured, returns an
|
|
empty dict.
|
|
"""
|
|
return self.manager.get_health_monitor(self)
|
|
|
|
|
|
def add_health_monitor(self, type, delay=10, timeout=10,
|
|
attemptsBeforeDeactivation=3, path="/", statusRegex=None,
|
|
bodyRegex=None, hostHeader=None):
|
|
"""
|
|
Adds a health monitor to the load balancer. If a monitor already
|
|
exists, it is updated with the supplied settings.
|
|
"""
|
|
abd = attemptsBeforeDeactivation
|
|
return self.manager.add_health_monitor(self, type=type, delay=delay,
|
|
timeout=timeout, attemptsBeforeDeactivation=abd,
|
|
path=path, statusRegex=statusRegex, bodyRegex=bodyRegex,
|
|
hostHeader=hostHeader)
|
|
|
|
|
|
def delete_health_monitor(self):
|
|
"""
|
|
Deletes the health monitor for the load balancer.
|
|
"""
|
|
return self.manager.delete_health_monitor(self)
|
|
|
|
|
|
def get_connection_throttle(self):
|
|
"""
|
|
Returns a dict representing the connection throttling information
|
|
for the load balancer. If no connection throttle has been configured,
|
|
returns an empty dict.
|
|
"""
|
|
return self.manager.get_connection_throttle(self)
|
|
|
|
|
|
def add_connection_throttle(self, maxConnectionRate=None,
|
|
maxConnections=None, minConnections=None, rateInterval=None):
|
|
"""
|
|
Updates the connection throttling information for the load balancer with
|
|
the supplied values. At least one of the parameters must be supplied.
|
|
"""
|
|
if not any((maxConnectionRate, maxConnections, minConnections,
|
|
rateInterval)):
|
|
# Pointless call
|
|
return
|
|
return self.manager.add_connection_throttle(self,
|
|
maxConnectionRate=maxConnectionRate, maxConnections=maxConnections,
|
|
minConnections=minConnections, rateInterval=rateInterval)
|
|
|
|
|
|
def delete_connection_throttle(self):
|
|
"""
|
|
Deletes all connection throttling settings for the load balancer.
|
|
"""
|
|
return self.manager.delete_connection_throttle(self)
|
|
|
|
|
|
def get_ssl_termination(self):
|
|
"""
|
|
Returns a dict representing the SSL termination configuration
|
|
for the load balancer. If SSL termination has not been configured,
|
|
returns an empty dict.
|
|
"""
|
|
return self.manager.get_ssl_termination(self)
|
|
|
|
|
|
def add_ssl_termination(self, securePort, privatekey, certificate,
|
|
intermediateCertificate=None, enabled=True,
|
|
secureTrafficOnly=False):
|
|
"""
|
|
Adds SSL termination information to the load balancer. If SSL
|
|
termination has already been configured, it is updated with the
|
|
supplied settings.
|
|
"""
|
|
return self.manager.add_ssl_termination(self, securePort=securePort,
|
|
privatekey=privatekey, certificate=certificate,
|
|
intermediateCertificate=intermediateCertificate,
|
|
enabled=enabled, secureTrafficOnly=secureTrafficOnly)
|
|
|
|
|
|
def update_ssl_termination(self, securePort=None, enabled=None,
|
|
secureTrafficOnly=None):
|
|
"""
|
|
Updates existing SSL termination information for the load balancer
|
|
without affecting the existing certificates/keys.
|
|
"""
|
|
return self.manager.update_ssl_termination(self, securePort=securePort,
|
|
enabled=enabled, secureTrafficOnly=secureTrafficOnly)
|
|
|
|
|
|
def delete_ssl_termination(self):
|
|
"""
|
|
Removes SSL termination for the load balancer.
|
|
"""
|
|
return self.manager.delete_ssl_termination(self)
|
|
|
|
|
|
def get_metadata(self):
|
|
"""
|
|
Returns the current metadata for the load balancer.
|
|
"""
|
|
return self.manager.get_metadata(self)
|
|
|
|
|
|
def set_metadata(self, metadata):
|
|
"""
|
|
Sets the metadata for the load balancer to the supplied dictionary
|
|
of values. Any existing metadata is cleared.
|
|
"""
|
|
return self.manager.set_metadata(self, metadata)
|
|
|
|
|
|
def update_metadata(self, metadata):
|
|
"""
|
|
Updates the existing metadata for the load balancer with
|
|
the supplied dictionary.
|
|
"""
|
|
return self.manager.update_metadata(self, metadata)
|
|
|
|
|
|
def delete_metadata(self, keys=None):
|
|
"""
|
|
Deletes metadata items specified by the 'keys' parameter for
|
|
this load balancer. If no value for 'keys' is provided, all
|
|
metadata is deleted.
|
|
"""
|
|
return self.manager.delete_metadata(self, keys=keys)
|
|
|
|
|
|
def get_metadata_for_node(self, node):
|
|
"""
|
|
Returns the current metadata for the specified node.
|
|
"""
|
|
return self.manager.get_metadata(self, node=node)
|
|
|
|
|
|
def set_metadata_for_node(self, node, metadata):
|
|
"""
|
|
Sets the metadata for the specified node to the supplied dictionary
|
|
of values. Any existing metadata is cleared.
|
|
"""
|
|
return self.manager.set_metadata(self, metadata, node=node)
|
|
|
|
|
|
def update_metadata_for_node(self, node, metadata):
|
|
"""
|
|
Updates the existing metadata for the specified node with
|
|
the supplied dictionary.
|
|
"""
|
|
return self.manager.update_metadata(self, metadata, node=node)
|
|
|
|
|
|
def delete_metadata_for_node(self, node, keys=None):
|
|
"""
|
|
Deletes metadata items specified by the 'keys' parameter for
|
|
the specified node. If no value for 'keys' is provided, all
|
|
metadata is deleted.
|
|
"""
|
|
return self.manager.delete_metadata(self, keys=keys, node=node)
|
|
|
|
|
|
def get_error_page(self):
|
|
"""
|
|
Returns the current error page for the load balancer.
|
|
|
|
Load balancers all have a default error page that is shown to
|
|
an end user who is attempting to access a load balancer node
|
|
that is offline/unavailable.
|
|
"""
|
|
return self.manager.get_error_page(self)
|
|
|
|
|
|
def set_error_page(self, html):
|
|
"""
|
|
Sets a custom error page for the load balancer.
|
|
|
|
A single custom error page may be added per account load balancer
|
|
with an HTTP protocol. Page updates will override existing content.
|
|
If a custom error page is deleted, or the load balancer is changed
|
|
to a non-HTTP protocol, the default error page will be restored.
|
|
"""
|
|
return self.manager.set_error_page(self, html)
|
|
|
|
|
|
def clear_error_page(self):
|
|
"""
|
|
Resets the error page to the default.
|
|
"""
|
|
return self.manager.clear_error_page(self)
|
|
|
|
|
|
# BEGIN - property definitions ##
|
|
def _get_connection_logging(self):
|
|
if self._connection_logging is None:
|
|
self._connection_logging = self.manager.get_connection_logging(self)
|
|
return self._connection_logging
|
|
|
|
def _set_connection_logging(self, val):
|
|
self.manager.set_connection_logging(self, val)
|
|
self._connection_logging = val
|
|
|
|
|
|
def _get_content_caching(self):
|
|
if self._content_caching is None:
|
|
self._content_caching = self.manager.get_content_caching(self)
|
|
return self._content_caching
|
|
|
|
def _set_content_caching(self, val):
|
|
self.manager.set_content_caching(self, val)
|
|
self._content_caching = val
|
|
|
|
|
|
def _get_session_persistence(self):
|
|
if self._session_persistence is None:
|
|
self._session_persistence = self.manager.get_session_persistence(self)
|
|
return self._session_persistence
|
|
|
|
def _set_session_persistence(self, val):
|
|
if val:
|
|
if not isinstance(val, six.string_types) or (val.upper() not in
|
|
("HTTP_COOKIE", "SOURCE_IP")):
|
|
raise exc.InvalidSessionPersistenceType("Session Persistence "
|
|
"must be one of 'HTTP_COOKIE' or 'SOURCE_IP'. '%s' is "
|
|
"not a valid setting." % val)
|
|
self.manager.set_session_persistence(self, val)
|
|
self._session_persistence = val.upper()
|
|
else:
|
|
self.manager.delete_session_persistence(self)
|
|
self._session_persistence = ""
|
|
|
|
|
|
connection_logging = property(_get_connection_logging,
|
|
_set_connection_logging, None, "The current state of connection "
|
|
"logging. Possible values are True or False.")
|
|
content_caching = property(_get_content_caching, _set_content_caching,
|
|
None, "The current state of content caching. Possible values are "
|
|
"True or False.")
|
|
session_persistence = property(_get_session_persistence,
|
|
_set_session_persistence, None, "The current state of session "
|
|
"persistence. Possible values are either 'HTTP_COOKIE' or "
|
|
"'SOURCE_IP', depending on the type of load balancing.")
|
|
# END - property definitions ##
|
|
|
|
|
|
|
|
class CloudLoadBalancerManager(BaseManager):
|
|
def update(self, lb, name=None, algorithm=None, protocol=None,
|
|
halfClosed=None, port=None, timeout=None, httpsRedirect=None):
|
|
"""
|
|
Provides a way to modify the following attributes of a load balancer:
|
|
- name
|
|
- algorithm
|
|
- protocol
|
|
- halfClosed
|
|
- port
|
|
- timeout
|
|
- httpsRedirect
|
|
"""
|
|
body = {}
|
|
if name is not None:
|
|
body["name"] = name
|
|
if algorithm is not None:
|
|
body["algorithm"] = algorithm
|
|
if protocol is not None:
|
|
body["protocol"] = protocol
|
|
if halfClosed is not None:
|
|
body["halfClosed"] = halfClosed
|
|
if port is not None:
|
|
body["port"] = port
|
|
if timeout is not None:
|
|
body["timeout"] = timeout
|
|
if httpsRedirect is not None:
|
|
body["httpsRedirect"] = httpsRedirect
|
|
if not body:
|
|
# Nothing passed
|
|
return
|
|
body = {"loadBalancer": body}
|
|
uri = "/loadbalancers/%s" % utils.get_id(lb)
|
|
try:
|
|
resp, resp_body = self.api.method_put(uri, body=body)
|
|
except exc.ClientException as e:
|
|
message = e.message
|
|
details = e.details
|
|
if message and details:
|
|
errmsg = "%s - %s" % (message, details)
|
|
else:
|
|
errmsg = message
|
|
raise exc.InvalidLoadBalancerParameters(errmsg)
|
|
return resp, resp_body
|
|
|
|
|
|
def _create_body(self, name, port=None, protocol=None, nodes=None,
|
|
virtual_ips=None, algorithm=None, halfClosed=None, accessList=None,
|
|
connectionLogging=None, connectionThrottle=None, healthMonitor=None,
|
|
metadata=None, timeout=None, sessionPersistence=None,
|
|
httpsRedirect=None):
|
|
"""
|
|
Used to create the dict required to create a load balancer instance.
|
|
"""
|
|
required = (virtual_ips, port, protocol)
|
|
if not all(required):
|
|
raise exc.MissingLoadBalancerParameters("Load Balancer creation "
|
|
"requires at least one virtual IP, a protocol, and a port.")
|
|
nodes = utils.coerce_string_to_list(nodes)
|
|
virtual_ips = utils.coerce_string_to_list(virtual_ips)
|
|
bad_conditions = [node.condition for node in nodes
|
|
if node.condition.upper() not in ("ENABLED", "DISABLED")]
|
|
if bad_conditions:
|
|
raise exc.InvalidNodeCondition("Nodes for new load balancer must be "
|
|
"created in either 'ENABLED' or 'DISABLED' condition; "
|
|
"received the following invalid conditions: %s" %
|
|
", ".join(set(bad_conditions)))
|
|
node_dicts = [nd.to_dict() for nd in nodes]
|
|
vip_dicts = [vip.to_dict() for vip in virtual_ips]
|
|
body = {"loadBalancer": {
|
|
"name": name,
|
|
"port": port,
|
|
"protocol": protocol,
|
|
"nodes": node_dicts,
|
|
"virtualIps": vip_dicts,
|
|
"algorithm": algorithm or "RANDOM",
|
|
"halfClosed": halfClosed,
|
|
"accessList": accessList,
|
|
"connectionLogging": connectionLogging,
|
|
"connectionThrottle": connectionThrottle,
|
|
"healthMonitor": healthMonitor,
|
|
"metadata": metadata,
|
|
"timeout": timeout,
|
|
"sessionPersistence": sessionPersistence,
|
|
"httpsRedirect": httpsRedirect,
|
|
}}
|
|
return body
|
|
|
|
|
|
def add_nodes(self, lb, nodes):
|
|
"""Adds the list of nodes to the specified load balancer."""
|
|
if not isinstance(nodes, (list, tuple)):
|
|
nodes = [nodes]
|
|
node_dicts = [nd.to_dict() for nd in nodes]
|
|
resp, body = self.api.method_post("/loadbalancers/%s/nodes" % lb.id,
|
|
body={"nodes": node_dicts})
|
|
return resp, body
|
|
|
|
|
|
def delete_node(self, loadbalancer, node):
|
|
"""Removes the node from its load balancer."""
|
|
lb = node.parent
|
|
if not lb:
|
|
raise exc.UnattachedNode("No parent Load Balancer for this node "
|
|
"could be determined.")
|
|
resp, body = self.api.method_delete("/loadbalancers/%s/nodes/%s" %
|
|
(lb.id, node.id))
|
|
return resp, body
|
|
|
|
|
|
def update_node(self, node, diff=None):
|
|
"""Updates the node's attributes."""
|
|
lb = node.parent
|
|
if not lb:
|
|
raise exc.UnattachedNode("No parent Load Balancer for this node "
|
|
"could be determined.")
|
|
if diff is None:
|
|
diff = node._diff()
|
|
req_body = {"node": diff}
|
|
resp, body = self.api.method_put("/loadbalancers/%s/nodes/%s" %
|
|
(lb.id, node.id), body=req_body)
|
|
return resp, body
|
|
|
|
|
|
def add_virtualip(self, lb, vip):
|
|
"""Adds the VirtualIP to the specified load balancer."""
|
|
resp, body = self.api.method_post("/loadbalancers/%s/virtualips" % lb.id,
|
|
body=vip.to_dict())
|
|
return resp, body
|
|
|
|
|
|
def delete_virtualip(self, loadbalancer, vip):
|
|
"""Deletes the VirtualIP from its load balancer."""
|
|
lb = vip.parent
|
|
if not lb:
|
|
raise exc.UnattachedVirtualIP("No parent Load Balancer for this "
|
|
"VirtualIP could be determined.")
|
|
resp, body = self.api.method_delete("/loadbalancers/%s/virtualips/%s" %
|
|
(lb.id, vip.id))
|
|
return resp, body
|
|
|
|
|
|
def get_access_list(self, loadbalancer):
|
|
"""
|
|
Returns the current access list for the load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/accesslist" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_get(uri)
|
|
return body.get("accessList")
|
|
|
|
|
|
def add_access_list(self, loadbalancer, access_list):
|
|
"""
|
|
Adds the access list provided to the load balancer.
|
|
|
|
The 'access_list' should be a list of dicts in the following format:
|
|
|
|
[{"address": "192.0.43.10", "type": "DENY"},
|
|
{"address": "192.0.43.11", "type": "ALLOW"},
|
|
...
|
|
{"address": "192.0.43.99", "type": "DENY"},
|
|
]
|
|
|
|
If no access list exists, it is created. If an access list
|
|
already exists, it is updated with the provided list.
|
|
"""
|
|
req_body = {"accessList": access_list}
|
|
uri = "/loadbalancers/%s/accesslist" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_post(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def delete_access_list(self, loadbalancer):
|
|
"""
|
|
Removes the access list from this load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/accesslist" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_delete(uri)
|
|
return body
|
|
|
|
|
|
def delete_access_list_items(self, loadbalancer, item_ids):
|
|
"""
|
|
Removes the item(s) from the load balancer's access list
|
|
that match the provided IDs. 'item_ids' should be one or
|
|
more access list item IDs.
|
|
"""
|
|
if not isinstance(item_ids, (list, tuple)):
|
|
item_ids = [item_ids]
|
|
valid_ids = [itm["id"] for itm in self.get_access_list(loadbalancer)]
|
|
bad_ids = [str(itm) for itm in item_ids if itm not in valid_ids]
|
|
if bad_ids:
|
|
raise exc.AccessListIDNotFound("The following ID(s) are not valid "
|
|
"Access List items: %s" % ", ".join(bad_ids))
|
|
items = "&".join(["id=%s" % item_id for item_id in item_ids])
|
|
uri = "/loadbalancers/%s/accesslist?%s" % (
|
|
utils.get_id(loadbalancer), items)
|
|
# TODO: add the item ids
|
|
resp, body = self.api.method_delete(uri)
|
|
return body
|
|
|
|
|
|
def get_health_monitor(self, loadbalancer):
|
|
"""
|
|
Returns a dict representing the health monitor for the load
|
|
balancer. If no monitor has been configured, returns an
|
|
empty dict.
|
|
"""
|
|
uri = "/loadbalancers/%s/healthmonitor" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_get(uri)
|
|
return body.get("healthMonitor", {})
|
|
|
|
|
|
def add_health_monitor(self, loadbalancer, type, delay=10, timeout=10,
|
|
attemptsBeforeDeactivation=3, path="/", statusRegex=None,
|
|
bodyRegex=None, hostHeader=None):
|
|
"""
|
|
Adds a health monitor to the load balancer. If a monitor already
|
|
exists, it is updated with the supplied settings.
|
|
"""
|
|
uri = "/loadbalancers/%s/healthmonitor" % utils.get_id(loadbalancer)
|
|
req_body = {"healthMonitor": {
|
|
"type": type,
|
|
"delay": delay,
|
|
"timeout": timeout,
|
|
"attemptsBeforeDeactivation": attemptsBeforeDeactivation,
|
|
}}
|
|
uptype = type.upper()
|
|
if uptype.startswith("HTTP"):
|
|
lb = self._get_lb(loadbalancer)
|
|
if uptype != lb.protocol:
|
|
raise exc.ProtocolMismatch("Cannot set the Health Monitor type "
|
|
"to '%s' when the Load Balancer's protocol is '%s'." %
|
|
(type, lb.protocol))
|
|
if not all((path, statusRegex, bodyRegex)):
|
|
raise exc.MissingHealthMonitorSettings("When creating an HTTP(S) "
|
|
"monitor, you must provide the 'path', 'statusRegex' and "
|
|
"'bodyRegex' parameters.")
|
|
body_hm = req_body["healthMonitor"]
|
|
body_hm["path"] = path
|
|
body_hm["statusRegex"] = statusRegex
|
|
body_hm["bodyRegex"] = bodyRegex
|
|
if hostHeader:
|
|
body_hm["hostHeader"] = hostHeader
|
|
resp, body = self.api.method_put(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def delete_health_monitor(self, loadbalancer):
|
|
"""
|
|
Deletes the health monitor for the load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/healthmonitor" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_delete(uri)
|
|
|
|
|
|
def get_connection_throttle(self, loadbalancer):
|
|
"""
|
|
Returns a dict representing the connection throttling information
|
|
for the load balancer. If no connection throttle has been configured,
|
|
returns an empty dict.
|
|
"""
|
|
uri = "/loadbalancers/%s/connectionthrottle" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_get(uri)
|
|
return body.get("connectionThrottle", {})
|
|
|
|
|
|
def add_connection_throttle(self, loadbalancer, maxConnectionRate=None,
|
|
maxConnections=None, minConnections=None, rateInterval=None):
|
|
"""
|
|
Creates or updates the connection throttling information for the load
|
|
balancer. When first creating the connection throttle, all 4 parameters
|
|
must be supplied. When updating an existing connection throttle, at
|
|
least one of the parameters must be supplied.
|
|
"""
|
|
settings = {}
|
|
if maxConnectionRate:
|
|
settings["maxConnectionRate"] = maxConnectionRate
|
|
if maxConnections:
|
|
settings["maxConnections"] = maxConnections
|
|
if minConnections:
|
|
settings["minConnections"] = minConnections
|
|
if rateInterval:
|
|
settings["rateInterval"] = rateInterval
|
|
req_body = {"connectionThrottle": settings}
|
|
uri = "/loadbalancers/%s/connectionthrottle" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_put(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def delete_connection_throttle(self, loadbalancer):
|
|
"""
|
|
Deletes all connection throttling settings for the load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/connectionthrottle" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_delete(uri)
|
|
|
|
|
|
def get_ssl_termination(self, loadbalancer):
|
|
"""
|
|
Returns a dict representing the SSL termination configuration
|
|
for the load balancer. If SSL termination has not been configured,
|
|
returns an empty dict.
|
|
"""
|
|
uri = "/loadbalancers/%s/ssltermination" % utils.get_id(loadbalancer)
|
|
try:
|
|
resp, body = self.api.method_get(uri)
|
|
except exc.NotFound:
|
|
# For some reason, instead of returning an empty dict like the
|
|
# other API GET calls, this raises a 404.
|
|
return {}
|
|
return body.get("sslTermination", {})
|
|
|
|
|
|
def add_ssl_termination(self, loadbalancer, securePort, privatekey, certificate,
|
|
intermediateCertificate, enabled=True, secureTrafficOnly=False):
|
|
"""
|
|
Adds SSL termination information to the load balancer. If SSL termination
|
|
has already been configured, it is updated with the supplied settings.
|
|
"""
|
|
uri = "/loadbalancers/%s/ssltermination" % utils.get_id(loadbalancer)
|
|
req_body = {"sslTermination": {
|
|
"certificate": certificate,
|
|
"enabled": enabled,
|
|
"secureTrafficOnly": secureTrafficOnly,
|
|
"privatekey": privatekey,
|
|
"intermediateCertificate": intermediateCertificate,
|
|
"securePort": securePort,
|
|
}}
|
|
resp, body = self.api.method_put(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def update_ssl_termination(self, loadbalancer, securePort=None, enabled=None,
|
|
secureTrafficOnly=None):
|
|
"""
|
|
Updates existing SSL termination information for the load balancer
|
|
without affecting the existing certificates/keys.
|
|
"""
|
|
ssl_info = self.get_ssl_termination(loadbalancer)
|
|
if not ssl_info:
|
|
raise exc.NoSSLTerminationConfiguration("You must configure SSL "
|
|
"termination on this load balancer before attempting "
|
|
"to update it.")
|
|
if securePort is None:
|
|
securePort = ssl_info["securePort"]
|
|
if enabled is None:
|
|
enabled = ssl_info["enabled"]
|
|
if secureTrafficOnly is None:
|
|
secureTrafficOnly = ssl_info["secureTrafficOnly"]
|
|
uri = "/loadbalancers/%s/ssltermination" % utils.get_id(loadbalancer)
|
|
req_body = {"sslTermination": {
|
|
"enabled": enabled,
|
|
"secureTrafficOnly": secureTrafficOnly,
|
|
"securePort": securePort,
|
|
}}
|
|
resp, body = self.api.method_put(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def delete_ssl_termination(self, loadbalancer):
|
|
"""
|
|
Deletes the SSL Termination configuration for the load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/ssltermination" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_delete(uri)
|
|
|
|
|
|
def get_metadata(self, loadbalancer, node=None, raw=False):
|
|
"""
|
|
Returns the current metadata for the load balancer. If 'node' is
|
|
provided, returns the current metadata for that node.
|
|
"""
|
|
if node:
|
|
uri = "/loadbalancers/%s/nodes/%s/metadata" % (
|
|
utils.get_id(loadbalancer), utils.get_id(node))
|
|
else:
|
|
uri = "/loadbalancers/%s/metadata" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_get(uri)
|
|
meta = body.get("metadata", [])
|
|
if raw:
|
|
return meta
|
|
ret = dict([(itm["key"], itm["value"]) for itm in meta])
|
|
return ret
|
|
|
|
|
|
def set_metadata(self, loadbalancer, metadata, node=None):
|
|
"""
|
|
Sets the metadata for the load balancer to the supplied dictionary
|
|
of values. Any existing metadata is cleared. If 'node' is provided,
|
|
the metadata for that node is set instead of for the load balancer.
|
|
"""
|
|
# Delete any existing metadata
|
|
self.delete_metadata(loadbalancer, node=node)
|
|
# Convert the metadata dict into the list format
|
|
metadata_list = [{"key": key, "value": val}
|
|
for key, val in metadata.items()]
|
|
if node:
|
|
uri = "/loadbalancers/%s/nodes/%s/metadata" % (
|
|
utils.get_id(loadbalancer), utils.get_id(node))
|
|
else:
|
|
uri = "/loadbalancers/%s/metadata" % utils.get_id(loadbalancer)
|
|
req_body = {"metadata": metadata_list}
|
|
resp, body = self.api.method_post(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def update_metadata(self, loadbalancer, metadata, node=None):
|
|
"""
|
|
Updates the existing metadata with the supplied dictionary. If
|
|
'node' is supplied, the metadata for that node is updated instead
|
|
of for the load balancer.
|
|
"""
|
|
# Get the existing metadata
|
|
md = self.get_metadata(loadbalancer, raw=True)
|
|
id_lookup = dict([(itm["key"], itm["id"]) for itm in md])
|
|
metadata_list = []
|
|
# Updates must be done individually
|
|
for key, val in metadata.items():
|
|
try:
|
|
meta_id = id_lookup[key]
|
|
if node:
|
|
uri = "/loadbalancers/%s/nodes/%s/metadata/%s" % (
|
|
utils.get_id(loadbalancer), utils.get_id(node),
|
|
meta_id)
|
|
else:
|
|
uri = "/loadbalancers/%s/metadata" % utils.get_id(loadbalancer)
|
|
req_body = {"meta": {"value": val}}
|
|
resp, body = self.api.method_put(uri, body=req_body)
|
|
except KeyError:
|
|
# Not an existing key; add to metadata_list
|
|
metadata_list.append({"key": key, "value": val})
|
|
if metadata_list:
|
|
# New items; POST them
|
|
if node:
|
|
uri = "/loadbalancers/%s/nodes/%s/metadata" % (
|
|
utils.get_id(loadbalancer), utils.get_id(node))
|
|
else:
|
|
uri = "/loadbalancers/%s/metadata" % utils.get_id(loadbalancer)
|
|
req_body = {"metadata": metadata_list}
|
|
resp, body = self.api.method_post(uri, body=req_body)
|
|
|
|
|
|
def delete_metadata(self, loadbalancer, keys=None, node=None):
|
|
"""
|
|
Deletes metadata items specified by the 'keys' parameter. If no value
|
|
for 'keys' is provided, all metadata is deleted. If 'node' is supplied,
|
|
the metadata for that node is deleted instead of the load balancer.
|
|
"""
|
|
if keys and not isinstance(keys, (list, tuple)):
|
|
keys = [keys]
|
|
md = self.get_metadata(loadbalancer, node=node, raw=True)
|
|
if keys:
|
|
md = [dct for dct in md if dct["key"] in keys]
|
|
if not md:
|
|
# Nothing to do; log it? Raise an error?
|
|
return
|
|
id_list = "&".join(["id=%s" % itm["id"] for itm in md])
|
|
if node:
|
|
uri = "/loadbalancers/%s/nodes/%s/metadata?%s" % (
|
|
utils.get_id(loadbalancer), utils.get_id(node), id_list)
|
|
else:
|
|
uri = "/loadbalancers/%s/metadata?%s" % (
|
|
utils.get_id(loadbalancer), id_list)
|
|
resp, body = self.api.method_delete(uri)
|
|
return body
|
|
|
|
|
|
def get_error_page(self, loadbalancer):
|
|
"""
|
|
Load Balancers all have a default error page that is shown to
|
|
an end user who is attempting to access a load balancer node
|
|
that is offline/unavailable.
|
|
"""
|
|
uri = "/loadbalancers/%s/errorpage" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_get(uri)
|
|
return body
|
|
|
|
|
|
def set_error_page(self, loadbalancer, html):
|
|
"""
|
|
A single custom error page may be added per account load balancer
|
|
with an HTTP protocol. Page updates will override existing content.
|
|
If a custom error page is deleted, or the load balancer is changed
|
|
to a non-HTTP protocol, the default error page will be restored.
|
|
"""
|
|
uri = "/loadbalancers/%s/errorpage" % utils.get_id(loadbalancer)
|
|
req_body = {"errorpage": {"content": html}}
|
|
resp, body = self.api.method_put(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def clear_error_page(self, loadbalancer):
|
|
"""
|
|
Resets the error page to the default.
|
|
"""
|
|
uri = "/loadbalancers/%s/errorpage" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_delete(uri)
|
|
return body
|
|
|
|
|
|
def get_usage(self, loadbalancer=None, start=None, end=None):
|
|
"""
|
|
Return the load balancer usage records for this account. If 'loadbalancer'
|
|
is None, records for all load balancers are returned. You may optionally
|
|
include a start datetime or an end datetime, or both, which will limit
|
|
the records to those on or after the start time, and those before or on the
|
|
end time. These times should be Python datetime.datetime objects, Python
|
|
datetime.date objects, or strings in the format: "YYYY-MM-DD HH:MM:SS" or
|
|
"YYYY-MM-DD".
|
|
"""
|
|
if start is end is None:
|
|
period = None
|
|
else:
|
|
parts = []
|
|
startStr = utils.iso_time_string(start)
|
|
if startStr:
|
|
parts.append("startTime=%s" % startStr)
|
|
endStr = utils.iso_time_string(end)
|
|
if endStr:
|
|
parts.append("endTime=%s" % endStr)
|
|
period = "&".join(parts).strip("&")
|
|
if loadbalancer is None:
|
|
uri = "/loadbalancers/usage"
|
|
else:
|
|
uri = "/loadbalancers/%s/usage" % utils.get_id(loadbalancer)
|
|
if period:
|
|
uri = "%s?%s" % (uri, period)
|
|
resp, body = self.api.method_get(uri)
|
|
return body
|
|
|
|
|
|
def get_stats(self, loadbalancer):
|
|
"""
|
|
Returns statistics for the given load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/stats" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_get(uri)
|
|
return body
|
|
|
|
|
|
def get_session_persistence(self, loadbalancer):
|
|
"""
|
|
Returns the session persistence setting for the given load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/sessionpersistence" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_get(uri)
|
|
ret = body["sessionPersistence"].get("persistenceType", "")
|
|
return ret
|
|
|
|
|
|
def set_session_persistence(self, loadbalancer, val):
|
|
"""
|
|
Sets the session persistence for the given load balancer.
|
|
"""
|
|
val = val.upper()
|
|
uri = "/loadbalancers/%s/sessionpersistence" % utils.get_id(loadbalancer)
|
|
req_body = {"sessionPersistence": {
|
|
"persistenceType": val,
|
|
}}
|
|
resp, body = self.api.method_put(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def delete_session_persistence(self, loadbalancer):
|
|
"""
|
|
Removes the session persistence setting for the given load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/sessionpersistence" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_delete(uri)
|
|
return body
|
|
|
|
|
|
def get_connection_logging(self, loadbalancer):
|
|
"""
|
|
Returns the connection logging setting for the given load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/connectionlogging" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_get(uri)
|
|
ret = body.get("connectionLogging", {}).get("enabled", False)
|
|
return ret
|
|
|
|
|
|
def set_connection_logging(self, loadbalancer, val):
|
|
"""
|
|
Sets the connection logging for the given load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/connectionlogging" % utils.get_id(loadbalancer)
|
|
val = str(val).lower()
|
|
req_body = {"connectionLogging": {
|
|
"enabled": val,
|
|
}}
|
|
resp, body = self.api.method_put(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def get_content_caching(self, loadbalancer):
|
|
"""
|
|
Returns the content caching setting for the given load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/contentcaching" % utils.get_id(loadbalancer)
|
|
resp, body = self.api.method_get(uri)
|
|
ret = body.get("contentCaching", {}).get("enabled", False)
|
|
return ret
|
|
|
|
|
|
def set_content_caching(self, loadbalancer, val):
|
|
"""
|
|
Sets the content caching for the given load balancer.
|
|
"""
|
|
uri = "/loadbalancers/%s/contentcaching" % utils.get_id(loadbalancer)
|
|
val = str(val).lower()
|
|
req_body = {"contentCaching": {
|
|
"enabled": val,
|
|
}}
|
|
resp, body = self.api.method_put(uri, body=req_body)
|
|
return body
|
|
|
|
|
|
def _get_lb(self, lb_or_id):
|
|
"""
|
|
Accepts either a loadbalancer or the ID of a loadbalancer, and returns
|
|
the CloudLoadBalancer instance.
|
|
"""
|
|
if isinstance(lb_or_id, CloudLoadBalancer):
|
|
ret = lb_or_id
|
|
else:
|
|
ret = self.get(lb_or_id)
|
|
return ret
|
|
|
|
|
|
|
|
class Node(object):
|
|
"""Represents a Node for a Load Balancer."""
|
|
def __init__(self, address=None, port=None, condition=None, weight=None,
|
|
status=None, parent=None, type=None, id=None):
|
|
if condition is None:
|
|
condition = "ENABLED"
|
|
if not all((address, port)):
|
|
raise exc.InvalidNodeParameters("You must include an address and a "
|
|
"port when creating a node.")
|
|
self.address = address
|
|
self.port = port
|
|
self.condition = condition
|
|
if weight is None:
|
|
weight = 1
|
|
self.weight = weight
|
|
self.status = status
|
|
self.parent = parent
|
|
self.type = type
|
|
self.id = id
|
|
self._original_state = self.to_dict()
|
|
|
|
|
|
def __repr__(self):
|
|
tmp = "<Node type=%s, condition=%s, id=%s, address=%s, port=%s weight=%s>"
|
|
return tmp % (self.type, self.condition, self.id, self.address, self.port,
|
|
self.weight)
|
|
|
|
def __eq__(self, other):
|
|
return (isinstance(other, self.__class__)
|
|
and self.__dict__ == other.__dict__)
|
|
|
|
def __ne__(self, other):
|
|
return not self.__eq__(other)
|
|
|
|
def to_dict(self):
|
|
"""Convert this Node to a dict representation for passing to the API."""
|
|
return {"address": self.address,
|
|
"port": self.port,
|
|
"condition": self.condition,
|
|
"type": self.type,
|
|
"id": self.id,
|
|
}
|
|
|
|
|
|
def get_metadata(self):
|
|
"""
|
|
Returns the current metadata for the node.
|
|
"""
|
|
return self.manager.get_metadata(self, node=self)
|
|
|
|
|
|
def set_metadata(self, metadata):
|
|
"""
|
|
Sets the metadata for the node to the supplied dictionary
|
|
of values. Any existing metadata is cleared.
|
|
"""
|
|
return self.manager.set_metadata(self, metadata, node=self)
|
|
|
|
|
|
def update_metadata(self, metadata):
|
|
"""
|
|
Updates the existing metadata for the node with
|
|
the supplied dictionary.
|
|
"""
|
|
return self.manager.update_metadata(self, metadata, node=self)
|
|
|
|
|
|
def delete_metadata(self, keys=None):
|
|
"""
|
|
Deletes metadata items specified by the 'keys' parameter for
|
|
this node. If no value for 'keys' is provided, all
|
|
metadata is deleted.
|
|
"""
|
|
return self.manager.delete_metadata(self, keys=keys, node=self)
|
|
|
|
|
|
@assure_parent
|
|
def delete(self):
|
|
"""Removes this Node from its Load Balancer."""
|
|
self.parent.delete_node(self)
|
|
|
|
|
|
def _diff(self):
|
|
diff_dict = {}
|
|
for att, val in self._original_state.items():
|
|
curr = getattr(self, att)
|
|
if curr != val:
|
|
diff_dict[att] = curr
|
|
return diff_dict
|
|
|
|
|
|
@assure_parent
|
|
def update(self):
|
|
"""
|
|
Pushes any local changes to the object up to the actual load
|
|
balancer node.
|
|
"""
|
|
diff = self._diff()
|
|
if not diff:
|
|
# Nothing to do!
|
|
return
|
|
self.parent.update_node(self, diff)
|
|
|
|
|
|
def get_device(self):
|
|
"""
|
|
Returns a reference to the device that is represented by this node.
|
|
Returns None if no such device can be determined.
|
|
"""
|
|
addr = self.address
|
|
servers = [server for server in pyrax.cloudservers.list()
|
|
if addr in server.networks.get("private", "")]
|
|
try:
|
|
return servers[0]
|
|
except IndexError:
|
|
return None
|
|
|
|
|
|
|
|
class VirtualIP(object):
|
|
"""Represents a Virtual IP for a Load Balancer."""
|
|
def __init__(self, type=None, address=None, ipVersion=None, id=None,
|
|
parent=None):
|
|
if type is None:
|
|
type = "PUBLIC"
|
|
if type.upper() not in ("PUBLIC", "SERVICENET"):
|
|
raise exc.InvalidVirtualIPType("Virtual IPs must be one of "
|
|
"'PUBLIC' or 'SERVICENET' type; '%s' is not valid." % type)
|
|
if not ipVersion:
|
|
ipVersion = "IPV4"
|
|
if not ipVersion.upper() in ("IPV4", "IPV6"):
|
|
raise exc.InvalidVirtualIPVersion("Virtual IP versions must be one "
|
|
"of 'IPV4' or 'IPV6'; '%s' is not valid." % ipVersion)
|
|
self.type = type
|
|
self.address = address
|
|
self.ip_version = ipVersion
|
|
self.id = id
|
|
self.parent = parent
|
|
|
|
|
|
def __repr__(self):
|
|
return "<VirtualIP type=%s, id=%s, address=%s version=%s>" % (
|
|
self.type, self.id, self.address, self.ip_version)
|
|
|
|
|
|
def to_dict(self):
|
|
"""
|
|
Convert this VirtualIP to a dict representation for passing
|
|
to the API.
|
|
"""
|
|
if self.id:
|
|
return {"id": self.id}
|
|
return {"type": self.type, "ipVersion": self.ip_version}
|
|
|
|
|
|
@assure_parent
|
|
def delete(self):
|
|
self.parent.delete_virtualip(self)
|
|
|
|
|
|
|
|
class CloudLoadBalancerClient(BaseClient):
|
|
"""
|
|
This is the primary class for interacting with Cloud Load Balancers.
|
|
"""
|
|
name = "Cloud Load Balancers"
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
# Bring these two classes into the Client namespace
|
|
self.Node = Node
|
|
self.VirtualIP = VirtualIP
|
|
self._algorithms = None
|
|
self._protocols = None
|
|
self._allowed_domains = None
|
|
super(CloudLoadBalancerClient, self).__init__(*args, **kwargs)
|
|
|
|
|
|
def _configure_manager(self):
|
|
"""
|
|
Creates a manager to handle the instances, and another
|
|
to handle flavors.
|
|
"""
|
|
self._manager = CloudLoadBalancerManager(self,
|
|
resource_class=CloudLoadBalancer,
|
|
response_key="loadBalancer", uri_base="loadbalancers")
|
|
|
|
|
|
def get_usage(self, loadbalancer=None, start=None, end=None):
|
|
"""
|
|
Return the load balancer usage records for this account. If 'loadbalancer'
|
|
is None, records for all load balancers are returned. You may optionally
|
|
include a start datetime or an end datetime, or both, which will limit
|
|
the records to those on or after the start time, and those before or on the
|
|
end time. These times should be Python datetime.datetime objects, Python
|
|
datetime.date objects, or strings in the format: "YYYY-MM-DD HH:MM:SS" or
|
|
"YYYY-MM-DD".
|
|
"""
|
|
return self._manager.get_usage(loadbalancer=loadbalancer, start=start,
|
|
end=end)
|
|
|
|
|
|
@property
|
|
def allowed_domains(self):
|
|
"""
|
|
This property lists the allowed domains for a load balancer.
|
|
|
|
The allowed domains are restrictions set for the allowed domain names
|
|
used for adding load balancer nodes. In order to submit a domain name
|
|
as an address for the load balancer node to add, the user must verify
|
|
that the domain is valid by using the List Allowed Domains call. Once
|
|
verified, simply supply the domain name in place of the node's address
|
|
in the add_nodes() call.
|
|
"""
|
|
if self._allowed_domains is None:
|
|
uri = "/loadbalancers/alloweddomains"
|
|
resp, body = self.method_get(uri)
|
|
dom_list = body["allowedDomains"]
|
|
self._allowed_domains = [itm["allowedDomain"]["name"]
|
|
for itm in dom_list]
|
|
return self._allowed_domains
|
|
|
|
|
|
@property
|
|
def algorithms(self):
|
|
"""
|
|
Returns a list of available load balancing algorithms.
|
|
"""
|
|
if self._algorithms is None:
|
|
uri = "/loadbalancers/algorithms"
|
|
resp, body = self.method_get(uri)
|
|
self._algorithms = [alg["name"] for alg in body["algorithms"]]
|
|
return self._algorithms
|
|
|
|
|
|
@property
|
|
def protocols(self):
|
|
"""
|
|
Returns a list of available load balancing protocols.
|
|
"""
|
|
if self._protocols is None:
|
|
uri = "/loadbalancers/protocols"
|
|
resp, body = self.method_get(uri)
|
|
self._protocols = [proto["name"] for proto in body["protocols"]]
|
|
return self._protocols
|
|
|
|
|
|
@assure_loadbalancer
|
|
def update(self, loadbalancer, name=None, algorithm=None, protocol=None,
|
|
halfClosed=None, port=None, timeout=None, httpsRedirect=None):
|
|
"""
|
|
Provides a way to modify the following attributes of a load balancer:
|
|
- name
|
|
- algorithm
|
|
- protocol
|
|
- halfClosed
|
|
- port
|
|
- timeout
|
|
- httpsRedirect
|
|
"""
|
|
return self._manager.update(loadbalancer, name=name,
|
|
algorithm=algorithm, protocol=protocol, halfClosed=halfClosed,
|
|
port=port, timeout=timeout, httpsRedirect=httpsRedirect)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def add_nodes(self, loadbalancer, nodes):
|
|
"""Adds the nodes to this load balancer."""
|
|
return loadbalancer.add_nodes(nodes)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def add_virtualip(self, loadbalancer, vip):
|
|
"""Adds the virtual IP to this load balancer."""
|
|
return loadbalancer.add_virtualip(vip)
|
|
|
|
|
|
def delete_node(self, node):
|
|
"""Removes the node from its load balancer."""
|
|
return node.delete()
|
|
|
|
|
|
def update_node(self, node):
|
|
"""Updates the node's attributes."""
|
|
return node.update()
|
|
|
|
|
|
def delete_virtualip(self, vip):
|
|
"""Deletes the VirtualIP from its load balancer."""
|
|
return vip.delete()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_access_list(self, loadbalancer):
|
|
"""
|
|
Returns the current access list for the load balancer.
|
|
"""
|
|
return loadbalancer.get_access_list()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def add_access_list(self, loadbalancer, access_list):
|
|
"""
|
|
Adds the access list provided to the load balancer.
|
|
|
|
The 'access_list' should be a dict in the following format:
|
|
|
|
{"accessList": [
|
|
{"address": "192.0.43.10", "type": "DENY"},
|
|
{"address": "192.0.43.11", "type": "ALLOW"},
|
|
...
|
|
{"address": "192.0.43.99", "type": "DENY"},
|
|
]
|
|
}
|
|
|
|
If no access list exists, it is created. If an access list
|
|
already exists, it is updated with the provided list.
|
|
"""
|
|
return loadbalancer.add_access_list(access_list)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def delete_access_list(self, loadbalancer):
|
|
"""
|
|
Removes the access list from this load balancer.
|
|
"""
|
|
return loadbalancer.delete_access_list()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def delete_access_list_items(self, loadbalancer, item_ids):
|
|
"""
|
|
Removes the item(s) from the load balancer's access list
|
|
that match the provided IDs. 'item_ids' should be one or
|
|
more access list item IDs.
|
|
"""
|
|
return loadbalancer.delete_access_list_items(item_ids)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_health_monitor(self, loadbalancer):
|
|
"""
|
|
Returns a dict representing the health monitor for the load
|
|
balancer. If no monitor has been configured, returns an
|
|
empty dict.
|
|
"""
|
|
return loadbalancer.get_health_monitor()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def add_health_monitor(self, loadbalancer, type, delay=10, timeout=10,
|
|
attemptsBeforeDeactivation=3, path="/", statusRegex=None,
|
|
bodyRegex=None, hostHeader=None):
|
|
"""
|
|
Adds a health monitor to the load balancer. If a monitor already
|
|
exists, it is updated with the supplied settings.
|
|
"""
|
|
abd = attemptsBeforeDeactivation
|
|
return loadbalancer.add_health_monitor(type=type, delay=delay,
|
|
timeout=timeout, attemptsBeforeDeactivation=abd, path=path,
|
|
statusRegex=statusRegex, bodyRegex=bodyRegex,
|
|
hostHeader=hostHeader)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def delete_health_monitor(self, loadbalancer):
|
|
"""
|
|
Deletes the health monitor for the load balancer.
|
|
"""
|
|
return loadbalancer.delete_health_monitor()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_connection_throttle(self, loadbalancer):
|
|
"""
|
|
Returns a dict representing the connection throttling information
|
|
for the load balancer. If no connection throttle has been configured,
|
|
returns an empty dict.
|
|
"""
|
|
return loadbalancer.get_connection_throttle()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def add_connection_throttle(self, loadbalancer, maxConnectionRate=None,
|
|
maxConnections=None, minConnections=None, rateInterval=None):
|
|
"""
|
|
Updates the connection throttling information for the load balancer with
|
|
the supplied values. At least one of the parameters must be supplied.
|
|
"""
|
|
return loadbalancer.add_connection_throttle(
|
|
maxConnectionRate=maxConnectionRate, maxConnections=maxConnections,
|
|
minConnections=minConnections, rateInterval=rateInterval)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def delete_connection_throttle(self, loadbalancer):
|
|
"""
|
|
Deletes all connection throttling settings for the load balancer.
|
|
"""
|
|
return loadbalancer.delete_connection_throttle()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_ssl_termination(self, loadbalancer):
|
|
"""
|
|
Returns a dict representing the SSL termination configuration
|
|
for the load balancer. If SSL termination has not been configured,
|
|
returns an empty dict.
|
|
"""
|
|
return loadbalancer.get_ssl_termination()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def add_ssl_termination(self, loadbalancer, securePort, privatekey,
|
|
certificate, intermediateCertificate, enabled=True,
|
|
secureTrafficOnly=False):
|
|
"""
|
|
Adds SSL termination information to the load balancer. If SSL termination
|
|
has already been configured, it is updated with the supplied settings.
|
|
"""
|
|
return loadbalancer.add_ssl_termination(securePort=securePort,
|
|
privatekey=privatekey, certificate=certificate,
|
|
intermediateCertificate=intermediateCertificate,
|
|
enabled=enabled, secureTrafficOnly=secureTrafficOnly)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def update_ssl_termination(self, loadbalancer, securePort=None, enabled=None,
|
|
secureTrafficOnly=None):
|
|
"""
|
|
Updates existing SSL termination information for the load balancer
|
|
without affecting the existing certificates/keys.
|
|
"""
|
|
return loadbalancer.update_ssl_termination(securePort=securePort,
|
|
enabled=enabled, secureTrafficOnly=secureTrafficOnly)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def delete_ssl_termination(self, loadbalancer):
|
|
"""
|
|
Removes SSL termination for the load balancer.
|
|
"""
|
|
return loadbalancer.delete_ssl_termination()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_metadata(self, loadbalancer):
|
|
"""
|
|
Returns the current metadata for the load balancer.
|
|
"""
|
|
return loadbalancer.get_metadata()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def set_metadata(self, loadbalancer, metadata):
|
|
"""
|
|
Sets the metadata for the load balancer to the supplied dictionary
|
|
of values. Any existing metadata is cleared.
|
|
"""
|
|
return loadbalancer.set_metadata(metadata)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def update_metadata(self, loadbalancer, metadata):
|
|
"""
|
|
Updates the existing metadata for the load balancer with
|
|
the supplied dictionary.
|
|
"""
|
|
return loadbalancer.update_metadata(metadata)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def delete_metadata(self, loadbalancer, keys=None):
|
|
"""
|
|
Deletes metadata items specified by the 'keys' parameter for
|
|
this load balancer. If no value for 'keys' is provided, all
|
|
metadata is deleted.
|
|
"""
|
|
return loadbalancer.delete_metadata(keys=keys)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_metadata_for_node(self, loadbalancer, node):
|
|
"""
|
|
Returns the current metadata for the specified node.
|
|
"""
|
|
return loadbalancer.get_metadata_for_node(node)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def set_metadata_for_node(self, loadbalancer, node, metadata):
|
|
"""
|
|
Sets the metadata for the specified node to the supplied dictionary
|
|
of values. Any existing metadata is cleared.
|
|
"""
|
|
return loadbalancer.set_metadata_for_node(node, metadata)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def update_metadata_for_node(self, loadbalancer, node, metadata):
|
|
"""
|
|
Updates the existing metadata for the specified node with
|
|
the supplied dictionary.
|
|
"""
|
|
return loadbalancer.update_metadata_for_node(node, metadata)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def delete_metadata_for_node(self, loadbalancer, node, keys=None):
|
|
"""
|
|
Deletes metadata items specified by the 'keys' parameter for
|
|
the specified node. If no value for 'keys' is provided, all
|
|
metadata is deleted.
|
|
"""
|
|
return loadbalancer.delete_metadata_for_node(node, keys=keys)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_error_page(self, loadbalancer):
|
|
"""
|
|
Load Balancers all have a default error page that is shown to
|
|
an end user who is attempting to access a load balancer node
|
|
that is offline/unavailable.
|
|
"""
|
|
return loadbalancer.get_error_page()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def set_error_page(self, loadbalancer, html):
|
|
"""
|
|
A single custom error page may be added per account load balancer
|
|
with an HTTP protocol. Page updates will override existing content.
|
|
If a custom error page is deleted, or the load balancer is changed
|
|
to a non-HTTP protocol, the default error page will be restored.
|
|
"""
|
|
return loadbalancer.set_error_page(html)
|
|
|
|
|
|
@assure_loadbalancer
|
|
def clear_error_page(self, loadbalancer):
|
|
"""
|
|
Resets the error page to the default.
|
|
"""
|
|
return loadbalancer.clear_error_page()
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_connection_logging(self, loadbalancer):
|
|
"""
|
|
Returns the current setting for connection logging for the load balancer.
|
|
"""
|
|
return loadbalancer.connection_logging
|
|
|
|
|
|
@assure_loadbalancer
|
|
def set_connection_logging(self, loadbalancer, val):
|
|
"""
|
|
Sets connection logging for the load balancer to either True
|
|
or False.
|
|
"""
|
|
loadbalancer.connection_logging = val
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_content_caching(self, loadbalancer):
|
|
"""
|
|
Returns the current setting for content caching for the load balancer.
|
|
"""
|
|
return loadbalancer.content_caching
|
|
|
|
|
|
@assure_loadbalancer
|
|
def set_content_caching(self, loadbalancer, val):
|
|
"""
|
|
Sets content caching for the load balancer to either True
|
|
or False.
|
|
"""
|
|
loadbalancer.content_caching = val
|
|
|
|
|
|
@assure_loadbalancer
|
|
def get_session_persistence(self, loadbalancer):
|
|
"""
|
|
Returns the current setting for session persistence for
|
|
the load balancer.
|
|
"""
|
|
return loadbalancer.session_persistence
|
|
|
|
|
|
@assure_loadbalancer
|
|
def set_session_persistence(self, loadbalancer, val):
|
|
"""
|
|
Sets the type of session persistence for the load balancer. This
|
|
must be one of either "HTTP_COOKIE" or "SOURCE_IP", depending
|
|
on the type of load balancing.
|
|
"""
|
|
loadbalancer.session_persistence = val
|
|
|
|
# END pass-through methods ##
|