diff --git a/moto/core/responses.py b/moto/core/responses.py index a5a1f3880..adad5d1de 100644 --- a/moto/core/responses.py +++ b/moto/core/responses.py @@ -1,4 +1,6 @@ from __future__ import unicode_literals + +from collections import defaultdict import datetime import json import logging @@ -330,6 +332,26 @@ class BaseResponse(_TemplateEnvironmentMixin): return results + def _parse_tag_specification(self, param_prefix): + tags = self._get_list_prefix(param_prefix) + + results = defaultdict(dict) + for tag in tags: + resource_type = tag.pop("resource_type") + + param_index = 1 + while True: + key_name = 'tag.{0}._key'.format(param_index) + value_name = 'tag.{0}._value'.format(param_index) + + try: + results[resource_type][tag[key_name]] = tag[value_name] + except KeyError: + break + param_index += 1 + + return results + @property def request_json(self): return 'JSON' in self.querystring.get('ContentType', []) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 8be13d867..87d2d59e5 100755 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -141,6 +141,10 @@ class TaggedEC2Resource(BaseModel): def add_tag(self, key, value): self.ec2_backend.create_tags([self.id], {key: value}) + def add_tags(self, tag_map): + for key, value in tag_map.items(): + self.ec2_backend.create_tags([self.id], {key: value}) + def get_filter_value(self, filter_name): tags = self.get_tags() @@ -638,6 +642,10 @@ class InstanceBackend(object): security_groups.extend(self.get_security_group_from_id(sg_id) for sg_id in kwargs.pop("security_group_ids", [])) self.reservations[new_reservation.id] = new_reservation + + tags = kwargs.pop("tags", {}) + instance_tags = tags.get('instance', {}) + for index in range(count): new_instance = Instance( self, @@ -647,6 +655,7 @@ class InstanceBackend(object): **kwargs ) new_reservation.instances.append(new_instance) + new_instance.add_tags(instance_tags) new_instance.setup_defaults() return new_reservation diff --git a/moto/ec2/responses/instances.py b/moto/ec2/responses/instances.py index d964fc22b..09ecb172b 100644 --- a/moto/ec2/responses/instances.py +++ b/moto/ec2/responses/instances.py @@ -47,13 +47,15 @@ class InstanceResponse(BaseResponse): associate_public_ip = self.querystring.get( "AssociatePublicIpAddress", [None])[0] key_name = self.querystring.get("KeyName", [None])[0] + tags = self._parse_tag_specification("TagSpecification") if self.is_not_dryrun('RunInstance'): new_reservation = self.ec2_backend.add_instances( image_id, min_count, user_data, security_group_names, instance_type=instance_type, placement=placement, subnet_id=subnet_id, key_name=key_name, security_group_ids=security_group_ids, - nics=nics, private_ip=private_ip, associate_public_ip=associate_public_ip) + nics=nics, private_ip=private_ip, associate_public_ip=associate_public_ip, + tags=tags) template = self.response_template(EC2_RUN_INSTANCES) return template.render(reservation=new_reservation) @@ -282,6 +284,14 @@ EC2_RUN_INSTANCES = """