diff --git a/moto/elb/models.py b/moto/elb/models.py index 94914a8e7..e1487f5aa 100644 --- a/moto/elb/models.py +++ b/moto/elb/models.py @@ -1,6 +1,13 @@ from __future__ import unicode_literals import boto.ec2.elb +from boto.ec2.elb.attributes import ( + LbAttributes, + ConnectionSettingAttribute, + ConnectionDrainingAttribute, + AccessLogAttribute, + CrossZoneLoadBalancingAttribute, +) from moto.core import BaseBackend @@ -29,6 +36,7 @@ class FakeLoadBalancer(object): self.instance_ids = [] self.zones = zones self.listeners = [] + self.attributes = FakeLoadBalancer.get_default_attributes() for protocol, lb_port, instance_port, ssl_certificate_id in ports: listener = FakeListener( @@ -73,6 +81,28 @@ class FakeLoadBalancer(object): raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "SourceSecurityGroup.OwnerAlias" ]"') raise UnformattedGetAttTemplateException() + @classmethod + def get_default_attributes(cls): + attributes = LbAttributes() + + cross_zone_load_balancing = CrossZoneLoadBalancingAttribute() + cross_zone_load_balancing.enabled = False + attributes.cross_zone_load_balancing = cross_zone_load_balancing + + connection_draining = ConnectionDrainingAttribute() + connection_draining.enabled = False + attributes.connection_draining = connection_draining + + access_log = AccessLogAttribute() + access_log.enabled = False + attributes.access_log = access_log + + connection_settings = ConnectionSettingAttribute() + connection_settings.idle_timeout = 60 + attributes.connecting_settings = connection_settings + + return attributes + class ELBBackend(BaseBackend): @@ -151,6 +181,26 @@ class ELBBackend(BaseBackend): load_balancer.instance_ids = new_instance_ids return load_balancer + def set_cross_zone_load_balancing_attribute(self, load_balancer_name, attribute): + load_balancer = self.get_load_balancer(load_balancer_name) + load_balancer.attributes.cross_zone_load_balancing = attribute + return load_balancer + + def set_access_log_attribute(self, load_balancer_name, attribute): + load_balancer = self.get_load_balancer(load_balancer_name) + load_balancer.attributes.access_log = attribute + return load_balancer + + def set_connection_draining_attribute(self, load_balancer_name, attribute): + load_balancer = self.get_load_balancer(load_balancer_name) + load_balancer.attributes.connection_draining = attribute + return load_balancer + + def set_connection_settings_attribute(self, load_balancer_name, attribute): + load_balancer = self.get_load_balancer(load_balancer_name) + load_balancer.attributes.connecting_settings = attribute + return load_balancer + elb_backends = {} for region in boto.ec2.elb.regions(): diff --git a/moto/elb/responses.py b/moto/elb/responses.py index fb114fb22..be9c8ad8b 100644 --- a/moto/elb/responses.py +++ b/moto/elb/responses.py @@ -1,4 +1,10 @@ from __future__ import unicode_literals +from boto.ec2.elb.attributes import ( + ConnectionSettingAttribute, + ConnectionDrainingAttribute, + AccessLogAttribute, + CrossZoneLoadBalancingAttribute, +) from moto.core.responses import BaseResponse from .models import elb_backends @@ -122,6 +128,56 @@ class ELBResponse(BaseResponse): load_balancer = self.elb_backend.deregister_instances(load_balancer_name, instance_ids) return template.render(load_balancer=load_balancer) + def describe_load_balancer_attributes(self): + load_balancer_name = self.querystring.get('LoadBalancerName')[0] + load_balancer = self.elb_backend.describe_load_balancers(load_balancer_name)[0] + template = self.response_template(DESCRIBE_ATTRIBUTES_TEMPLATE) + return template.render(attributes=load_balancer.attributes) + + def modify_load_balancer_attributes(self): + load_balancer_name = self.querystring.get('LoadBalancerName')[0] + load_balancer = self.elb_backend.describe_load_balancers(load_balancer_name)[0] + + def parse_attribute(attribute_name): + """ + Transform self.querystring parameters matching `LoadBalancerAttributes.attribute_name.attribute_key` + into a dictionary of (attribute_name, attribute_key)` pairs. + """ + attribute_prefix = "LoadBalancerAttributes." + attribute_name + return dict((key.lstrip(attribute_prefix), value[0]) for key, value in self.querystring.items() if key.startswith(attribute_prefix)) + + cross_zone = parse_attribute("CrossZoneLoadBalancing") + if cross_zone: + attribute = CrossZoneLoadBalancingAttribute() + attribute.enabled = cross_zone["Enabled"] == "true" + self.elb_backend.set_cross_zone_load_balancing_attribute(load_balancer_name, attribute) + + access_log = parse_attribute("AccessLog") + if access_log: + attribute = AccessLogAttribute() + attribute.enabled = access_log["Enabled"] == "true" + attribute.s3_bucket_name = access_log["S3BucketName"] + attribute.s3_bucket_prefix = access_log["S3BucketPrefix"] + attribute.emit_interval = access_log["EmitInterval"] + self.elb_backend.set_access_log_attribute(load_balancer_name, attribute) + + connection_draining = parse_attribute("ConnectionDraining") + if connection_draining: + attribute = ConnectionDrainingAttribute() + attribute.enabled = connection_draining["Enabled"] == "true" + attribute.timeout = connection_draining["Timeout"] + self.elb_backend.set_connection_draining_attribute(load_balancer_name, attribute) + + connection_settings = parse_attribute("ConnectionSettings") + if connection_settings: + attribute = ConnectionSettingAttribute() + attribute.idle_timeout = connection_settings["IdleTimeout"] + self.elb_backend.set_connection_settings_attribute(load_balancer_name, attribute) + + template = self.response_template(MODIFY_ATTRIBUTES_TEMPLATE) + return template.render(attributes=load_balancer.attributes) + + CREATE_LOAD_BALANCER_TEMPLATE = """ tests.us-east-1.elb.amazonaws.com """ @@ -253,3 +309,67 @@ DELETE_LOAD_BALANCER_LISTENERS = """ + + + + {{ attributes.access_log.enabled }} + {% if attributes.access_log.enabled %} + {{ attributes.access_log.s3_bucket_name }} + {{ attributes.access_log.s3_bucket_prefix }} + {{ attributes.access_log.emit_interval }} + {% endif %} + + + {{ attributes.connecting_settings.idle_timeout }} + + + {{ attributes.cross_zone_load_balancing.enabled }} + + + {{ attributes.connection_draining.enabled }} + {% if attributes.connection_draining.enabled %} + {{ attributes.connection_draining.timeout }} + {% endif %} + + + + + 83c88b9d-12b7-11e3-8b82-87b12EXAMPLE + + +""" + +MODIFY_ATTRIBUTES_TEMPLATE = """ + + my-loadbalancer + + + {{ attributes.access_log.enabled }} + {% if attributes.access_log.enabled %} + {{ attributes.access_log.s3_bucket_name }} + {{ attributes.access_log.s3_bucket_prefix }} + {{ attributes.access_log.emit_interval }} + {% endif %} + + + {{ attributes.connecting_settings.idle_timeout }} + + + {{ attributes.cross_zone_load_balancing.enabled }} + + + {{ attributes.connection_draining.enabled }} + {% if attributes.connection_draining.enabled %} + {{ attributes.connection_draining.timeout }} + {% endif %} + + + + + 83c88b9d-12b7-11e3-8b82-87b12EXAMPLE + + +""" + diff --git a/tests/test_elb/test_elb.py b/tests/test_elb/test_elb.py index abfa38e5c..3f31e9d49 100644 --- a/tests/test_elb/test_elb.py +++ b/tests/test_elb/test_elb.py @@ -2,6 +2,11 @@ from __future__ import unicode_literals import boto import boto.ec2.elb from boto.ec2.elb import HealthCheck +from boto.ec2.elb.attributes import ( + ConnectionSettingAttribute, + ConnectionDrainingAttribute, + AccessLogAttribute, +) import sure # noqa from moto import mock_elb, mock_ec2 @@ -193,3 +198,99 @@ def test_deregister_instances(): balancer.instances.should.have.length_of(1) balancer.instances[0].id.should.equal(instance_id2) + +@mock_elb +def test_default_attributes(): + conn = boto.connect_elb() + ports = [(80, 8080, 'http'), (443, 8443, 'tcp')] + lb = conn.create_load_balancer('my-lb', [], ports) + attributes = lb.get_attributes() + + attributes.cross_zone_load_balancing.enabled.should.be.false + attributes.connection_draining.enabled.should.be.false + attributes.access_log.enabled.should.be.false + attributes.connecting_settings.idle_timeout.should.equal(60) + + +@mock_elb +def test_cross_zone_load_balancing_attribute(): + conn = boto.connect_elb() + ports = [(80, 8080, 'http'), (443, 8443, 'tcp')] + lb = conn.create_load_balancer('my-lb', [], ports) + + conn.modify_lb_attribute("my-lb", "CrossZoneLoadBalancing", True) + attributes = lb.get_attributes(force=True) + attributes.cross_zone_load_balancing.enabled.should.be.true + + conn.modify_lb_attribute("my-lb", "CrossZoneLoadBalancing", False) + attributes = lb.get_attributes(force=True) + attributes.cross_zone_load_balancing.enabled.should.be.false + +@mock_elb +def test_connection_draining_attribute(): + conn = boto.connect_elb() + ports = [(80, 8080, 'http'), (443, 8443, 'tcp')] + lb = conn.create_load_balancer('my-lb', [], ports) + + connection_draining = ConnectionDrainingAttribute() + connection_draining.enabled = True + connection_draining.timeout = 60 + + conn.modify_lb_attribute("my-lb", "ConnectionDraining", connection_draining) + attributes = lb.get_attributes(force=True) + attributes.connection_draining.enabled.should.be.true + attributes.connection_draining.timeout.should.equal(60) + + connection_draining.timeout = 30 + conn.modify_lb_attribute("my-lb", "ConnectionDraining", connection_draining) + attributes = lb.get_attributes(force=True) + attributes.connection_draining.timeout.should.equal(30) + + connection_draining.enabled = False + conn.modify_lb_attribute("my-lb", "ConnectionDraining", connection_draining) + attributes = lb.get_attributes(force=True) + attributes.connection_draining.enabled.should.be.false + +@mock_elb +def test_access_log_attribute(): + conn = boto.connect_elb() + ports = [(80, 8080, 'http'), (443, 8443, 'tcp')] + lb = conn.create_load_balancer('my-lb', [], ports) + + access_log = AccessLogAttribute() + access_log.enabled = True + access_log.s3_bucket_name = 'bucket' + access_log.s3_bucket_prefix = 'prefix' + access_log.emit_interval = 60 + + conn.modify_lb_attribute("my-lb", "AccessLog", access_log) + attributes = lb.get_attributes(force=True) + attributes.access_log.enabled.should.be.true + attributes.access_log.s3_bucket_name.should.equal("bucket") + attributes.access_log.s3_bucket_prefix.should.equal("prefix") + attributes.access_log.emit_interval.should.equal(60) + + access_log.enabled = False + conn.modify_lb_attribute("my-lb", "AccessLog", access_log) + attributes = lb.get_attributes(force=True) + attributes.access_log.enabled.should.be.false + +@mock_elb +def test_connection_settings_attribute(): + conn = boto.connect_elb() + ports = [(80, 8080, 'http'), (443, 8443, 'tcp')] + lb = conn.create_load_balancer('my-lb', [], ports) + + connection_settings = ConnectionSettingAttribute(conn) + connection_settings.idle_timeout = 120 + + conn.modify_lb_attribute("my-lb", "ConnectingSettings", connection_settings) + attributes = lb.get_attributes(force=True) + attributes.connecting_settings.idle_timeout.should.equal(120) + + connection_settings.idle_timeout = 60 + conn.modify_lb_attribute("my-lb", "ConnectingSettings", connection_settings) + attributes = lb.get_attributes(force=True) + attributes.connecting_settings.idle_timeout.should.equal(60) + +