Basic ELB support

This commit is contained in:
Steve Pulec 2013-07-22 22:50:58 -04:00
parent 421a5e60af
commit b40d3a5629
7 changed files with 392 additions and 0 deletions

View File

@ -3,6 +3,7 @@ logging.getLogger('boto').setLevel(logging.CRITICAL)
from .dynamodb import mock_dynamodb
from .ec2 import mock_ec2
from .elb import mock_elb
from .s3 import mock_s3
from .ses import mock_ses
from .sqs import mock_sqs

2
moto/elb/__init__.py Normal file
View File

@ -0,0 +1,2 @@
from .models import elb_backend
mock_elb = elb_backend.decorator

80
moto/elb/models.py Normal file
View File

@ -0,0 +1,80 @@
from moto.core import BaseBackend
class FakeHealthCheck(object):
def __init__(self, timeout, healthy_threshold, unhealthy_threshold,
interval, target):
self.timeout = timeout
self.healthy_threshold = healthy_threshold
self.unhealthy_threshold = unhealthy_threshold
self.interval = interval
self.target = target
class FakeListener(object):
def __init__(self, load_balancer_port, instance_port, protocol):
self.load_balancer_port = load_balancer_port
self.instance_port = instance_port
self.protocol = protocol.upper()
class FakeLoadBalancer(object):
def __init__(self, name, zones, ports):
self.name = name
self.health_check = None
self.instance_ids = []
self.zones = zones
self.listeners = []
for protocol, lb_port, instance_port in ports:
listener = FakeListener(
protocol=protocol,
load_balancer_port=lb_port,
instance_port=instance_port,
)
self.listeners.append(listener)
class ELBBackend(BaseBackend):
def __init__(self):
self.load_balancers = {}
def create_load_balancer(self, name, zones, ports):
new_load_balancer = FakeLoadBalancer(name=name, zones=zones, ports=ports)
self.load_balancers[name] = new_load_balancer
return new_load_balancer
def describe_load_balancers(self, names):
balancers = self.load_balancers.values()
if names:
return [balancer for balancer in balancers if balancer.name in names]
else:
return balancers
def delete_load_balancer(self, load_balancer_name):
self.load_balancers.pop(load_balancer_name, None)
def get_load_balancer(self, load_balancer_name):
return self.load_balancers.get(load_balancer_name)
def configure_health_check(self, load_balancer_name, timeout,
healthy_threshold, unhealthy_threshold, interval,
target):
check = FakeHealthCheck(timeout, healthy_threshold, unhealthy_threshold,
interval, target)
load_balancer = self.get_load_balancer(load_balancer_name)
load_balancer.health_check = check
return check
def register_instances(self, load_balancer_name, instance_ids):
load_balancer = self.get_load_balancer(load_balancer_name)
load_balancer.instance_ids.extend(instance_ids)
return load_balancer
def deregister_instances(self, load_balancer_name, instance_ids):
load_balancer = self.get_load_balancer(load_balancer_name)
new_instance_ids = [instance_id for instance_id in load_balancer.instance_ids if instance_id not in instance_ids]
load_balancer.instance_ids = new_instance_ids
return load_balancer
elb_backend = ELBBackend()

179
moto/elb/responses.py Normal file
View File

