From d2029c3fa33a685449ee0da66cb07d833a4c290f Mon Sep 17 00:00:00 2001 From: Kevin Glisson Date: Thu, 29 May 2014 14:25:26 -0700 Subject: [PATCH 1/3] adding - get all certificates, get certificate, and upload certificates endpoints --- moto/iam/models.py | 28 +++++++++++++ moto/iam/responses.py | 92 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/moto/iam/models.py b/moto/iam/models.py index c3d1360b..440c32c6 100644 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -51,11 +51,25 @@ class InstanceProfile(object): return self.name +class Certificate(object): + def __init__(self, cert_name, cert_body, private_key, cert_chain=None, path=None): + self.cert_name = cert_name + self.cert_body = cert_body + self.private_key = private_key + self.path = path + self.cert_chain = cert_chain + + @property + def physical_resource_id(self): + return self.name + + class IAMBackend(BaseBackend): def __init__(self): self.instance_profiles = {} self.roles = {} + self.certificates = {} super(IAMBackend, self).__init__() def create_role(self, role_name, assume_role_policy_document, path, policies): @@ -96,4 +110,18 @@ class IAMBackend(BaseBackend): role = self.get_role(role_name) profile.roles.append(role) + def get_all_server_certs(self, marker=None): + return self.certificates.values() + + def upload_server_cert(self, cert_name, cert_body, private_key, cert_chain=None, path=None): + certificate_id = random_resource_id() + cert = Certificate(cert_name, cert_body, private_key, cert_chain, path) + self.certificates[certificate_id] = cert + return cert + + def get_server_certificate(self, name): + for key, cert in self.certificates.items(): + if name == cert.cert_name: + return cert + iam_backend = IAMBackend() diff --git a/moto/iam/responses.py b/moto/iam/responses.py index f30c189d..d8f6fb41 100644 --- a/moto/iam/responses.py +++ b/moto/iam/responses.py @@ -60,6 +60,29 @@ class IamResponse(BaseResponse): template = Template(LIST_INSTANCE_PROFILES_TEMPLATE) return template.render(instance_profiles=profiles) + def upload_server_certificate(self): + cert_name = self._get_param('ServerCertificateName') + cert_body = self._get_param('CertificateBody') + path = self._get_param('Path') + private_key = self._get_param('PrivateKey') + cert_chain = self._get_param('CertificateName') + + cert = iam_backend.upload_server_cert(cert_name, cert_body, private_key, cert_chain=cert_chain, path=path) + template = Template(UPLOAD_CERT_TEMPLATE) + return template.render(certificate=cert) + + def list_server_certificates(self, marker=None): + certs = iam_backend.get_all_server_certs(marker=marker) + template = Template(LIST_SERVER_CERTIFICATES_TEMPLATE) + return template.render(server_certificates=certs) + + def get_server_certificate(self): + cert_name = self._get_param('ServerCertificateName') + cert = iam_backend.get_server_certificate(cert_name) + template = Template(GET_SERVER_CERTIFICATE_TEMPLATE) + return template.render(certificate=cert) + + CREATE_INSTANCE_PROFILE_TEMPLATE = """ @@ -182,3 +205,72 @@ LIST_INSTANCE_PROFILES_TEMPLATE = """ + + + {{ certificate.cert_name }} + {% if certificate.path %} + {{ certificate.path }} + {% endif %} + arn:aws:iam::123456789012:server-certificate/{{ certificate.path }}/{{ certificate.cert_name }} + 2010-05-08T01:02:03.004Z + ASCACKCEVSQ6C2EXAMPLE + 2012-05-08T01:02:03.004Z + + + + 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE + +""" + +LIST_SERVER_CERTIFICATES_TEMPLATE = """ + + false + + {% for certificate in server_certificates %} + + + {{ certificate.cert_name }} + {% if certificate.path %} + {{ certificate.path }} + arn:aws:iam::123456789012:server-certificate/{{ certificate.path }}/{{ certificate.cert_name }} + {% else %} + arn:aws:iam::123456789012:server-certificate/{{ certificate.cert_name }} + {% endif %} + 2010-05-08T01:02:03.004Z + ASCACKCEVSQ6C2EXAMPLE + 2012-05-08T01:02:03.004Z + + + {% endfor %} + + + + 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE + +""" + +GET_SERVER_CERTIFICATE_TEMPLATE = """ + + + + {{ certificate.cert_name }} + {% if certificate.path %} + {{ certificate.path }} + arn:aws:iam::123456789012:server-certificate/{{ certificate.path }}/{{ certificate.cert_name }} + {% else %} + arn:aws:iam::123456789012:server-certificate/{{ certificate.cert_name }} + {% endif %} + 2010-05-08T01:02:03.004Z + ASCACKCEVSQ6C2EXAMPLE + 2012-05-08T01:02:03.004Z + + {{ certificate.cert_body }} + + + + 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE + +""" + From c8d8f00241020cdd5d6bdb839f17c740d0eb41af Mon Sep 17 00:00:00 2001 From: Kevin Glisson Date: Mon, 14 Jul 2014 17:54:45 -0700 Subject: [PATCH 2/3] adding ability to delete elb listeners --- moto/elb/models.py | 42 ++++++++++++++++++++++++-- moto/elb/responses.py | 70 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/moto/elb/models.py b/moto/elb/models.py index c99040cf..36f6eef2 100644 --- a/moto/elb/models.py +++ b/moto/elb/models.py @@ -12,10 +12,11 @@ class FakeHealthCheck(object): class FakeListener(object): - def __init__(self, load_balancer_port, instance_port, protocol): + def __init__(self, load_balancer_port, instance_port, protocol, ssl_certificate_id): self.load_balancer_port = load_balancer_port self.instance_port = instance_port self.protocol = protocol.upper() + self.ssl_certificate_id = ssl_certificate_id class FakeLoadBalancer(object): @@ -25,11 +26,13 @@ class FakeLoadBalancer(object): self.instance_ids = [] self.zones = zones self.listeners = [] - for protocol, lb_port, instance_port in ports: + + for protocol, lb_port, instance_port, ssl_certificate_id in ports: listener = FakeListener( protocol=protocol, load_balancer_port=lb_port, instance_port=instance_port, + ssl_certificate_id=ssl_certificate_id ) self.listeners.append(listener) @@ -63,6 +66,18 @@ class ELBBackend(BaseBackend): self.load_balancers[name] = new_load_balancer return new_load_balancer + def create_load_balancer_listeners(self, name, ports): + balancer = self.load_balancers.get(name, None) + if balancer: + for protocol, lb_port, instance_port, ssl_certificate_id in ports: + for listener in balancer.listeners: + if lb_port == listener.load_balancer_port: + break + else: + balancer.listeners.append(FakeListener(lb_port, instance_port, protocol, ssl_certificate_id)) + + return balancer + def describe_load_balancers(self, names): balancers = self.load_balancers.values() if names: @@ -70,6 +85,20 @@ class ELBBackend(BaseBackend): else: return balancers + def delete_load_balancer_listeners(self, name, ports): + balancer = self.load_balancers.get(name, None) + listeners = [] + if balancer: + for lb_port in ports: + for listener in balancer.listeners: + if lb_port == listener.load_balancer_port: + continue + else: + listeners.append(listener) + + balancer.listeners = listeners + return balancer + def delete_load_balancer(self, load_balancer_name): self.load_balancers.pop(load_balancer_name, None) @@ -85,6 +114,15 @@ class ELBBackend(BaseBackend): load_balancer.health_check = check return check + def set_load_balancer_listener_sslcertificate(self, name, lb_port, ssl_certificate_id): + balancer = self.load_balancers.get(name, None) + if balancer: + for idx, listener in enumerate(balancer.listeners): + if lb_port == listener.load_balancer_port: + balancer.listeners[idx].ssl_certificate_id = ssl_certificate_id + + return balancer + 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) diff --git a/moto/elb/responses.py b/moto/elb/responses.py index e6ba6b53..1c3e1f0d 100644 --- a/moto/elb/responses.py +++ b/moto/elb/responses.py @@ -21,8 +21,10 @@ class ELBResponse(BaseResponse): break lb_port = self.querystring['Listeners.member.{0}.LoadBalancerPort'.format(port_index)][0] instance_port = self.querystring['Listeners.member.{0}.InstancePort'.format(port_index)][0] - ports.append([protocol, lb_port, instance_port]) + ssl_certificate_id = self.querystring.get('Listeners.member.{0}.SSLCertificateId'.format(port_index)[0], None) + ports.append([protocol, lb_port, instance_port, ssl_certificate_id]) port_index += 1 + elb_backend.create_load_balancer( name=load_balancer_name, zones=availability_zones, @@ -31,12 +33,45 @@ class ELBResponse(BaseResponse): template = Template(CREATE_LOAD_BALANCER_TEMPLATE) return template.render() + def create_load_balancer_listeners(self): + load_balancer_name = self.querystring.get('LoadBalancerName')[0] + ports = [] + port_index = 1 + while True: + try: + protocol = self.querystring['Listeners.member.{0}.Protocol'.format(port_index)][0] + except KeyError: + break + lb_port = self.querystring['Listeners.member.{0}.LoadBalancerPort'.format(port_index)][0] + instance_port = self.querystring['Listeners.member.{0}.InstancePort'.format(port_index)][0] + ssl_certificate_id = self.querystring.get('Listeners.member.{0}.SSLCertificateId'.format(port_index)[0], None) + ports.append([protocol, lb_port, instance_port, ssl_certificate_id]) + port_index += 1 + + elb_backend.create_load_balancer_listeners(name=load_balancer_name, ports=ports) + + template = Template(CREATE_LOAD_BALANCER_LISTENERS_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_listeners(self): + load_balancer_name = self.querystring.get('LoadBalancerName')[0] + ports = [] + port_index = 1 + while True: + try: + ports.append(self.querystring['Listeners.member.{0}.LoadBalancerPort'.format(port_index)][0]) + except KeyError: + break + elb_backend.delete_load_balancer_listeners(load_balancer_name, ports) + template = Template(DELETE_LOAD_BALANCER_LISTENERS) + return template.render() + def delete_load_balancer(self): load_balancer_name = self.querystring.get('LoadBalancerName')[0] elb_backend.delete_load_balancer(load_balancer_name) @@ -62,6 +97,16 @@ class ELBResponse(BaseResponse): load_balancer = elb_backend.register_instances(load_balancer_name, instance_ids) return template.render(load_balancer=load_balancer) + def set_load_balancer_listener_sslcertificate(self): + load_balancer_name = self.querystring.get('LoadBalancerName')[0] + ssl_certificate_id = self.querystring['SSLCertificateId'][0] + lb_port = self.querystring['LoadBalancerPort'][0] + + elb_backend.set_load_balancer_listener_sslcertificate(load_balancer_name, lb_port, ssl_certificate_id) + + template = Template(SET_LOAD_BALANCER_SSL_CERTIFICATE) + return template.render() + 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] @@ -73,6 +118,13 @@ CREATE_LOAD_BALANCER_TEMPLATE = """ + + + 1549581b-12b7-11e3-895e-1334aEXAMPLE + +""" + DELETE_LOAD_BALANCER_TEMPLATE = """ """ @@ -106,6 +158,7 @@ DESCRIBE_LOAD_BALANCERS_TEMPLATE = """ """ + +SET_LOAD_BALANCER_SSL_CERTIFICATE = """ + + + 83c88b9d-12b7-11e3-8b82-87b12EXAMPLE + +""" + + +DELETE_LOAD_BALANCER_LISTENERS = """ + + + 83c88b9d-12b7-11e3-8b82-87b12EXAMPLE + +""" From fc30f5ba1f03b836a75d493af9af383ed683bb9a Mon Sep 17 00:00:00 2001 From: Kevin Glisson Date: Fri, 18 Jul 2014 17:31:57 -0700 Subject: [PATCH 3/3] adding tests --- moto/elb/models.py | 3 +-- moto/elb/responses.py | 6 ++++- tests/test_elb/test_elb.py | 54 ++++++++++++++++++++++++++++++++++++++ tests/test_iam/test_iam.py | 33 +++++++++++++++++++++++ 4 files changed, 93 insertions(+), 3 deletions(-) diff --git a/moto/elb/models.py b/moto/elb/models.py index 36f6eef2..6a6bc6f6 100644 --- a/moto/elb/models.py +++ b/moto/elb/models.py @@ -91,11 +91,10 @@ class ELBBackend(BaseBackend): if balancer: for lb_port in ports: for listener in balancer.listeners: - if lb_port == listener.load_balancer_port: + if int(lb_port) == int(listener.load_balancer_port): continue else: listeners.append(listener) - balancer.listeners = listeners return balancer diff --git a/moto/elb/responses.py b/moto/elb/responses.py index 1c3e1f0d..8f92a914 100644 --- a/moto/elb/responses.py +++ b/moto/elb/responses.py @@ -65,9 +65,13 @@ class ELBResponse(BaseResponse): port_index = 1 while True: try: - ports.append(self.querystring['Listeners.member.{0}.LoadBalancerPort'.format(port_index)][0]) + port = self.querystring['LoadBalancerPorts.member.{0}'.format(port_index)][0] except KeyError: break + + port_index += 1 + ports.append(int(port)) + elb_backend.delete_load_balancer_listeners(load_balancer_name, ports) template = Template(DELETE_LOAD_BALANCER_LISTENERS) return template.render() diff --git a/tests/test_elb/test_elb.py b/tests/test_elb/test_elb.py index cd4e449e..4e74701d 100644 --- a/tests/test_elb/test_elb.py +++ b/tests/test_elb/test_elb.py @@ -27,6 +27,60 @@ def test_create_load_balancer(): listener2.protocol.should.equal("TCP") +@mock_elb +def test_add_listener(): + conn = boto.connect_elb() + zones = ['us-east-1a', 'us-east-1b'] + ports = [(80, 8080, 'http')] + conn.create_load_balancer('my-lb', zones, ports) + new_listener = (443, 8443, 'tcp') + conn.create_load_balancer_listeners('my-lb', [new_listener]) + balancers = conn.get_all_load_balancers() + balancer = balancers[0] + 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_delete_listener(): + conn = boto.connect_elb() + + zones = ['us-east-1a', 'us-east-1b'] + ports = [(80, 8080, 'http'), (443, 8443, 'tcp')] + conn.create_load_balancer('my-lb', zones, ports) + conn.delete_load_balancer_listeners('my-lb', [443]) + balancers = conn.get_all_load_balancers() + balancer = balancers[0] + listener1 = balancer.listeners[0] + listener1.load_balancer_port.should.equal(80) + listener1.instance_port.should.equal(8080) + listener1.protocol.should.equal("HTTP") + balancer.listeners.should.have.length_of(1) + + +@mock_elb +def test_set_sslcertificate(): + conn = boto.connect_elb() + + zones = ['us-east-1a', 'us-east-1b'] + ports = [(443, 8443, 'tcp')] + conn.create_load_balancer('my-lb', zones, ports) + conn.set_lb_listener_SSL_certificate('my-lb', '443', 'arn:certificate') + balancers = conn.get_all_load_balancers() + balancer = balancers[0] + listener1 = balancer.listeners[0] + listener1.load_balancer_port.should.equal(443) + listener1.instance_port.should.equal(8443) + listener1.protocol.should.equal("TCP") + listener1.ssl_certificate_id.should.equal("arn:certificate") + + @mock_elb def test_get_load_balancers_by_name(): conn = boto.connect_elb() diff --git a/tests/test_iam/test_iam.py b/tests/test_iam/test_iam.py index 73d548e6..2cbb0ba5 100644 --- a/tests/test_iam/test_iam.py +++ b/tests/test_iam/test_iam.py @@ -5,6 +5,39 @@ import sure # noqa from moto import mock_iam +@mock_iam() +def test_get_all_server_certs(): + conn = boto.connect_iam() + + conn = boto.connect_iam() + conn.upload_server_cert("certname", "certbody", "privatekey") + certs = conn.get_all_server_certs()['list_server_certificates_response']['list_server_certificates_result']['server_certificate_metadata_list'] + certs.should.have.length_of(1) + cert1 = certs[0] + cert1.server_certificate_name.should.equal("certname") + cert1.arn.should.equal("arn:aws:iam::123456789012:server-certificate/certname") + + +@mock_iam() +def test_get_server_cert(): + conn = boto.connect_iam() + + conn.upload_server_cert("certname", "certbody", "privatekey") + cert = conn.get_server_certificate("certname") + cert.server_certificate_name.should.equal("certname") + cert.arn.should.equal("arn:aws:iam::123456789012:server-certificate/certname") + + +@mock_iam() +def test_upload_server_cert(): + conn = boto.connect_iam() + + conn.upload_server_cert("certname", "certbody", "privatekey") + cert = conn.get_server_certificate("certname") + cert.server_certificate_name.should.equal("certname") + cert.arn.should.equal("arn:aws:iam::123456789012:server-certificate/certname") + + @mock_iam() def test_create_role_and_instance_profile(): conn = boto.connect_iam()