Repository: ansible/ansible-modules-core

Issue:
ec2_vpc module will not update subnet tags
#### Issue Type:

Bug Report
##### Ansible Version:

ansible 1.9.0.1
##### Environment:

n/a
##### Summary:

When declaring a VPC with existing subnets that match the declared CIDR blocks, but have _different tags_, the module ignores the tags.

(Looking at the code, the same thing seems to be the case for AZs, but I haven't run into that issue myself.)
##### Steps To Reproduce:

Assuming we've got a VPC with the `10.0.0.0/16` block, tagged `Name="myvpc"`. The VPC has 1 subnet for the `10.0.1.0/24` block, tagged `Name="wrongname"`.

Running this task:

```
- ec2_vpc:
  cidr_block: 10.0.0.0/16
  region: "{{ ec2_region }}"
  resource_tags:
    Name: myvpc
  subnets:
    - cidr: 10.0.1.0/24
      az: "{{ ec2_availability_zone }}"
      resource_tags:
        Name: great_subnet_name
```

will not change the tag value for the subnet.  
##### Expected Results:

After running the task, the `10.0.1.0/24` subnet should have the tag `Name="great_subnet_name"`.
##### Actual Results:

It has the tag `Name="wrongname"`.



Discussion:
+1

+1

One thing to note after poking around the code for this module and additional testing so far is that it does update the tags upon creation of a new subnet, but once that subnet has been created it does not make additional updates when resource tags are modified. I am continuing to look into this bug, and will likely just be a matter of adding a condition to make sure they get updated outside of new subnet creation if the tags are different. This is present in the latest version of Ansible as well (2.1.0 (devel 15135f3c16) last updated 2015/12/16) on CentOS 7.1. 


Resolving patch:
diff --git a/cloud/amazon/ec2_vpc.py b/cloud/amazon/ec2_vpc.py
--- a/cloud/amazon/ec2_vpc.py
+++ b/cloud/amazon/ec2_vpc.py
@@ -46,9 +46,10 @@
     choices: [ "yes", "no" ]
   subnets:
     description:
-      - 'A dictionary array of subnets to add of the form: { cidr: ..., az: ... , resource_tags: ... }. Where az is the desired availability zone of the subnet, but it is not required. Tags (i.e.: resource_tags) is also optional and use dictionary form: { "Environment":"Dev", "Tier":"Web", ...}. All VPC subnets not in this list will be removed. As of 1.8, if the subnets parameter is not specified, no existing subnets will be modified.'
+      - 'A dictionary array of subnets to add of the form: { cidr: ..., az: ... , resource_tags: ... }. Where az is the desired availability zone of the subnet, but it is not required. Tags (i.e.: resource_tags) is also optional and use dictionary form: { "Environment":"Dev", "Tier":"Web", ...}. All VPC subnets not in this list will be removed as well. As of 1.8, if the subnets parameter is not specified, no existing subnets will be modified.'
     required: false
     default: null
+    resource_tags: See resource_tags for VPC below. The main difference is subnet tags not specified here will be deleted. 
   vpc_id:
     description:
       - A VPC id to terminate when state=absent
@@ -406,9 +407,39 @@ def create_vpc(module, vpc_conn):
         # First add all new subnets
         for subnet in subnets:
             add_subnet = True
+            subnet_tags_current = True
+            new_subnet_tags = subnet.get('resource_tags', None)
+            subnet_tags_delete = []
+            
             for csn in current_subnets:
                 if subnet['cidr'] == csn.cidr_block:
                     add_subnet = False
+
+                # Check if AWS subnet tags are in playbook subnet tags
+                subnet_tags_extra = (set(csn.tags.items()).issubset(set(new_subnet_tags.items())))
+                # Check if subnet tags in playbook are in AWS subnet tags 
+                subnet_tags_current = (set(new_subnet_tags.items()).issubset(set(csn.tags.items())))
+                if subnet_tags_extra is False:
+                    try:
+                        for item in csn.tags.items():
+                            if item not in new_subnet_tags.items():
+                                subnet_tags_delete.append(item)
+
+                        subnet_tags_delete = [key[0] for key in subnet_tags_delete]
+                        delete_subnet_tag = vpc_conn.delete_tags(csn.id, subnet_tags_delete)
+                        changed = True
+                    except EC2ResponseError, e:
+                        module.fail_json(msg='Unable to delete resource tag, error {0}'.format(e))
+                # Add new subnet tags if not current
+                subnet_tags_current = (set(new_subnet_tags.items()).issubset(set(csn.tags.items())))
+                if subnet_tags_current is not True:
+                    try:
+                        changed = True
+                        create_subnet_tag = vpc_conn.create_tags(csn.id, new_subnet_tags)
+
+                    except EC2ResponseError, e:
+                        module.fail_json(msg='Unable to create resource tag, error: {0}'.format(e))
+
             if add_subnet:
                 try:
                     new_subnet = vpc_conn.create_subnet(vpc.id, subnet['cidr'], subnet.get('az', None))


Test patch: