Repository: ansible-collections/community.vmware

Issue:
vmware_guest_disk not idempotent when removing non existing disk
##### SUMMARY
vmware_guest_disk fails when a disk with state 'absent' is not present

##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
vmware_guest_disk

##### ANSIBLE VERSION
```paste below
ansible [core 2.13.3]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/ivo/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.9/site-packages/ansible
  ansible collection location = /home/ivo/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.9.14 (main, Jan  9 2023, 00:00:00) [GCC 11.3.1 20220421 (Red Hat 11.3.1-2)]
  jinja version = 3.1.2
  libyaml = True
```

##### COLLECTION VERSION
```paste below
# /home/ivo/.ansible/collections/ansible_collections
Collection       Version
---------------- -------
community.vmware 3.6.0
```

##### CONFIGURATION
```paste below

```

##### OS / ENVIRONMENT
RHEL9.1

##### STEPS TO REPRODUCE
Try to remove non-existing disk on existing SCSI controller

```yaml
---
- hosts: localhost
  gather_facts: no
  tasks:
    - name: Remove VM disk
      ansible.builtin.vmware_guest_disk:
        hostname: "vcenter.work.lan"
        username: "user@vcenter"
        password: 'pwd@vcenter'
        datacenter: "datacenter1"
        name: "testVM1"
        disk:
          - scsi_controller: 0
            unit_number: 15
            state: absent
```

##### EXPECTED RESULTS
No failures, no changes

##### ACTUAL RESULTS
Playbook fails when removing a disk which is not present

<!--- Paste verbatim command output between quotes -->
```paste below
TASK [Remove VM disk] ********************************************************************************************************************************************************************************************************************
task path: /home/ivo/tst.yml:8
redirecting (type: modules) ansible.builtin.vmware_guest_disk to community.vmware.vmware_guest_disk
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: ivo
<127.0.0.1> EXEC /bin/sh -c 'echo ~ivo && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/ivo/.ansible/tmp `"&& mkdir "` echo /home/ivo/.ansible/tmp/ansible-tmp-1685993784.132655-203446-30703779486048 `" && echo ansible-tmp-1685993784.132655-203446-30703779486048="` echo /home/ivo/.ansible/tmp/ansible-tmp-1685993784.132655-203446-30703779486048 `" ) && sleep 0'
redirecting (type: modules) ansible.builtin.vmware_guest_disk to community.vmware.vmware_guest_disk
Using module file /home/ivo/.ansible/collections/ansible_collections/community/vmware/plugins/modules/vmware_guest_disk.py
<127.0.0.1> PUT /home/ivo/.ansible/tmp/ansible-local-203442e9x39zgz/tmphsd07ifd TO /home/ivo/.ansible/tmp/ansible-tmp-1685993784.132655-203446-30703779486048/AnsiballZ_vmware_guest_disk.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/ivo/.ansible/tmp/ansible-tmp-1685993784.132655-203446-30703779486048/ /home/ivo/.ansible/tmp/ansible-tmp-1685993784.132655-203446-30703779486048/AnsiballZ_vmware_guest_disk.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python3.9 /home/ivo/.ansible/tmp/ansible-tmp-1685993784.132655-203446-30703779486048/AnsiballZ_vmware_guest_disk.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/ivo/.ansible/tmp/ansible-tmp-1685993784.132655-203446-30703779486048/ > /dev/null 2>&1 && sleep 0'
fatal: [localhost]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "datacenter": "datacenter1",
            "disk": [
                {
                    "autoselect_datastore": false,
                    "bus_sharing": "noSharing",
                    "cluster_disk": false,
                    "compatibility_mode": null,
                    "controller_number": null,
                    "controller_type": null,
                    "datastore": null,
                    "destroy": true,
                    "disk_mode": null,
                    "filename": null,
                    "iolimit": null,
                    "rdm_path": null,
                    "scsi_controller": 0,
                    "scsi_type": null,
                    "shares": null,
                    "sharing": false,
                    "size": null,
                    "size_gb": null,
                    "size_kb": null,
                    "size_mb": null,
                    "size_tb": null,
                    "state": "absent",
                    "type": null,
                    "unit_number": 15
                }
            ],
            "folder": null,
            "hostname": "vcenter.work.lan",
            "moid": null,
            "name": "testVM1",
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "port": 443,
            "proxy_host": null,
            "proxy_port": null,
            "use_instance_uuid": false,
            "username": "user@vcenter",
            "uuid": null,
            "validate_certs": true
        }
    },
    "msg": "Not found disk with 'controller_type': 'paravirtual', 'controller_number': '0', 'unit_number': '15' to remove."
}

PLAY RECAP *******************************************************************************************************************************************************************************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
```



Discussion:

Resolving patch:
diff --git a/plugins/modules/vmware_guest_disk.py b/plugins/modules/vmware_guest_disk.py
--- a/plugins/modules/vmware_guest_disk.py
+++ b/plugins/modules/vmware_guest_disk.py
@@ -810,10 +810,6 @@ def ensure_disks(self, vm_obj=None):
                         disk_change_list.append(disk_change)
                         results['disk_changes'][disk['disk_index']] = "Disk created."
                         break
-                    if not disk_found and disk['state'] == 'absent':
-                        self.module.fail_json(msg="Not found disk with 'controller_type': '%s',"
-                                                  " 'controller_number': '%s', 'unit_number': '%s' to remove."
-                                                  % (disk['controller_type'], disk['controller_number'], disk['disk_unit_number']))
             if disk_change:
                 # Adding multiple disks in a single attempt raises weird errors
                 # So adding single disk at a time.


Test patch:
diff --git a/tests/integration/targets/vmware_guest_disk/tasks/main.yml b/tests/integration/targets/vmware_guest_disk/tasks/main.yml
--- a/tests/integration/targets/vmware_guest_disk/tasks/main.yml
+++ b/tests/integration/targets/vmware_guest_disk/tasks/main.yml
@@ -607,4 +607,28 @@
 - name: assert that changes were made
   assert:
     that:
-      - test_remove_ide_disk is changed
\ No newline at end of file
+      - test_remove_ide_disk is changed
+
+- name: Try to remove non-existing SCSI disk
+  vmware_guest_disk:
+    hostname: "{{ vcenter_hostname }}"
+    username: "{{ vcenter_username }}"
+    password: "{{ vcenter_password }}"
+    datacenter: "{{ dc1 }}"
+    validate_certs: false
+    name: test_vm1
+    disk:
+      - state: "absent"
+        controller_type: 'paravirtual'
+        controller_number: 0
+        unit_number: 15
+  register: test_remove_non_existing_disk
+  ignore_errors: true
+
+- debug:
+    msg: "{{ test_remove_non_existing_disk }}"
+
+- name: assert that removing non existing disk does not fail
+  assert:
+    that:
+      - test_remove_non_existing_disk is not failed