Repository: ansible-collections/amazon.aws

Issue:
ec2_vol doesn't report volume changes properly
### Summary

When `modify_volume` is used but no new disk is being attached, the module incorrectly reports that no change has occurred even when disks have been modified (iops, throughput, type, etc.). This is due to the attach function overwriting the `changed` variable even if no disks are attached:

https://github.com/ansible-collections/amazon.aws/blob/e8df91778ee808bfbfa7008c855a3bda92bf4c01/plugins/modules/ec2_vol.py#L812-L830

Locally I have used the following workaround as a fix:

```python
        if detach_vol_flag:
            volume, changed = detach_volume(module, ec2_conn, volume_dict=volume)
        elif inst is not None:
            volume, vol_attached = attach_volume(module, ec2_conn, volume_dict=volume, instance_dict=inst, device_name=device_name)

        # Add device, volume_id and volume_type parameters separately to maintain backward compatibility
        volume_info = get_volume_info(module, volume, tags=final_tags)

        if tags_changed or vol_attached:
            changed = True
```

I am happy to make a PR with this change if this is an acceptable route to go down.

### Issue Type

Bug Report

### Component Name

ec2_vol

### Ansible Version

```console (paste below)
ansible 2.9.9
```



### Collection Versions

```console (paste below)
Collection        Version
----------------- -------
amazon.aws        1.5.0
```


### AWS SDK versions

```console (paste below)
Name: boto
Version: 2.49.0
Summary: Amazon Web Services Library
Home-page: https://github.com/boto/boto/
Author: Mitch Garnaat
Author-email: mitch@garnaat.com
License: MIT
Location: /Users/john.mccall/.pyenv/versions/3.6.5/lib/python3.6/site-packages
Requires: 
Required-by: 
---
Name: boto3
Version: 1.18.31
Summary: The AWS SDK for Python
Home-page: https://github.com/boto/boto3
Author: Amazon Web Services
Author-email: 
License: Apache License 2.0
Location: /Users/john.mccall/.pyenv/versions/3.6.5/lib/python3.6/site-packages
Requires: botocore, jmespath, s3transfer
Required-by: 
---
Name: botocore
Version: 1.21.31
Summary: Low-level, data-driven core of boto 3.
Home-page: https://github.com/boto/botocore
Author: Amazon Web Services
Author-email: 
License: Apache License 2.0
Location: /Users/john.mccall/.pyenv/versions/3.6.5/lib/python3.6/site-packages
Requires: jmespath, urllib3, python-dateutil
Required-by: s3transfer, boto3
```


### Configuration

N/A


### OS / Environment

MacOS

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
amazon.aws.ec2_vol:
        region: "region-name"
        name: "disk-name"
        device_name: "device-name"
        volume_type: gp3
        volume_size: 50
        iops: 126
        throughput: 3001
        modify_volume: true