@ -0,0 +1,179 @@
from jinja2 import Template
from moto.core.responses import BaseResponse
from .models import elb_backend
class ELBResponse(BaseResponse):
def create_load_balancer(self):
"""
u'Scheme': [u'internet-facing'],
"""
load_balancer_name = self.querystring.get('LoadBalancerName')[0]
availability_zones = [value[0] for key, value in self.querystring.items() if "AvailabilityZones.member" in key]
ports = []
port_index = 1
while True:
try:
protocol = self.querystring['Listeners.member.{}.Protocol'.format(port_index)][0]
except KeyError:
break
lb_port = self.querystring['Listeners.member.{}.LoadBalancerPort'.format(port_index)][0]
instance_port = self.querystring['Listeners.member.{}.InstancePort'.format(port_index)][0]
ports.append([protocol, lb_port, instance_port])
port_index += 1
elb_backend.create_load_balancer(
name=load_balancer_name,
zones=availability_zones,
ports=ports,
)
template = Template(CREATE_LOAD_BALANCER_TEMPLATE)
return template.render()
def describe_load_balancers(self):
names = [value[0] for key, value in self.querystring.items() if "LoadBalancerNames.member" in key]
load_balancers = elb_backend.describe_load_balancers(names)
template = Template(DESCRIBE_LOAD_BALANCERS_TEMPLATE)
return template.render(load_balancers=load_balancers)
def delete_load_balancer(self):
load_balancer_name = self.querystring.get('LoadBalancerName')[0]
elb_backend.delete_load_balancer(load_balancer_name)
template = Template(DELETE_LOAD_BALANCER_TEMPLATE)
return template.render()
def configure_health_check(self):
check = elb_backend.configure_health_check(
load_balancer_name=self.querystring.get('LoadBalancerName')[0],
timeout=self.querystring.get('HealthCheck.Timeout')[0],
healthy_threshold=self.querystring.get('HealthCheck.HealthyThreshold')[0],
unhealthy_threshold=self.querystring.get('HealthCheck.UnhealthyThreshold')[0],
interval=self.querystring.get('HealthCheck.Interval')[0],
target=self.querystring.get('HealthCheck.Target')[0],
)
template = Template(CONFIGURE_HEALTH_CHECK_TEMPLATE)
return template.render(check=check)
def register_instances_with_load_balancer(self):
load_balancer_name = self.querystring.get('LoadBalancerName')[0]
instance_ids = [value[0] for key, value in self.querystring.items() if "Instances.member" in key]
template = Template(REGISTER_INSTANCES_TEMPLATE)
load_balancer = elb_backend.register_instances(load_balancer_name, instance_ids)
return template.render(load_balancer=load_balancer)
def deregister_instances_from_load_balancer(self):
load_balancer_name = self.querystring.get('LoadBalancerName')[0]
instance_ids = [value[0] for key, value in self.querystring.items() if "Instances.member" in key]
template = Template(DEREGISTER_INSTANCES_TEMPLATE)
load_balancer = elb_backend.deregister_instances(load_balancer_name, instance_ids)
return template.render(load_balancer=load_balancer)
CREATE_LOAD_BALANCER_TEMPLATE = """<CreateLoadBalancerResult xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<DNSName>tests.us-east-1.elb.amazonaws.com</DNSName>
</CreateLoadBalancerResult>"""
DELETE_LOAD_BALANCER_TEMPLATE = """<DeleteLoadBalancerResult xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
</DeleteLoadBalancerResult>"""
DESCRIBE_LOAD_BALANCERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<DescribeLoadBalancersResult>
<LoadBalancerDescriptions>
{% for load_balancer in load_balancers %}
<member>
<SecurityGroups>
</SecurityGroups>
<LoadBalancerName>{{ load_balancer.name }}</LoadBalancerName>
<CreatedTime>2013-01-01T00:00:00.19000Z</CreatedTime>
<HealthCheck>
{% if load_balancer.health_check %}
<Interval>{{ load_balancer.health_check.interval }}</Interval>
<Target>{{ load_balancer.health_check.target }}</Target>
<HealthyThreshold>{{ load_balancer.health_check.healthy_threshold }}</HealthyThreshold>
<Timeout>{{ load_balancer.health_check.timeout }}</Timeout>
<UnhealthyThreshold>{{ load_balancer.health_check.unhealthy_threshold }}</UnhealthyThreshold>
{% endif %}
</HealthCheck>
<VPCId>vpc-56e10e3d</VPCId>
<ListenerDescriptions>
{% for listener in load_balancer.listeners %}
<member>
<PolicyNames>
<member>AWSConsolePolicy-1</member>
</PolicyNames>
<Listener>
<Protocol>{{ listener.protocol }}</Protocol>
<LoadBalancerPort>{{ listener.load_balancer_port }}</LoadBalancerPort>
<InstanceProtocol>{{ listener.protocol }}</InstanceProtocol>
<InstancePort>{{ listener.instance_port }}</InstancePort>
</Listener>
</member>
{% endfor %}
</ListenerDescriptions>
<Instances>
{% for instance_id in load_balancer.instance_ids %}
<member>
<InstanceId>{{ instance_id }}</InstanceId>
</member>
{% endfor %}
</Instances>
<Policies>
<AppCookieStickinessPolicies/>
<OtherPolicies/>
<LBCookieStickinessPolicies>
<member>
<PolicyName>AWSConsolePolicy-1</PolicyName>
<CookieExpirationPeriod>30</CookieExpirationPeriod>
</member>
</LBCookieStickinessPolicies>
</Policies>
<AvailabilityZones>
{% for zone in load_balancer.zones %}
<member>{{ zone }}</member>
{% endfor %}
</AvailabilityZones>
<CanonicalHostedZoneName>tests.us-east-1.elb.amazonaws.com</CanonicalHostedZoneName>
<CanonicalHostedZoneNameID>Z3ZONEID</CanonicalHostedZoneNameID>
<Scheme>internet-facing</Scheme>
<DNSName>tests.us-east-1.elb.amazonaws.com</DNSName>
<BackendServerDescriptions/>
<Subnets>
</Subnets>
</member>
{% endfor %}
</LoadBalancerDescriptions>
</DescribeLoadBalancersResult>
<ResponseMetadata>
<RequestId>f9880f01-7852-629d-a6c3-3ae2-666a409287e6dc0c</RequestId>
</ResponseMetadata>
</DescribeLoadBalancersResponse>"""
CONFIGURE_HEALTH_CHECK_TEMPLATE = """<ConfigureHealthCheckResult xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<HealthCheck>
<Interval>{{ check.interval }}</Interval>
<Target>{{ check.target }}</Target>
<HealthyThreshold>{{ check.healthy_threshold }}</HealthyThreshold>
<Timeout>{{ check.timeout }}</Timeout>
<UnhealthyThreshold>{{ check.unhealthy_threshold }}</UnhealthyThreshold>
</HealthCheck>
</ConfigureHealthCheckResult>"""
REGISTER_INSTANCES_TEMPLATE = """<RegisterInstancesWithLoadBalancerResult xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<Instances>
{% for instance_id in load_balancer.instance_ids %}
<member>
<InstanceId>{{ instance_id }}</InstanceId>
</member>
{% endfor %}
</Instances>
</RegisterInstancesWithLoadBalancerResult>"""
DEREGISTER_INSTANCES_TEMPLATE = """<DeregisterInstancesWithLoadBalancerResult xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
<Instances>
{% for instance_id in load_balancer.instance_ids %}
<member>
<InstanceId>{{ instance_id }}</InstanceId>
</member>
{% endfor %}
</Instances>
</DeregisterInstancesWithLoadBalancerResult>"""

9
moto/elb/urls.py Normal file
View File

@ -0,0 +1,9 @@
from .responses import ELBResponse
url_bases = [
"https?://elasticloadbalancing.(.+).amazonaws.com",
]
url_paths = {
'{0}/$': ELBResponse().dispatch,
}

121
tests/test_elb/test_elb.py Normal file
View File

@ -0,0 +1,121 @@
import boto
from boto.ec2.elb import HealthCheck
import sure # flake8: noqa
from moto import mock_elb, mock_ec2
@mock_elb
def test_create_load_balancer():
conn = boto.connect_elb()
zones = ['us-east-1a', 'us-east-1b']
ports = [(80, 8080, 'http'), (443, 8443, 'tcp')]
lb = conn.create_load_balancer('my-lb', zones, ports)
balancers = conn.get_all_load_balancers()
balancer = balancers[0]
balancer.name.should.equal("my-lb")
set(balancer.availability_zones).should.equal(set(['us-east-1a', 'us-east-1b']))
listener1 = balancer.listeners[0]
listener1.load_balancer_port.should.equal(80)
listener1.instance_port.should.equal(8080)
listener1.protocol.should.equal("HTTP")
listener2 = balancer.listeners[1]
listener2.load_balancer_port.should.equal(443)
listener2.instance_port.should.equal(8443)
listener2.protocol.should.equal("TCP")
@mock_elb
def test_get_load_balancers_by_name():
conn = boto.connect_elb()
zones = ['us-east-1a', 'us-east-1b']
ports = [(80, 8080, 'http'), (443, 8443, 'tcp')]
lb = conn.create_load_balancer('my-lb1', zones, ports)
lb = conn.create_load_balancer('my-lb2', zones, ports)
lb = conn.create_load_balancer('my-lb3', zones, ports)
conn.get_all_load_balancers().should.have.length_of(3)
conn.get_all_load_balancers(load_balancer_names=['my-lb1']).should.have.length_of(1)
conn.get_all_load_balancers(load_balancer_names=['my-lb1', 'my-lb2']).should.have.length_of(2)
@mock_elb
def test_delete_load_balancer():
conn = boto.connect_elb()
zones = ['us-east-1a']
ports = [(80, 8080, 'http'), (443, 8443, 'tcp')]
lb = conn.create_load_balancer('my-lb', zones, ports)
balancers = conn.get_all_load_balancers()
balancers.should.have.length_of(1)
conn.delete_load_balancer("my-lb")
balancers = conn.get_all_load_balancers()
balancers.should.have.length_of(0)
@mock_elb
def test_create_health_check():
conn = boto.connect_elb()
hc = HealthCheck(
interval=20,
healthy_threshold=3,
unhealthy_threshold=5,
target='HTTP:8080/health',
timeout=23,
)
lb = conn.create_load_balancer('my-lb', [], [])
lb.configure_health_check(hc)
balancer = conn.get_all_load_balancers()[0]
health_check = balancer.health_check
health_check.interval.should.equal(20)
health_check.healthy_threshold.should.equal(3)
health_check.unhealthy_threshold.should.equal(5)
health_check.target.should.equal('HTTP:8080/health')
health_check.timeout.should.equal(23)
@mock_ec2
@mock_elb
def test_register_instances():
ec2_conn = boto.connect_ec2()
reservation = ec2_conn.run_instances('ami-1234abcd', 2)
instance_id1 = reservation.instances[0].id
instance_id2 = reservation.instances[1].id
conn = boto.connect_elb()
lb = conn.create_load_balancer('my-lb', [], [])
lb.register_instances([instance_id1, instance_id2])
balancer = conn.get_all_load_balancers()[0]
instance_ids = [instance.id for instance in balancer.instances]
set(instance_ids).should.equal(set([instance_id1, instance_id2]))
@mock_ec2
@mock_elb
def test_deregister_instances():
ec2_conn = boto.connect_ec2()
reservation = ec2_conn.run_instances('ami-1234abcd', 2)
instance_id1 = reservation.instances[0].id
instance_id2 = reservation.instances[1].id
conn = boto.connect_elb()
lb = conn.create_load_balancer('my-lb', [], [])
lb.register_instances([instance_id1, instance_id2])
balancer = conn.get_all_load_balancers()[0]
balancer.instances.should.have.length_of(2)
balancer.deregister_instances([instance_id1])
balancer.instances.should.have.length_of(1)
balancer.instances[0].id.should.equal(instance_id2)

View File