Repository: ansible/ansible-modules-core

Issue:
ec2 module - dont modify termination protection
##### ISSUE TYPE
- Feature Idea
##### COMPONENT NAME

ec2
##### ANSIBLE VERSION

```
ansible 2.0.1.0
```
##### OS / ENVIRONMENT

N/A
##### SUMMARY

I was using ansible v1.9.4 to start/stop servers using a playbook. I've recently updated to ansible v2.0.1.0 however the termination_protection option defaults to "no" therefore it tries to disable termination protection on some servers. The playbook sole purpose is to start/stop servers therefore I do not want to enable or disable termination protection. I just want to leave it configured the way it is configured.
##### STEPS TO REPRODUCE

```
- name: start ec2 instance
  hosts: all
  gather_facts: False
  connection: local
  tasks:
    - name: start ec2 instance
      ec2:
        instance_ids: '{{ ec2_id }}'
        region: 'eu-west-1'
        aws_access_key: '{{ aws_access_key }}'
        aws_secret_key: '{{ aws_secret_key }}'
        state: running
        wait: True
```
##### EXPECTED RESULTS

Starts ec2 instance and not modify termination protection
##### ACTUAL RESULTS

Starts ec2 instance and modified termination protection



Discussion:
Having the same issue here. Looks like it's simply setting it to the default value when you don't explicitly specify the protection [1]. This feels completely silly though, I've already set it to protect me when I created the instance - so no need to touch this again.

Moreover, this feels like a bug since Ansible is resetting a parameter that has nothing to do with the operation at hand.

[1] https://github.com/ansible/ansible-modules-core/blob/devel/cloud/amazon/ec2.py#L1299

@ansible, ping. This issue is still waiting on your response.
[click here for bot help](https://github.com/jctanner/ansibullbot/blob/ISSUE_TRIAGE_CLASS/ISSUE_HELP.md)

<!--- boilerplate: issue_renotify_maintainer --->

@ansible, ping. This issue is still waiting on your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_renotify_maintainer --->


Resolving patch:
diff --git a/cloud/amazon/ec2.py b/cloud/amazon/ec2.py
--- a/cloud/amazon/ec2.py
+++ b/cloud/amazon/ec2.py
@@ -1328,7 +1328,8 @@ def startstop_instances(module, ec2, instance_ids, state, instance_tags):
                                      exception=traceback.format_exc(exc))
 
             # Check "termination_protection" attribute
-            if inst.get_attribute('disableApiTermination')['disableApiTermination'] != termination_protection:
+            if (inst.get_attribute('disableApiTermination')['disableApiTermination'] != termination_protection
+                    and termination_protection is not None):
                 inst.modify_attribute('disableApiTermination', termination_protection)
                 changed = True
 
@@ -1395,8 +1396,6 @@ def restart_instances(module, ec2, instance_ids, state, instance_tags):
     termination_protection = module.params.get('termination_protection')
     changed = False
     instance_dict_array = []
-    source_dest_check = module.params.get('source_dest_check')
-    termination_protection = module.params.get('termination_protection')
 
     if not isinstance(instance_ids, list) or len(instance_ids) < 1:
         # Fail unless the user defined instance tags
@@ -1414,17 +1413,30 @@ def restart_instances(module, ec2, instance_ids, state, instance_tags):
      # Check that our instances are not in the state we want to take
 
     # Check (and eventually change) instances attributes and instances state
-    running_instances_array = []
     for res in ec2.get_all_instances(instance_ids, filters=filters):
         for inst in res.instances:
 
             # Check "source_dest_check" attribute
-            if inst.get_attribute('sourceDestCheck')['sourceDestCheck'] != source_dest_check:
-                inst.modify_attribute('sourceDestCheck', source_dest_check)
-                changed = True
+            try:
+                if inst.vpc_id is not None and inst.get_attribute('sourceDestCheck')['sourceDestCheck'] != source_dest_check:
+                    inst.modify_attribute('sourceDestCheck', source_dest_check)
+                    changed = True
+            except boto.exception.EC2ResponseError as exc:
+                # instances with more than one Elastic Network Interface will
+                # fail, because they have the sourceDestCheck attribute defined
+                # per-interface
+                if exc.code == 'InvalidInstanceID':
+                    for interface in inst.interfaces:
+                        if interface.source_dest_check != source_dest_check:
+                            ec2.modify_network_interface_attribute(interface.id, "sourceDestCheck", source_dest_check)
+                            changed = True
+                else:
+                    module.fail_json(msg='Failed to handle source_dest_check state for instance {0}, error: {1}'.format(inst.id, exc),
+                                     exception=traceback.format_exc(exc))
 
             # Check "termination_protection" attribute
-            if inst.get_attribute('disableApiTermination')['disableApiTermination'] != termination_protection:
+            if (inst.get_attribute('disableApiTermination')['disableApiTermination'] != termination_protection
+                    and termination_protection is not None):
                 inst.modify_attribute('disableApiTermination', termination_protection)
                 changed = True
 
@@ -1469,7 +1481,7 @@ def main():
             instance_profile_name = dict(),
             instance_ids = dict(type='list', aliases=['instance_id']),
             source_dest_check = dict(type='bool', default=True),
-            termination_protection = dict(type='bool', default=False),
+            termination_protection = dict(type='bool', default=None),
             state = dict(default='present', choices=['present', 'absent', 'running', 'restarted', 'stopped']),
             instance_initiated_shutdown_behavior=dict(default=None, choices=['stop', 'terminate']),
             exact_count = dict(type='int', default=None),


Test patch: