Repository: ansible-collections/amazon.aws

Issue:
s3_bucket.destroy_bucket fails to delete unversioned items
### Summary

aws s3_client.list_object_versions() now (at least as of boto3 1.26.129) returns "VersionId": "null" for those objects that have no versions.  Per the code in s3_bucket.destroy_bucket (lines 1161-1167) previously it did not return a "VersionId" if there was no versioning and so it popped those `None` values.  With these "null" values, `s3_client.delete_objects` (line 1170) is failing on "Permission Denied".  Deletes without  the "VersionId" keys work.   

Recommend the following change to those lines (comments omitted):

```
for fk in formatted_keys:  
  if not fk.get("VersionId") or fk.get("VersionId") == "null":  
    fk.pop("VersionId")
```


### Issue Type

Bug Report

### Component Name

s3_bucket.destroy_bucket

### Ansible Version

```console (paste below)
$ ansible --version

```
not applicable

### Collection Versions

```console (paste below)
$ ansible-galaxy collection list
```


### AWS SDK versions

```console (paste below)
$ pip show boto boto3 botocore
```
 WARNING: Package(s) not found: boto
Name: boto3
Version: 1.24.28
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: c:\users\administrator\anaconda3\lib\site-packages
Requires: botocore, jmespath, s3transfer
Required-by:
---
Name: botocore
Version: 1.27.28
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: c:\users\administrator\anaconda3\lib\site-packages
Requires: jmespath, python-dateutil, urllib3
Required-by: boto3, s3transfer

### Configuration

```console (paste below)
$ ansible-config dump --only-changed

```
not applicable - transcribing from an isolated system.

### OS / Environment

CENTOS 7

### Steps to Reproduce

```
- name: Remove buckets
  tags: s3, aws_resources
  s3_bucket:
    name: "my_bucket_with_objects_with_no_versioning"
    state: absent
    force: yes
```

### Expected Results

I expected all objects in the bucket to get deleted, but they did not since there was no versioning applied.

### Actual Results

The bucket does not get deleted since the objects in it remained.


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
@evohnave Thank you for raising this. Would you be willing to open a Pull Request with a patch. 
@alinabuzachis I'm willing, but gotta tell you that I've promised to do this sort of thing to other open source projects and never gotten around to it.  I will try to get to it tonight.

Resolving patch:
diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py
--- a/plugins/modules/s3_bucket.py
+++ b/plugins/modules/s3_bucket.py
@@ -1163,7 +1163,7 @@ def destroy_bucket(s3_client, module):
                     # unversioned objects are deleted using `DeleteObject`
                     # rather than `DeleteObjectVersion`, improving backwards
                     # compatibility with older IAM policies.
-                    if not fk.get("VersionId"):
+                    if not fk.get("VersionId") or fk.get("VersionId") == "null":
                         fk.pop("VersionId")
 
                 if formatted_keys:


Test patch: