Repository: ansible/ansible

Issue:
ec2_vpc_igw 412 Precondition Failed
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
ec2_vpc_igw

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.1.0
  config file = /Users/tom/repos/aws-codecommit/ansible-tower/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.10 (default, Feb  6 2017, 23:53:20) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)]
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
Using latest commit of `ec2_vpc_igw` (supports tagging).

https://github.com/ansible/ansible/blob/225fa5d09229bd673ea76f8b8bc8e7d8b50d2399/lib/ansible/modules/cloud/amazon/ec2_vpc_igw.py

##### SUMMARY
<!--- Explain the problem briefly -->
Running ec2_vpc_igw with `--check` produces an error.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

Add a gateway to an existing VPC with an existing gateway, using check mode (`--check`)

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: add internet gateway to VPC
  ec2_vpc_igw:
    region: us-west-1
    vpc_id: vpc-123456
    tags:
      foo: bar
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
The task is skipped if check mode is not supported. Or OK, or CHANGED if it is supported.

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
Fatal error.

<!--- Paste verbatim command output between quotes below -->
```
fatal: [localhost]: FAILED! => {
    "changed": false,
    "failed": true,
    "invocation": {
        "module_args": {
            "aws_access_key": null,
            "aws_secret_key": null,
            "ec2_url": null,
            "profile": null,
            "region": "us-west-1",
            "security_token": null,
            "state": "present",
            "tags": {
                "foo": "bar"
            },
            "validate_certs": true,
            "vpc_id": "vpc-123456"
        }
    },
    "msg": "Unable to update tags for igw-123456, error: EC2ResponseError: 412 Precondition Failed\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response><Errors><Error><Code>DryRunOperation</Code><Message>Request would have succeeded, but DryRun flag is set.</Message></Error></Errors><RequestID>c9b3b77c-4520-4c00-915d-97191297cebc</RequestID></Response>"
}
```

Possibly related (similar error messages, different modules):

https://github.com/ansible/ansible/pull/23113
https://github.com/ansible/ansible/pull/23108
ec2_vpc_igw 412 Precondition Failed
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
ec2_vpc_igw

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.1.0
  config file = /Users/tom/repos/aws-codecommit/ansible-tower/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.10 (default, Feb  6 2017, 23:53:20) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)]
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
Using latest commit of `ec2_vpc_igw` (supports tagging).

https://github.com/ansible/ansible/blob/225fa5d09229bd673ea76f8b8bc8e7d8b50d2399/lib/ansible/modules/cloud/amazon/ec2_vpc_igw.py

##### SUMMARY
<!--- Explain the problem briefly -->
Running ec2_vpc_igw with `--check` produces an error.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

Add a gateway to an existing VPC with an existing gateway, using check mode (`--check`)

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: add internet gateway to VPC
  ec2_vpc_igw:
    region: us-west-1
    vpc_id: vpc-123456
    tags:
      foo: bar
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
The task is skipped if check mode is not supported. Or OK, or CHANGED if it is supported.

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
Fatal error.

<!--- Paste verbatim command output between quotes below -->
```
fatal: [localhost]: FAILED! => {
    "changed": false,
    "failed": true,
    "invocation": {
        "module_args": {
            "aws_access_key": null,
            "aws_secret_key": null,
            "ec2_url": null,
            "profile": null,
            "region": "us-west-1",
            "security_token": null,
            "state": "present",
            "tags": {
                "foo": "bar"
            },
            "validate_certs": true,
            "vpc_id": "vpc-123456"
        }
    },
    "msg": "Unable to update tags for igw-123456, error: EC2ResponseError: 412 Precondition Failed\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response><Errors><Error><Code>DryRunOperation</Code><Message>Request would have succeeded, but DryRun flag is set.</Message></Error></Errors><RequestID>c9b3b77c-4520-4c00-915d-97191297cebc</RequestID></Response>"
}
```

Possibly related (similar error messages, different modules):

https://github.com/ansible/ansible/pull/23113
https://github.com/ansible/ansible/pull/23108


Discussion:
cc @willthames
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
cc @willthames
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/cloud/amazon/ec2_vpc_igw.py b/lib/ansible/modules/cloud/amazon/ec2_vpc_igw.py
--- a/lib/ansible/modules/cloud/amazon/ec2_vpc_igw.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_vpc_igw.py
@@ -127,14 +127,26 @@ def ensure_tags(vpc_conn, resource_id, tags, add_only, check_mode):
         if cur_tags == tags:
             return {'changed': False, 'tags': cur_tags}
 
+        if check_mode:
+            latest_check_mode_tags = cur_tags
+
         to_delete = dict((k, cur_tags[k]) for k in cur_tags if k not in tags)
         if to_delete and not add_only:
-            vpc_conn.delete_tags(resource_id, to_delete, dry_run=check_mode)
+            if check_mode:
+                # just overwriting latest_check_mode_tags instead of deleting keys
+                latest_check_mode_tags = dict((k, cur_tags[k]) for k in cur_tags if k not in to_delete)
+            else:
+                vpc_conn.delete_tags(resource_id, to_delete)
 
         to_add = dict((k, tags[k]) for k in tags if k not in cur_tags or cur_tags[k] != tags[k])
         if to_add:
-            vpc_conn.create_tags(resource_id, to_add, dry_run=check_mode)
+            if check_mode:
+                latest_check_mode_tags.update(to_add)
+            else:
+                vpc_conn.create_tags(resource_id, to_add)
 
+        if check_mode:
+            return {'changed': True, 'tags': latest_check_mode_tags}
         latest_tags = get_resource_tags(vpc_conn, resource_id)
         return {'changed': True, 'tags': latest_tags}
     except EC2ResponseError as e:
@@ -187,6 +199,11 @@ def ensure_igw_present(vpc_conn, vpc_id, tags, check_mode):
     igw.vpc_id = vpc_id
 
     if tags != igw.tags:
+        if check_mode:
+            check_mode_tags = ensure_tags(vpc_conn, igw.id, tags, False, check_mode)
+            igw_info = get_igw_info(igw)
+            igw_info.get('tags', {}).update(check_mode_tags.get('tags', {}))
+            return {'changed': True, 'gateway': igw_info}
         ensure_tags(vpc_conn, igw.id, tags, False, check_mode)
         igw.tags = tags
         changed = True


Test patch: