From 955b4c6c4a368ab77fb3bc2d25baf2fae9861d43 Mon Sep 17 00:00:00 2001 From: Steve Pulec Date: Sun, 11 May 2014 19:00:28 -0400 Subject: [PATCH] Add tagging to all applicable EC2 objects. Closes #66. --- moto/ec2/models.py | 24 +++++++++++++----------- moto/ec2/responses/amis.py | 11 ++++++++++- moto/ec2/responses/dhcp_options.py | 28 +++++++++++++++++++++++----- moto/ec2/responses/subnets.py | 22 ++++++++++++++++++++-- moto/ec2/responses/vpcs.py | 22 ++++++++++++++++++++-- tests/test_ec2/test_amis.py | 20 ++++++++++++++++++++ tests/test_ec2/test_dhcp_options.py | 19 ++++++++++++++++++- tests/test_ec2/test_subnets.py | 18 ++++++++++++++++++ tests/test_ec2/test_vpcs.py | 17 +++++++++++++++++ 9 files changed, 159 insertions(+), 22 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index d40c21f57..440c1c5a2 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -36,7 +36,13 @@ class InstanceState(object): self.code = code -class Instance(BotoInstance): +class TaggedEC2Instance(object): + def get_tags(self, *args, **kwargs): + tags = ec2_backend.describe_tags(self.id) + return tags + + +class Instance(BotoInstance, TaggedEC2Instance): def __init__(self, image_id, user_data, security_groups, **kwargs): super(Instance, self).__init__() self.id = random_instance_id() @@ -86,10 +92,6 @@ class Instance(BotoInstance): self._state.name = "running" self._state.code = 16 - def get_tags(self, *args, **kwargs): - tags = ec2_backend.describe_tags(self.id) - return tags - class InstanceBackend(object): @@ -267,7 +269,7 @@ class TagBackend(object): return results -class Ami(object): +class Ami(TaggedEC2Instance): def __init__(self, ami_id, instance, name, description): self.id = ami_id self.instance = instance @@ -657,7 +659,7 @@ class EBSBackend(object): return False -class VPC(object): +class VPC(TaggedEC2Instance): def __init__(self, vpc_id, cidr_block): self.id = vpc_id self.cidr_block = cidr_block @@ -703,7 +705,7 @@ class VPCBackend(object): return vpc -class Subnet(object): +class Subnet(TaggedEC2Instance): def __init__(self, subnet_id, vpc_id, cidr_block): self.id = subnet_id self.vpc_id = vpc_id @@ -1061,7 +1063,7 @@ class ElasticAddressBackend(object): return False -class DHCPOptionsSet(object): +class DHCPOptionsSet(TaggedEC2Instance): def __init__(self, domain_name_servers=None, domain_name=None, ntp_servers=None, netbios_name_servers=None, netbios_node_type=None): @@ -1071,7 +1073,7 @@ class DHCPOptionsSet(object): "ntp-servers": ntp_servers, "netbios-name-servers": netbios_name_servers, "netbios-node-type": netbios_node_type, - } + } self.id = random_dhcp_option_id() self.vpc = None @@ -1113,7 +1115,7 @@ class DHCPOptionsSetBackend(object): if options_id in self.dhcp_options_sets: if self.dhcp_options_sets[options_id].vpc: raise DependencyViolationError("Cannot delete assigned DHCP options.") - dhcp_opt = self.dhcp_options_sets.pop(options_id) + self.dhcp_options_sets.pop(options_id) else: raise InvalidDHCPOptionsIdError(options_id) return True diff --git a/moto/ec2/responses/amis.py b/moto/ec2/responses/amis.py index fc1e95db2..60615cd5a 100644 --- a/moto/ec2/responses/amis.py +++ b/moto/ec2/responses/amis.py @@ -92,7 +92,16 @@ DESCRIBE_IMAGES_RESPONSE = """ - + + {% for tag in dhcp_options_set.get_tags() %} + + {{ tag.resource_id }} + {{ tag.resource_type }} + {{ tag.key }} + {{ tag.value }} + + {% endfor %} + """ @@ -141,7 +150,16 @@ DESCRIBE_DHCP_OPTIONS_RESPONSE = u""" {% endif %} {% endfor %} - + + {% for tag in dhcp_options_set.get_tags() %} + + {{ tag.resource_id }} + {{ tag.resource_type }} + {{ tag.key }} + {{ tag.value }} + + {% endfor %} + {% endfor %} diff --git a/moto/ec2/responses/subnets.py b/moto/ec2/responses/subnets.py index c4fce1662..5ad5b6d4c 100644 --- a/moto/ec2/responses/subnets.py +++ b/moto/ec2/responses/subnets.py @@ -37,7 +37,16 @@ CREATE_SUBNET_RESPONSE = """ {{ subnet.cidr_block }} 251 us-east-1a - + + {% for tag in subnet.get_tags() %} + + {{ tag.resource_id }} + {{ tag.resource_type }} + {{ tag.key }} + {{ tag.value }} + + {% endfor %} + """ @@ -59,7 +68,16 @@ DESCRIBE_SUBNETS_RESPONSE = """ {{ subnet.cidr_block }} 251 us-east-1a - + + {% for tag in subnet.get_tags() %} + + {{ tag.resource_id }} + {{ tag.resource_type }} + {{ tag.key }} + {{ tag.value }} + + {% endfor %} + {% endfor %} diff --git a/moto/ec2/responses/vpcs.py b/moto/ec2/responses/vpcs.py index 1decdb33c..ca50869c8 100644 --- a/moto/ec2/responses/vpcs.py +++ b/moto/ec2/responses/vpcs.py @@ -35,7 +35,16 @@ CREATE_VPC_RESPONSE = """ {{ vpc.cidr_block }} dopt-1a2b3c4d2 default - + + {% for tag in vpc.get_tags() %} + + {{ tag.resource_id }} + {{ tag.resource_type }} + {{ tag.key }} + {{ tag.value }} + + {% endfor %} + """ @@ -50,7 +59,16 @@ DESCRIBE_VPCS_RESPONSE = """ {{ vpc.cidr_block }} dopt-7a8b9c2d default - + + {% for tag in vpc.get_tags() %} + + {{ tag.resource_id }} + {{ tag.resource_type }} + {{ tag.key }} + {{ tag.value }} + + {% endfor %} + {% endfor %} diff --git a/tests/test_ec2/test_amis.py b/tests/test_ec2/test_amis.py index 365b0c242..d959f4c3f 100644 --- a/tests/test_ec2/test_amis.py +++ b/tests/test_ec2/test_amis.py @@ -22,6 +22,26 @@ def test_ami_create_and_delete(): success = conn.deregister_image.when.called_with(image).should.throw(EC2ResponseError) +@mock_ec2 +def test_ami_tagging(): + conn = boto.connect_vpc('the_key', 'the_secret') + reservation = conn.run_instances('ami-1234abcd') + instance = reservation.instances[0] + conn.create_image(instance.id, "test-ami", "this is a test ami") + image = conn.get_all_images()[0] + + image.add_tag("a key", "some value") + + tag = conn.get_all_tags()[0] + tag.name.should.equal("a key") + tag.value.should.equal("some value") + + # Refresh the DHCP options + image = conn.get_all_images()[0] + image.tags.should.have.length_of(1) + image.tags["a key"].should.equal("some value") + + @mock_ec2 def test_ami_create_from_missing_instance(): conn = boto.connect_ec2('the_key', 'the_secret') diff --git a/tests/test_ec2/test_dhcp_options.py b/tests/test_ec2/test_dhcp_options.py index 6ed5e5826..b05dc56a5 100644 --- a/tests/test_ec2/test_dhcp_options.py +++ b/tests/test_ec2/test_dhcp_options.py @@ -114,5 +114,22 @@ def test_delete_dhcp_options(): def test_delete_dhcp_options_invalid_id(): conn = boto.connect_vpc('the_key', 'the_secret') - dhcp_option = conn.create_dhcp_options() + conn.create_dhcp_options() conn.delete_dhcp_options.when.called_with("1").should.throw(EC2ResponseError) + + +@mock_ec2 +def test_dhcp_tagging(): + conn = boto.connect_vpc('the_key', 'the_secret') + dhcp_option = conn.create_dhcp_options() + + dhcp_option.add_tag("a key", "some value") + + tag = conn.get_all_tags()[0] + tag.name.should.equal("a key") + tag.value.should.equal("some value") + + # Refresh the DHCP options + dhcp_option = conn.get_all_dhcp_options()[0] + dhcp_option.tags.should.have.length_of(1) + dhcp_option.tags["a key"].should.equal("some value") diff --git a/tests/test_ec2/test_subnets.py b/tests/test_ec2/test_subnets.py index f12d35de5..1f08c1869 100644 --- a/tests/test_ec2/test_subnets.py +++ b/tests/test_ec2/test_subnets.py @@ -21,3 +21,21 @@ def test_subnets(): conn.delete_subnet.when.called_with( subnet.id).should.throw(EC2ResponseError) + + +@mock_ec2 +def test_subnet_tagging(): + conn = boto.connect_vpc('the_key', 'the_secret') + vpc = conn.create_vpc("10.0.0.0/16") + subnet = conn.create_subnet(vpc.id, "10.0.0.0/18") + + subnet.add_tag("a key", "some value") + + tag = conn.get_all_tags()[0] + tag.name.should.equal("a key") + tag.value.should.equal("some value") + + # Refresh the subnet + subnet = conn.get_all_subnets()[0] + subnet.tags.should.have.length_of(1) + subnet.tags["a key"].should.equal("some value") diff --git a/tests/test_ec2/test_vpcs.py b/tests/test_ec2/test_vpcs.py index 3a4570ecd..2c61b6d7a 100644 --- a/tests/test_ec2/test_vpcs.py +++ b/tests/test_ec2/test_vpcs.py @@ -21,3 +21,20 @@ def test_vpcs(): conn.delete_vpc.when.called_with( "vpc-1234abcd").should.throw(EC2ResponseError) + + +@mock_ec2 +def test_vpc_tagging(): + conn = boto.connect_vpc() + vpc = conn.create_vpc("10.0.0.0/16") + + vpc.add_tag("a key", "some value") + + tag = conn.get_all_tags()[0] + tag.name.should.equal("a key") + tag.value.should.equal("some value") + + # Refresh the vpc + vpc = conn.get_all_vpcs()[0] + vpc.tags.should.have.length_of(1) + vpc.tags["a key"].should.equal("some value")