```

Run something similar to the above example to upgrade an existing attached gp2 volume to gp3, along with non-default iops and throughput. The module will make the changes correctly but mark the volume as "ok" instead of "changed" in the results. 

### Expected Results

I expect the module to report back `changed: true` when modifying the type, iops, etc. of an already-attached ebs volume.

### Actual Results

Module reports `changed: false` when modifying the type, iops, etc. of an already-attached ebs volume.


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/ec2_vol.py`](https://github.com/['ansible-collections/amazon.aws', 'ansible-collections/community.aws', 'ansible-collections/community.vmware']/blob/main/plugins/modules/ec2_vol.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @jillr @lwade @s-hertel @tremble @wimnat
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Hi @LowlyDBA 
Thanks for taking the time to report this issue.
You can submit a PR and we will review it.

Thanks again
@LowlyDBA,

PRs are always welcome.  If you've taken "the wrong" approach we'll generally try to explain why and what the better approach would be.

A couple of things to speed up the approval/merging of the PR:

1. For bugfixes and features, please add a [changelog fragment](https://docs.ansible.com/ansible/latest/community/development_process.html#changelogs-how-to) Note: We use fragments rather than updating the main changelog doc, and the release process will merge them into the main changelog.
2. Please update the [ec2_vol integration tests](https://github.com/ansible-collections/amazon.aws/blob/main/tests/integration/targets/ec2_vol/tasks/tests.yml) to help avoid a regression creeping in over time.  These tests are just an Ansible role which is run in a CI AWS account.

Resolving patch:
diff --git a/plugins/modules/ec2_vol.py b/plugins/modules/ec2_vol.py
--- a/plugins/modules/ec2_vol.py
+++ b/plugins/modules/ec2_vol.py
@@ -740,14 +740,16 @@ def main():
         final_tags, tags_changed = ensure_tags(module, ec2_conn, volume['volume_id'], 'volume', tags, module.params.get('purge_tags'))
 
         if detach_vol_flag:
-            volume, changed = detach_volume(module, ec2_conn, volume_dict=volume)
+            volume, attach_changed = detach_volume(module, ec2_conn, volume_dict=volume)
         elif inst is not None:
-            volume, changed = attach_volume(module, ec2_conn, volume_dict=volume, instance_dict=inst, device_name=device_name)
+            volume, attach_changed = attach_volume(module, ec2_conn, volume_dict=volume, instance_dict=inst, device_name=device_name)
+        else:
+            attach_changed = False
 
         # Add device, volume_id and volume_type parameters separately to maintain backward compatibility
         volume_info = get_volume_info(volume, tags=final_tags)
 
-        if tags_changed:
+        if tags_changed or attach_changed:
             changed = True
 
         module.exit_json(changed=changed, volume=volume_info, device=volume_info['attachment_set']['device'],


Test patch:
diff --git a/tests/integration/targets/ec2_vol/tasks/tests.yml b/tests/integration/targets/ec2_vol/tasks/tests.yml
--- a/tests/integration/targets/ec2_vol/tasks/tests.yml
+++ b/tests/integration/targets/ec2_vol/tasks/tests.yml
@@ -203,7 +203,7 @@
       assert:
         that:
           - "not vol_attach_result.changed"
-          - "vol_attach_result.volume.attachment_set.status == 'attached'"
+          - vol_attach_result.volume.attachment_set.status in ['attached', 'attaching']
 
     - name: attach a new volume to an instance
       ec2_vol:
@@ -330,29 +330,6 @@
         that:
           - ec2_vol_info.volumes | length == 4
 
-    - name: detach volume from the instance
-      ec2_vol:
-        id: "{{ new_vol_attach_result.volume_id }}"
-        instance: ""
-      register: new_vol_attach_result
-
-    - name: check task return attributes
-      assert:
-        that:
-          - new_vol_attach_result.changed
-          - new_vol_attach_result.volume.status == 'available'
-
-    - name: detach volume from the instance (idempotent)
-      ec2_vol:
-        id: "{{ new_vol_attach_result.volume_id }}"
-        instance: ""
-      register: new_vol_attach_result_idem
-
-    - name: check task return attributes
-      assert:
-        that:
-          - not new_vol_attach_result_idem.changed
-
     - name: must not change because of missing parameter modify_volume
       ec2_vol:
         id: "{{ new_vol_attach_result.volume_id }}"
@@ -414,7 +391,30 @@
           - v.type == 'gp3'
       vars:
         v: "{{ verify_gp3_change.volumes[0] }}"
+        
+    - name: detach volume from the instance
+      ec2_vol:
+        id: "{{ new_vol_attach_result.volume_id }}"
+        instance: ""
+      register: new_vol_attach_result
+
+    - name: check task return attributes
+      assert:
+        that:
+          - new_vol_attach_result.changed
+          - new_vol_attach_result.volume.status == 'available'
 
+    - name: detach volume from the instance (idempotent)
+      ec2_vol:
+        id: "{{ new_vol_attach_result.volume_id }}"
+        instance: ""
+      register: new_vol_attach_result_idem
+
+    - name: check task return attributes
+      assert:
+        that:
+          - not new_vol_attach_result_idem.changed
+          
     - name: delete volume
       ec2_vol:
         id: "{{ volume2.volume_id }}"