From 390d3b900cb686ba141298d2924a9fb2bd66f1a2 Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 12:08:00 +0200 Subject: [PATCH 01/13] add a first failing unit test for keypairs --- tests/test_ec2/test_key_pairs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_ec2/test_key_pairs.py b/tests/test_ec2/test_key_pairs.py index 7a961051..a5e35455 100644 --- a/tests/test_ec2/test_key_pairs.py +++ b/tests/test_ec2/test_key_pairs.py @@ -5,5 +5,6 @@ from moto import mock_ec2 @mock_ec2 -def test_key_pairs(): - pass +def test_key_pairs_empty(): + conn = boto.connect_ec2('the_key', 'the_secret') + assert len(conn.get_all_key_pairs()) == 0 From d438b05d413108dad1c57864c0dd46b2fd2cd649 Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 12:18:52 +0200 Subject: [PATCH 02/13] return empty key pairs response --- moto/ec2/responses/key_pairs.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/moto/ec2/responses/key_pairs.py b/moto/ec2/responses/key_pairs.py index fd0a35fe..bcb4e5ed 100644 --- a/moto/ec2/responses/key_pairs.py +++ b/moto/ec2/responses/key_pairs.py @@ -1,3 +1,4 @@ +from jinja2 import Template from moto.core.responses import BaseResponse @@ -9,7 +10,15 @@ class KeyPairs(BaseResponse): raise NotImplementedError('KeyPairs.delete_key_pair is not yet implemented') def describe_key_pairs(self): - raise NotImplementedError('KeyPairs.describe_key_pairs is not yet implemented') + template = Template(DESCRIBE_KEY_PAIRS_RESPONSE) + return template.render(keypairs=[]) def import_key_pair(self): raise NotImplementedError('KeyPairs.import_key_pair is not yet implemented') + + +DESCRIBE_KEY_PAIRS_RESPONSE = """ + 59dbff89-35bd-4eac-99ed-be587EXAMPLE + + + """ From c688e43a9a9ba01b41845a3f1a23ada104d54338 Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 12:24:46 +0200 Subject: [PATCH 03/13] add test for create_key_pair --- tests/test_ec2/test_key_pairs.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_ec2/test_key_pairs.py b/tests/test_ec2/test_key_pairs.py index a5e35455..9b488e3d 100644 --- a/tests/test_ec2/test_key_pairs.py +++ b/tests/test_ec2/test_key_pairs.py @@ -8,3 +8,10 @@ from moto import mock_ec2 def test_key_pairs_empty(): conn = boto.connect_ec2('the_key', 'the_secret') assert len(conn.get_all_key_pairs()) == 0 + + +@mock_ec2 +def test_key_pairs_create(): + conn = boto.connect_ec2('the_key', 'the_secret') + kp = conn.create_key_pair('foo') + assert kp.material.startswith('-----BEGIN RSA PRIVATE KEY-----') From 65beb30054f5477447fdf53ea3b6cb30f66585b2 Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 12:42:50 +0200 Subject: [PATCH 04/13] create KeyPairBackend in ec2 model, use in keypair test --- moto/ec2/models.py | 27 ++++++++++++++++++++++++++- moto/ec2/responses/key_pairs.py | 4 +++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index e0907978..65008458 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -161,6 +161,30 @@ class InstanceBackend(object): return [reservation for reservation in self.reservations.values()] +class KeyPairBackend(object): + + class KeyPair(object): + pass + + def __init__(self): + self.keypairs = defaultdict(dict) + super(KeyPairBackend, self).__init__() + + def create_key_pair(self, name): + self.keypairs[name] = self.KeyPair() + return name + + def delete_key_pair(self, name): + return self.keypairs.pop(name) + + def describe_key_pairs(self, filter_names=None): + results = [] + for name, keypair in self.keypairs.iteritems(): + if not filter_names or name in filter_names: + results.append({name: keypair}) + return results + + class TagBackend(object): def __init__(self): @@ -675,7 +699,8 @@ class ElasticAddressBackend(object): class EC2Backend(BaseBackend, InstanceBackend, TagBackend, AmiBackend, RegionsAndZonesBackend, SecurityGroupBackend, EBSBackend, - VPCBackend, SubnetBackend, SpotRequestBackend, ElasticAddressBackend): + VPCBackend, SubnetBackend, SpotRequestBackend, ElasticAddressBackend, + KeyPairBackend): pass diff --git a/moto/ec2/responses/key_pairs.py b/moto/ec2/responses/key_pairs.py index bcb4e5ed..565d0506 100644 --- a/moto/ec2/responses/key_pairs.py +++ b/moto/ec2/responses/key_pairs.py @@ -1,8 +1,10 @@ from jinja2 import Template from moto.core.responses import BaseResponse +from moto.ec2.models import ec2_backend class KeyPairs(BaseResponse): + def create_key_pair(self): raise NotImplementedError('KeyPairs.create_key_pair is not yet implemented') @@ -11,7 +13,7 @@ class KeyPairs(BaseResponse): def describe_key_pairs(self): template = Template(DESCRIBE_KEY_PAIRS_RESPONSE) - return template.render(keypairs=[]) + return template.render(keypairs=ec2_backend.describe_key_pairs()) def import_key_pair(self): raise NotImplementedError('KeyPairs.import_key_pair is not yet implemented') From ddfe47847982e3cb75226f958b1abf5b58c5efce Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 13:03:26 +0200 Subject: [PATCH 05/13] implement test for create_key_pair --- moto/ec2/models.py | 16 +++++++++------- moto/ec2/responses/key_pairs.py | 14 +++++++++++++- moto/ec2/utils.py | 24 ++++++++++++++++++++++++ tests/test_ec2/test_key_pairs.py | 2 +- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 65008458..595b96d7 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -19,6 +19,7 @@ from .utils import ( random_eip_association_id, random_eip_allocation_id, random_ip, + random_key_pair, ) @@ -163,25 +164,26 @@ class InstanceBackend(object): class KeyPairBackend(object): - class KeyPair(object): - pass - def __init__(self): self.keypairs = defaultdict(dict) super(KeyPairBackend, self).__init__() def create_key_pair(self, name): - self.keypairs[name] = self.KeyPair() - return name + self.keypairs[name] = keypair = random_key_pair() + keypair['name'] = name + return keypair def delete_key_pair(self, name): - return self.keypairs.pop(name) + keypair = self.keypairs.pop(name) + keypair['name'] = name + return keypair def describe_key_pairs(self, filter_names=None): results = [] for name, keypair in self.keypairs.iteritems(): if not filter_names or name in filter_names: - results.append({name: keypair}) + keypair['name'] = name + results.append(keypair) return results diff --git a/moto/ec2/responses/key_pairs.py b/moto/ec2/responses/key_pairs.py index 565d0506..30cd2dd6 100644 --- a/moto/ec2/responses/key_pairs.py +++ b/moto/ec2/responses/key_pairs.py @@ -6,7 +6,9 @@ from moto.ec2.models import ec2_backend class KeyPairs(BaseResponse): def create_key_pair(self): - raise NotImplementedError('KeyPairs.create_key_pair is not yet implemented') + name = self.querystring.get('KeyName')[0] + template = Template(CREATE_KEY_PAIR_RESPONSE) + return template.render(**ec2_backend.create_key_pair(name)) def delete_key_pair(self): raise NotImplementedError('KeyPairs.delete_key_pair is not yet implemented') @@ -24,3 +26,13 @@ DESCRIBE_KEY_PAIRS_RESPONSE = """ + {{ name }} + + {{ fingerprint }} + + {{ material }} + +""" diff --git a/moto/ec2/utils.py b/moto/ec2/utils.py index f138919d..385f4cce 100644 --- a/moto/ec2/utils.py +++ b/moto/ec2/utils.py @@ -144,3 +144,27 @@ def filter_reservations(reservations, filter_dict): reservation.instances = new_instances result.append(reservation) return result + + +# not really random +def random_key_pair(): + return { + 'fingerprint': ('1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:' + '7d:b8:ca:9f:f5:f1:6f'), + 'material': """---- BEGIN RSA PRIVATE KEY ---- +MIICiTCCAfICCQD6m7oRw0uXOjANBgkqhkiG9w0BAQUFADCBiDELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6 +b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAd +BgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5jb20wHhcNMTEwNDI1MjA0NTIxWhcN +MTIwNDI0MjA0NTIxWjCBiDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYD +VQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6b24xFDASBgNVBAsTC0lBTSBDb25z +b2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAdBgkqhkiG9w0BCQEWEG5vb25lQGFt +YXpvbi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMaK0dn+a4GmWIWJ +21uUSfwfEvySWtC2XADZ4nB+BLYgVIk60CpiwsZ3G93vUEIO3IyNoH/f0wYK8m9T +rDHudUZg3qX4waLG5M43q7Wgc/MbQITxOUSQv7c7ugFFDzQGBzZswY6786m86gpE +Ibb3OhjZnzcvQAaRHhdlQWIMm2nrAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAtCu4 +nUhVVxYUntneD9+h8Mg9q6q+auNKyExzyLwaxlAoo7TJHidbtS4J5iNmZgXL0Fkb +FFBjvSfpJIlJ00zbhNYS5f6GuoEDmFJl0ZxBHjJnyp378OD8uTs7fLvjx79LjSTb +NYiytVbZPQUQ5Yaxu2jXnimvw3rrszlaEXAMPLE +-----END RSA PRIVATE KEY-----""" + } diff --git a/tests/test_ec2/test_key_pairs.py b/tests/test_ec2/test_key_pairs.py index 9b488e3d..5bb26173 100644 --- a/tests/test_ec2/test_key_pairs.py +++ b/tests/test_ec2/test_key_pairs.py @@ -14,4 +14,4 @@ def test_key_pairs_empty(): def test_key_pairs_create(): conn = boto.connect_ec2('the_key', 'the_secret') kp = conn.create_key_pair('foo') - assert kp.material.startswith('-----BEGIN RSA PRIVATE KEY-----') + assert kp.material.startswith('---- BEGIN RSA PRIVATE KEY ----') From 8b7c3a331277d9ff7f25b379976f14696417d3e2 Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 13:06:53 +0200 Subject: [PATCH 06/13] add test for creating already existing keypair --- tests/test_ec2/test_key_pairs.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_ec2/test_key_pairs.py b/tests/test_ec2/test_key_pairs.py index 5bb26173..e0cc8373 100644 --- a/tests/test_ec2/test_key_pairs.py +++ b/tests/test_ec2/test_key_pairs.py @@ -1,6 +1,7 @@ import boto import sure # noqa +from boto.exception import EC2ResponseError from moto import mock_ec2 @@ -15,3 +16,15 @@ def test_key_pairs_create(): conn = boto.connect_ec2('the_key', 'the_secret') kp = conn.create_key_pair('foo') assert kp.material.startswith('---- BEGIN RSA PRIVATE KEY ----') + + +@mock_ec2 +def test_key_pairs_create_exist(): + conn = boto.connect_ec2('the_key', 'the_secret') + kp = conn.create_key_pair('foo') + assert kp.material.startswith('---- BEGIN RSA PRIVATE KEY ----') + # Call get_all_instances with a bad id should raise an error + conn.create_key_pair.when.called_with('foo').should.throw( + EC2ResponseError, + "The keypair 'foo' already exists." + ) From 35063ca7437f6c103663ba3f047ee24ddbf1de0e Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 13:13:23 +0200 Subject: [PATCH 07/13] make duplicate key pair test pass --- moto/ec2/models.py | 2 ++ moto/ec2/responses/key_pairs.py | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 595b96d7..b3ac035b 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -169,6 +169,8 @@ class KeyPairBackend(object): super(KeyPairBackend, self).__init__() def create_key_pair(self, name): + if name in self.keypairs: + raise InvalidIdError(name) self.keypairs[name] = keypair = random_key_pair() keypair['name'] = name return keypair diff --git a/moto/ec2/responses/key_pairs.py b/moto/ec2/responses/key_pairs.py index 30cd2dd6..9afabda8 100644 --- a/moto/ec2/responses/key_pairs.py +++ b/moto/ec2/responses/key_pairs.py @@ -1,14 +1,21 @@ from jinja2 import Template from moto.core.responses import BaseResponse from moto.ec2.models import ec2_backend +from moto.ec2.exceptions import InvalidIdError class KeyPairs(BaseResponse): def create_key_pair(self): - name = self.querystring.get('KeyName')[0] - template = Template(CREATE_KEY_PAIR_RESPONSE) - return template.render(**ec2_backend.create_key_pair(name)) + try: + name = self.querystring.get('KeyName')[0] + keypair = ec2_backend.create_key_pair(name) + except InvalidIdError as exc: + template = Template(CREATE_KEY_PAIR_INVALID_NAME) + return template.render(keypair_id=exc.id), dict(status=400) + else: + template = Template(CREATE_KEY_PAIR_RESPONSE) + return template.render(**keypair) def delete_key_pair(self): raise NotImplementedError('KeyPairs.delete_key_pair is not yet implemented') @@ -36,3 +43,8 @@ CREATE_KEY_PAIR_RESPONSE = """ +InvalidKeyPair.DuplicateThe keypair '{{ keypair_id }}' already exists.f4f76e81-8ca5-4e61-a6d5-a4a96EXAMPLE +""" From 99c6b8acbe7725f91fdfb1e0108fa7ba92394c47 Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 13:20:47 +0200 Subject: [PATCH 08/13] test DescribeKeyPairs with more than one key pair --- moto/ec2/responses/key_pairs.py | 6 ++++++ tests/test_ec2/test_key_pairs.py | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/moto/ec2/responses/key_pairs.py b/moto/ec2/responses/key_pairs.py index 9afabda8..c3072af3 100644 --- a/moto/ec2/responses/key_pairs.py +++ b/moto/ec2/responses/key_pairs.py @@ -31,6 +31,12 @@ class KeyPairs(BaseResponse): DESCRIBE_KEY_PAIRS_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE + {% for keypair in keypairs %} + + {{ keypair.name }} + {{ keypair.fingerprint }} + + {% endfor %} """ diff --git a/tests/test_ec2/test_key_pairs.py b/tests/test_ec2/test_key_pairs.py index e0cc8373..da266bd4 100644 --- a/tests/test_ec2/test_key_pairs.py +++ b/tests/test_ec2/test_key_pairs.py @@ -16,6 +16,21 @@ def test_key_pairs_create(): conn = boto.connect_ec2('the_key', 'the_secret') kp = conn.create_key_pair('foo') assert kp.material.startswith('---- BEGIN RSA PRIVATE KEY ----') + kps = conn.get_all_key_pairs() + assert len(kps) == 1 + assert kps[0].name == 'foo' + + +@mock_ec2 +def test_key_pairs_create_two(): + conn = boto.connect_ec2('the_key', 'the_secret') + kp = conn.create_key_pair('foo') + kp = conn.create_key_pair('bar') + assert kp.material.startswith('---- BEGIN RSA PRIVATE KEY ----') + kps = conn.get_all_key_pairs() + assert len(kps) == 2 + assert kps[0].name == 'foo' + assert kps[1].name == 'bar' @mock_ec2 @@ -23,6 +38,7 @@ def test_key_pairs_create_exist(): conn = boto.connect_ec2('the_key', 'the_secret') kp = conn.create_key_pair('foo') assert kp.material.startswith('---- BEGIN RSA PRIVATE KEY ----') + assert len(conn.get_all_key_pairs()) == 1 # Call get_all_instances with a bad id should raise an error conn.create_key_pair.when.called_with('foo').should.throw( EC2ResponseError, From e7d2c2687aa7d53fe7261c62f70fa4cc6c3bb354 Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 13:34:39 +0200 Subject: [PATCH 09/13] implement delete_key_pair, test zero case --- moto/ec2/responses/key_pairs.py | 8 +++++++- tests/test_ec2/test_key_pairs.py | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/moto/ec2/responses/key_pairs.py b/moto/ec2/responses/key_pairs.py index c3072af3..68c25e71 100644 --- a/moto/ec2/responses/key_pairs.py +++ b/moto/ec2/responses/key_pairs.py @@ -18,7 +18,7 @@ class KeyPairs(BaseResponse): return template.render(**keypair) def delete_key_pair(self): - raise NotImplementedError('KeyPairs.delete_key_pair is not yet implemented') + return Template(DELETE_KEY_PAIR_RESPONSE).render(success="true") def describe_key_pairs(self): template = Template(DESCRIBE_KEY_PAIRS_RESPONSE) @@ -54,3 +54,9 @@ CREATE_KEY_PAIR_RESPONSE = """ InvalidKeyPair.DuplicateThe keypair '{{ keypair_id }}' already exists.f4f76e81-8ca5-4e61-a6d5-a4a96EXAMPLE """ + + +DELETE_KEY_PAIR_RESPONSE = """ + 59dbff89-35bd-4eac-99ed-be587EXAMPLE + {{ success }} +""" diff --git a/tests/test_ec2/test_key_pairs.py b/tests/test_ec2/test_key_pairs.py index da266bd4..a23516da 100644 --- a/tests/test_ec2/test_key_pairs.py +++ b/tests/test_ec2/test_key_pairs.py @@ -39,8 +39,15 @@ def test_key_pairs_create_exist(): kp = conn.create_key_pair('foo') assert kp.material.startswith('---- BEGIN RSA PRIVATE KEY ----') assert len(conn.get_all_key_pairs()) == 1 - # Call get_all_instances with a bad id should raise an error conn.create_key_pair.when.called_with('foo').should.throw( EC2ResponseError, "The keypair 'foo' already exists." ) + + +@mock_ec2 +def test_key_pairs_delete_no_exist(): + conn = boto.connect_ec2('the_key', 'the_secret') + assert len(conn.get_all_key_pairs()) == 0 + r = conn.delete_key_pair('foo') + r.should.be.ok From 38fa8de4b426821520e85f4ec6f9ef4b753ca38b Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 13:35:42 +0200 Subject: [PATCH 10/13] test for delete_key_pair --- tests/test_ec2/test_key_pairs.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_ec2/test_key_pairs.py b/tests/test_ec2/test_key_pairs.py index a23516da..18bc0865 100644 --- a/tests/test_ec2/test_key_pairs.py +++ b/tests/test_ec2/test_key_pairs.py @@ -51,3 +51,12 @@ def test_key_pairs_delete_no_exist(): assert len(conn.get_all_key_pairs()) == 0 r = conn.delete_key_pair('foo') r.should.be.ok + + +@mock_ec2 +def test_key_pairs_delete_exist(): + conn = boto.connect_ec2('the_key', 'the_secret') + conn.create_key_pair('foo') + r = conn.delete_key_pair('foo') + r.should.be.ok + assert len(conn.get_all_key_pairs()) == 0 From 72ae98128c1102435572a5396007f2379a6912df Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 13:38:46 +0200 Subject: [PATCH 11/13] really delete key pair --- moto/ec2/models.py | 6 +++--- moto/ec2/responses/key_pairs.py | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index b3ac035b..3eaa1a4d 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -176,9 +176,9 @@ class KeyPairBackend(object): return keypair def delete_key_pair(self, name): - keypair = self.keypairs.pop(name) - keypair['name'] = name - return keypair + if name in self.keypairs: + self.keypairs.pop(name) + return True def describe_key_pairs(self, filter_names=None): results = [] diff --git a/moto/ec2/responses/key_pairs.py b/moto/ec2/responses/key_pairs.py index 68c25e71..0e5fc47a 100644 --- a/moto/ec2/responses/key_pairs.py +++ b/moto/ec2/responses/key_pairs.py @@ -18,7 +18,9 @@ class KeyPairs(BaseResponse): return template.render(**keypair) def delete_key_pair(self): - return Template(DELETE_KEY_PAIR_RESPONSE).render(success="true") + name = self.querystring.get('KeyName')[0] + success = str(ec2_backend.delete_key_pair(name)).lower() + return Template(DELETE_KEY_PAIR_RESPONSE).render(success=success) def describe_key_pairs(self): template = Template(DESCRIBE_KEY_PAIRS_RESPONSE) From e19967b7d5b7251a471dda8e1c33aa16ed05135e Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 15:22:08 +0200 Subject: [PATCH 12/13] support names in DescribeKeyPairs --- moto/ec2/responses/key_pairs.py | 17 +++++++++++++++-- moto/ec2/utils.py | 9 +++++++++ tests/test_ec2/test_key_pairs.py | 3 +++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/moto/ec2/responses/key_pairs.py b/moto/ec2/responses/key_pairs.py index 0e5fc47a..d03a10e3 100644 --- a/moto/ec2/responses/key_pairs.py +++ b/moto/ec2/responses/key_pairs.py @@ -2,6 +2,7 @@ from jinja2 import Template from moto.core.responses import BaseResponse from moto.ec2.models import ec2_backend from moto.ec2.exceptions import InvalidIdError +from moto.ec2.utils import keypair_names_from_querystring class KeyPairs(BaseResponse): @@ -23,8 +24,15 @@ class KeyPairs(BaseResponse): return Template(DELETE_KEY_PAIR_RESPONSE).render(success=success) def describe_key_pairs(self): - template = Template(DESCRIBE_KEY_PAIRS_RESPONSE) - return template.render(keypairs=ec2_backend.describe_key_pairs()) + names = keypair_names_from_querystring(self.querystring) + try: + keypairs = ec2_backend.describe_key_pairs(names) + except InvalidIdError as exc: + template = Template(CREATE_KEY_PAIR_NOT_FOUND) + return template.render(keypair_id=exc.id), dict(status=400) + else: + template = Template(DESCRIBE_KEY_PAIRS_RESPONSE) + return template.render(keypairs=keypairs) def import_key_pair(self): raise NotImplementedError('KeyPairs.import_key_pair is not yet implemented') @@ -58,6 +66,11 @@ CREATE_KEY_PAIR_INVALID_NAME = """ """ +CREATE_KEY_PAIR_NOT_FOUND = """ +InvalidKeyPair.NotFoundThe keypair '{{ keypair_id }}' does not exist.f4f76e81-8ca5-4e61-a6d5-a4a96EXAMPLE +""" + + DELETE_KEY_PAIR_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE {{ success }} diff --git a/moto/ec2/utils.py b/moto/ec2/utils.py index 385f4cce..dc569783 100644 --- a/moto/ec2/utils.py +++ b/moto/ec2/utils.py @@ -116,6 +116,15 @@ def filters_from_querystring(querystring_dict): return response_values +def keypair_names_from_querystring(querystring_dict): + keypair_names = [] + for key, value in querystring_dict.iteritems(): + if 'KeyName' in key: + keypair_names.append(value[0]) + return keypair_names + + + filter_dict_attribute_mapping = { 'instance-state-name': 'state' } diff --git a/tests/test_ec2/test_key_pairs.py b/tests/test_ec2/test_key_pairs.py index 18bc0865..e43718ad 100644 --- a/tests/test_ec2/test_key_pairs.py +++ b/tests/test_ec2/test_key_pairs.py @@ -31,6 +31,9 @@ def test_key_pairs_create_two(): assert len(kps) == 2 assert kps[0].name == 'foo' assert kps[1].name == 'bar' + kps = conn.get_all_key_pairs('foo') + assert len(kps) == 1 + assert kps[0].name == 'foo' @mock_ec2 From 8db40978611e86cda42aedc1fb5eef34e7a1176d Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Mon, 24 Feb 2014 16:35:03 +0200 Subject: [PATCH 13/13] raise NotImplementedError when Filters are used in describe_key_pairs --- moto/ec2/responses/key_pairs.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/moto/ec2/responses/key_pairs.py b/moto/ec2/responses/key_pairs.py index d03a10e3..9c8686c8 100644 --- a/moto/ec2/responses/key_pairs.py +++ b/moto/ec2/responses/key_pairs.py @@ -2,7 +2,7 @@ from jinja2 import Template from moto.core.responses import BaseResponse from moto.ec2.models import ec2_backend from moto.ec2.exceptions import InvalidIdError -from moto.ec2.utils import keypair_names_from_querystring +from moto.ec2.utils import keypair_names_from_querystring, filters_from_querystring class KeyPairs(BaseResponse): @@ -25,6 +25,10 @@ class KeyPairs(BaseResponse): def describe_key_pairs(self): names = keypair_names_from_querystring(self.querystring) + filters = filters_from_querystring(self.querystring) + if len(filters) > 0: + raise NotImplementedError('Using filters in KeyPairs.describe_key_pairs is not yet implemented') + try: keypairs = ec2_backend.describe_key_pairs(names) except InvalidIdError as exc: