Repository: ansible-collections/community.vmware

Issue:
Missing attribute controller_bus_number in output of vmware_guest_disk
##### SUMMARY
I specify disks to modify with controller number and bus number. I also use both attributes to filter the disks later.

After adding a new disk to a VM with `vmware_guest_disk`, the disk details are returned. Unfortunataly these details does not contains  `controller_bus_number` in the attributes like `vmware_guest_disk_info` does.

Workaround: add an additional call of `vmware_guest_disk_info` and use its data.

Output of `vmware_guest_disk`:
```
ok: [myvm] =>
  disk_facts:
    changed: false
    disk_changes: {}
    disk_data:
      '0':
        backing_datastore: mydatastore
        backing_disk_mode: persistent
        backing_eagerlyscrub: false
        backing_filename: '[mydatastore] myvm/myvm.vmdk'
        backing_sharing: sharingNone   <--- missing in guest_disk_info
        backing_thinprovisioned: true
        backing_uuid: 60001A43-0e94-ea74-4efd-92cd21912412
        backing_writethrough: false
        capacity_in_bytes: 5368709120
        capacity_in_kb: 5242880
        controller_key: 1000
        iolimit_limit: -1              <--- missing in guest_disk_info
        iolimit_shares_level: normal   <--- missing in guest_disk_info
        iolimit_shares_limit: 1000     <--- missing in guest_disk_info
        key: 2000
        label: Hard disk 1
        shares_level: normal           <--- missing in guest_disk_info
        shares_limit: 1000             <--- missing in guest_disk_info
        summary: 5,242,880 KB
        unit_number: 0
    failed: false
```

Output of `vmware_guest_disk_info`:

```
ok: [myvm] =>
  guest_disk_info:
    changed: false
    failed: false
    guest_disk_info:
      '0':
        backing_datastore: mydatastore
        backing_disk_mode: persistent
        backing_diskmode: persistent   <--- missing in guest_disk
        backing_eagerlyscrub: false
        backing_filename: '[mydatastore] myvm/myvm.vmdk'
        backing_thinprovisioned: true
        backing_type: FlatVer2         <--- missing in guest_disk
        backing_uuid: 60001A43-0e94-ea74-4efd-92cd21912412
        backing_writethrough: false
        capacity_in_bytes: 5368709120
        capacity_in_kb: 5242880
        controller_bus_number: 0       <--- missing in guest_disk
        controller_key: 1000
        controller_type: paravirtual   <--- missing in guest_disk
        key: 2000
        label: Hard disk 1
        summary: 5,242,880 KB
        unit_number: 0
```

Please add the `controller_bus_number` to the output of `vmware_guest_disk`.

What do you think about aligning both structures and use just 1 function to provide the disk data?


##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
vmware_guest_disk

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```paste below
ansible --version
ansible [core 2.13.7]
  config file = /home/myuser/Projects/myproject/ansible.cfg
  configured module search path = ['/home/myuser/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/myuser/virtualenv/lib64/python3.10/site-packages/ansible
  ansible collection location = /home/myuser/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/myuser/virtualenv/bin/ansible
  python version = 3.10.8 (main, Oct 28 2022, 17:28:32) [GCC]
  jinja version = 3.1.2
  libyaml = True
```

##### COLLECTION VERSION
```paste below
Collection        Version
----------------- -------
community.general 5.8.0
community.vmware 2.10.1
```

##### CONFIGURATION
```paste below
CACHE_PLUGIN(/home/myuser/Projects/myproject/ansible.cfg) = jsonfile
CACHE_PLUGIN_CONNECTION(/home/myuser/Projects/myproject/ansible.cfg) = ./facts
CACHE_PLUGIN_TIMEOUT(/home/myuser/Projects/myproject/ansible.cfg) = 28800
DEFAULT_GATHERING(/home/myuser/Projects/myproject/ansible.cfg) = smart
DEFAULT_HOST_LIST(/home/myuser/Projects/myproject/ansible.cfg) = ['/home/myuser/Projects/myproject/hosts']
DEFAULT_ROLES_PATH(/home/myuser/Projects/myproject/ansible.cfg) = ['/home/myuser/Projects/myproject/roles']
DEFAULT_STDOUT_CALLBACK(/home/myuser/Projects/myproject/ansible.cfg) = yaml
DEFAULT_VAULT_PASSWORD_FILE(/home/myuser/Projects/myproject/ansible.cfg) = /home/myuser/.ansible_vault_password
HOST_KEY_CHECKING(/home/myuser/Projects/myproject/ansible.cfg) = False
INTERPRETER_PYTHON(/home/myuser/Projects/myproject/ansible.cfg) = auto_silent
```

##### STEPS TO REPRODUCE
```yaml
- name: Create a new disk
  community.vmware.vmware_guest_disk:
    hostname: '{{ vcenter_hostname }}'
    username: '{{ vcenter_username }}'
    password: '{{ vcenter_password }}'
    validate_certs: no
    datacenter: '{{ vmware_datacenter }}'
    name: "myvm"
    disk:
      - size_gb: 5
        type: "thin"
        datastore: '{{ vmware_datastore }}'
        state: present
        scsi_controller: 1
        unit_number: 2
        scsi_type: "paravirtual"
        disk_mode: "persistent"
  delegate_to: localhost
  connection: local
  become: false
  register: guest_disk

- name: Get vmware guest disk facts
  community.vmware.vmware_guest_disk_info:
    hostname: '{{ vcenter_hostname }}'
    username: '{{ vcenter_username }}'
    password: '{{ vcenter_password }}'
    validate_certs: "no"
    datacenter: '{{ vmware_datacenter }}'
    name: "myvm"
  register: guest_disk_info
  delegate_to: localhost
  connection: local
  become: false
```


Discussion:

Resolving patch:
diff --git a/plugins/module_utils/vm_device_helper.py b/plugins/module_utils/vm_device_helper.py
--- a/plugins/module_utils/vm_device_helper.py
+++ b/plugins/module_utils/vm_device_helper.py
@@ -40,6 +40,13 @@ def __init__(self, module):
         }
         self.sata_device_type = vim.vm.device.VirtualAHCIController
         self.nvme_device_type = vim.vm.device.VirtualNVMEController
+        self.ide_device_type = vim.vm.device.VirtualIDEController
+        self.disk_ctl_device_type = self.scsi_device_type.copy()
+        self.disk_ctl_device_type.update({
+            'sata': self.sata_device_type,
+            'nvme': self.nvme_device_type,
+            'ide': self.ide_device_type
+        })
         self.usb_device_type = {
             'usb2': vim.vm.device.VirtualUSBController,
             'usb3': vim.vm.device.VirtualUSBXHCIController
@@ -404,3 +411,105 @@ def remove_tpm(self, vtpm_device):
         vtpm_device_spec.device = vtpm_device
 
         return vtpm_device_spec
+
+    def gather_disk_info(self, vm_obj):
+        """
+        Gather information about VM's disks
+        Args:
+            vm_obj: Managed object of virtual machine
+        Returns: A list of dict containing disks information
+        """
+        controller_info = dict()
+        disks_info = dict()
+        if vm_obj is None:
+            return disks_info
+
+        controller_index = 0
+        for controller in vm_obj.config.hardware.device:
+            for name, type in self.disk_ctl_device_type.items():
+                if isinstance(controller, type):
+                    controller_info[controller_index] = dict(
+                        key=controller.key,
+                        controller_type=name,
+                        bus_number=controller.busNumber,
+                        devices=controller.device
+                    )
+                    controller_index += 1
+
+        disk_index = 0
+        for disk in vm_obj.config.hardware.device:
+            if isinstance(disk, vim.vm.device.VirtualDisk):
+                if disk.storageIOAllocation is None:
+                    disk.storageIOAllocation = vim.StorageResourceManager.IOAllocationInfo()
+                    disk.storageIOAllocation.shares = vim.SharesInfo()
+
+                if disk.shares is None:
+                    disk.shares = vim.SharesInfo()
+
+                disks_info[disk_index] = dict(
+                    key=disk.key,
+                    label=disk.deviceInfo.label,
+                    summary=disk.deviceInfo.summary,
+                    backing_filename=disk.backing.fileName,
+                    backing_datastore=disk.backing.datastore.name,
+                    backing_sharing=disk.backing.sharing if hasattr(disk.backing, 'sharing') else None,
+                    backing_uuid=disk.backing.uuid if hasattr(disk.backing, 'uuid') else None,
+                    backing_writethrough=disk.backing.writeThrough if hasattr(disk.backing, 'writeThrough') else None,
+                    backing_diskmode=disk.backing.diskMode if hasattr(disk.backing, 'diskMode') else None,
+                    backing_disk_mode=disk.backing.diskMode if hasattr(disk.backing, 'diskMode') else None,
+                    iolimit_limit=disk.storageIOAllocation.limit,
+                    iolimit_shares_level=disk.storageIOAllocation.shares.level,
+                    iolimit_shares_limit=disk.storageIOAllocation.shares.shares,
+                    shares_level=disk.shares.level,
+                    shares_limit=disk.shares.shares,
+                    controller_key=disk.controllerKey,
+                    unit_number=disk.unitNumber,
+                    capacity_in_kb=disk.capacityInKB,
+                    capacity_in_bytes=disk.capacityInBytes,
+                )
+                if isinstance(disk.backing, vim.vm.device.VirtualDisk.FlatVer1BackingInfo):
+                    disks_info[disk_index]['backing_type'] = 'FlatVer1'
+
+                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.FlatVer2BackingInfo):
+                    disks_info[disk_index]['backing_type'] = 'FlatVer2'
+                    disks_info[disk_index]['backing_thinprovisioned'] = disk.backing.thinProvisioned
+                    disks_info[disk_index]['backing_eagerlyscrub'] = disk.backing.eagerlyScrub
+
+                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.LocalPMemBackingInfo):
+                    disks_info[disk_index]['backing_type'] = 'LocalPMem'
+                    disks_info[disk_index]['backing_volumeuuid'] = disk.backing.volumeUUID
+
+                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.PartitionedRawDiskVer2BackingInfo):
+                    disks_info[disk_index]['backing_type'] = 'PartitionedRawDiskVer2'
+                    disks_info[disk_index]['backing_descriptorfilename'] = disk.backing.descriptorFileName
+
+                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.RawDiskMappingVer1BackingInfo):
+                    disks_info[disk_index]['backing_type'] = 'RawDiskMappingVer1'
+                    disks_info[disk_index]['backing_devicename'] = disk.backing.deviceName
+                    disks_info[disk_index]['backing_lunuuid'] = disk.backing.lunUuid
+                    disks_info[disk_index]['backing_compatibility_mode'] = disk.backing.compatibilityMode
+
+                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.RawDiskVer2BackingInfo):
+                    disks_info[disk_index]['backing_type'] = 'RawDiskVer2'
+                    disks_info[disk_index]['backing_descriptorfilename'] = disk.backing.descriptorFileName
+
+                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.SeSparseBackingInfo):
+                    disks_info[disk_index]['backing_type'] = 'SeSparse'
+
+                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.SparseVer1BackingInfo):
+                    disks_info[disk_index]['backing_type'] = 'SparseVer1'
+                    disks_info[disk_index]['backing_spaceusedinkb'] = disk.backing.spaceUsedInKB
+                    disks_info[disk_index]['backing_split'] = disk.backing.split
+
+                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.SparseVer2BackingInfo):
+                    disks_info[disk_index]['backing_type'] = 'SparseVer2'
+                    disks_info[disk_index]['backing_spaceusedinkb'] = disk.backing.spaceUsedInKB
+                    disks_info[disk_index]['backing_split'] = disk.backing.split
+
+                for controller_index in range(len(controller_info)):
+                    if controller_info[controller_index]['key'] == disks_info[disk_index]['controller_key']:
+                        disks_info[disk_index]['controller_bus_number'] = controller_info[controller_index]['bus_number']
+                        disks_info[disk_index]['controller_type'] = controller_info[controller_index]['controller_type']
+
+                disk_index += 1
+        return disks_info
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
@@ -154,9 +154,10 @@
          description:
            - Disk Unit Number.
            - Valid value range from 0 to 15, except 7 for SCSI Controller.
-           - Valid value range from 0 to 64, except 7 for Paravirtual SCSI Controller on Virtual Hardware version 14 or higher
+           - Valid value range from 0 to 64, except 7 for Paravirtual SCSI Controller on Virtual Hardware version 14 or higher.
            - Valid value range from 0 to 29 for SATA controller.
            - Valid value range from 0 to 14 for NVME controller.
+           - Valid value range from 0 to 1 for IDE controller.
          type: int
          required: True
        scsi_type:
@@ -189,9 +190,11 @@
            - This parameter is added for managing disks attaching other types of controllers, e.g., SATA or NVMe.
            - If either C(controller_type) or C(scsi_type) is not specified, then use C(paravirtual) type.
          type: str
-         choices: ['buslogic', 'lsilogic', 'lsilogicsas', 'paravirtual', 'sata', 'nvme']
+         choices: ['buslogic', 'lsilogic', 'lsilogicsas', 'paravirtual', 'sata', 'nvme', 'ide']
        controller_number:
-         description: This parameter is used with C(controller_type) for specifying controller bus number.
+         description:
+           - This parameter is used with C(controller_type) for specifying controller bus number.
+           - For C(ide) controller type, valid value is 0 or 1.
          type: int
          choices: [0, 1, 2, 3]
        iolimit:
@@ -516,8 +519,6 @@ def __init__(self, module):
         self.device_helper = PyVmomiDeviceHelper(self.module)
         self.desired_disks = self.params['disk']  # Match with vmware_guest parameter
         self.vm = None
-        self.ctl_device_type = self.device_helper.scsi_device_type.copy()
-        self.ctl_device_type.update({'sata': self.device_helper.sata_device_type, 'nvme': self.device_helper.nvme_device_type})
         self.config_spec = vim.vm.ConfigSpec()
         self.config_spec.deviceChange = []
 
@@ -667,7 +668,7 @@ def ensure_disks(self, vm_obj=None):
             # check if disk controller already exists
             if not ctl_found:
                 for device in self.vm.config.hardware.device:
-                    if isinstance(device, self.ctl_device_type[disk['controller_type']]):
+                    if isinstance(device, self.device_helper.disk_ctl_device_type[disk['controller_type']]):
                         if device.busNumber == disk['controller_number']:
                             ctl_found = True
                             break
@@ -699,7 +700,7 @@ def ensure_disks(self, vm_obj=None):
             disk_change = False
             ctl_found = False
             for device in self.vm.config.hardware.device:
-                if isinstance(device, self.ctl_device_type[disk['controller_type']]) and device.busNumber == disk['controller_number']:
+                if isinstance(device, self.device_helper.disk_ctl_device_type[disk['controller_type']]) and device.busNumber == disk['controller_number']:
                     for disk_key in device.device:
                         disk_device = self.find_disk_by_key(disk_key, disk['disk_unit_number'])
                         if disk_device is not None:
@@ -813,7 +814,7 @@ def ensure_disks(self, vm_obj=None):
                 self.config_spec.deviceChange = []
         if any(disk_change_list):
             results['changed'] = True
-        results['disk_data'] = self.gather_disk_facts(vm_obj=self.vm)
+        results['disk_data'] = self.device_helper.gather_disk_info(self.vm)
         self.module.exit_json(**results)
 
     def sanitize_disk_inputs(self):
@@ -870,6 +871,10 @@ def sanitize_disk_inputs(self):
             else:
                 self.module.fail_json(msg="Please specify either 'scsi_type' or 'controller_type' for disk index [%s]."
                                           % disk_index)
+            if current_disk['controller_type'] == 'ide':
+                if self.vm.runtime.powerState != vim.VirtualMachinePowerState.poweredOff:
+                    self.module.fail_json(msg="Please make sure VM is in powered off state before doing IDE disk"
+                                              " reconfiguration.")
 
             # Check controller bus number
             if disk['scsi_controller'] is not None and disk['controller_number'] is None and disk['controller_type'] is None:
@@ -885,6 +890,10 @@ def sanitize_disk_inputs(self):
             except ValueError:
                 self.module.fail_json(msg="Invalid controller bus number '%s' specified"
                                           " for disk index [%s]" % (temp_disk_controller, disk_index))
+            if current_disk['controller_type'] == 'ide' and disk_controller not in [0, 1]:
+                self.module.fail_json(msg="Invalid controller bus number '%s' specified"
+                                          " for disk index [%s], valid value is 0 or 1" % (disk_controller, disk_index))
+
             current_disk['controller_number'] = disk_controller
 
             try:
@@ -921,6 +930,9 @@ def sanitize_disk_inputs(self):
             elif current_disk['controller_type'] == 'nvme' and temp_disk_unit_number not in range(0, 15):
                 self.module.fail_json(msg="Invalid Disk unit number ID specified for NVMe disk [%s] at index [%s],"
                                           " please specify value between 0 to 14" % (temp_disk_unit_number, disk_index))
+            elif current_disk['controller_type'] == 'ide' and temp_disk_unit_number not in [0, 1]:
+                self.module.fail_json(msg="Invalid Disk unit number ID specified for IDE disk [%s] at index [%s],"
+                                          " please specify value 0 or 1" % (temp_disk_unit_number, disk_index))
             current_disk['disk_unit_number'] = temp_disk_unit_number
 
             # By default destroy file from datastore if 'destroy' parameter is not provided
@@ -1124,60 +1136,6 @@ def get_recommended_datastore(self, datastore_cluster_obj, disk_spec_obj):
             return datastore.name
         return None
 
-    @staticmethod
-    def gather_disk_facts(vm_obj):
-        """
-        Gather facts about VM's disks
-        Args:
-            vm_obj: Managed object of virtual machine
-
-        Returns: A list of dict containing disks information
-
-        """
-        disks_facts = dict()
-        if vm_obj is None:
-            return disks_facts
-
-        disk_index = 0
-        for disk in vm_obj.config.hardware.device:
-            if isinstance(disk, vim.vm.device.VirtualDisk):
-                if disk.storageIOAllocation is None:
-                    disk.storageIOAllocation = vim.StorageResourceManager.IOAllocationInfo()
-                    disk.storageIOAllocation.shares = vim.SharesInfo()
-
-                if disk.shares is None:
-                    disk.shares = vim.SharesInfo()
-
-                disks_facts[disk_index] = dict(
-                    key=disk.key,
-                    label=disk.deviceInfo.label,
-                    summary=disk.deviceInfo.summary,
-                    backing_filename=disk.backing.fileName,
-                    backing_datastore=disk.backing.datastore.name,
-                    backing_disk_mode=disk.backing.diskMode,
-                    backing_sharing=disk.backing.sharing if hasattr(disk.backing, 'sharing') else None,
-                    backing_uuid=disk.backing.uuid,
-                    controller_key=disk.controllerKey,
-                    unit_number=disk.unitNumber,
-                    iolimit_limit=disk.storageIOAllocation.limit,
-                    iolimit_shares_level=disk.storageIOAllocation.shares.level,
-                    iolimit_shares_limit=disk.storageIOAllocation.shares.shares,
-                    shares_level=disk.shares.level,
-                    shares_limit=disk.shares.shares,
-                    capacity_in_kb=disk.capacityInKB,
-                    capacity_in_bytes=disk.capacityInBytes,
-                )
-                if isinstance(disk.backing, vim.vm.device.VirtualDisk.RawDiskMappingVer1BackingInfo):
-                    disks_facts[disk_index].update(backing_devicename=disk.backing.deviceName,
-                                                   backing_compatibility_mode=disk.backing.compatibilityMode)
-
-                elif not isinstance(disk.backing, vim.vm.device.VirtualDisk.LocalPMemBackingInfo):
-                    disks_facts[disk_index].update(backing_writethrough=disk.backing.writeThrough,
-                                                   backing_thinprovisioned=disk.backing.thinProvisioned,
-                                                   backing_eagerlyscrub=bool(disk.backing.eagerlyScrub))
-                disk_index += 1
-        return disks_facts
-
 
 def main():
     argument_spec = vmware_argument_spec()
@@ -1211,7 +1169,7 @@ def main():
                 destroy=dict(type='bool', default=True),
                 filename=dict(type='str'),
                 state=dict(type='str', default='present', choices=['present', 'absent']),
-                controller_type=dict(type='str', choices=['buslogic', 'lsilogic', 'paravirtual', 'lsilogicsas', 'sata', 'nvme']),
+                controller_type=dict(type='str', choices=['buslogic', 'lsilogic', 'paravirtual', 'lsilogicsas', 'sata', 'nvme', 'ide']),
                 controller_number=dict(type='int', choices=[0, 1, 2, 3]),
                 bus_sharing=dict(type='str', choices=['noSharing', 'physicalSharing', 'virtualSharing'], default='noSharing'),
                 cluster_disk=dict(type='bool', default=False),
diff --git a/plugins/modules/vmware_guest_disk_info.py b/plugins/modules/vmware_guest_disk_info.py
--- a/plugins/modules/vmware_guest_disk_info.py
+++ b/plugins/modules/vmware_guest_disk_info.py
@@ -147,134 +147,10 @@
     }
 '''
 
-try:
-    from pyVmomi import vim
-except ImportError:
-    pass
-
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils._text import to_text
 from ansible_collections.community.vmware.plugins.module_utils.vmware import PyVmomi, vmware_argument_spec
-
-
-class PyVmomiHelper(PyVmomi):
-    def __init__(self, module):
-        super(PyVmomiHelper, self).__init__(module)
-
-    def gather_disk_info(self, vm_obj):
-        """
-        Gather information about VM's disks
-        Args:
-            vm_obj: Managed object of virtual machine
-
-        Returns: A list of dict containing disks information
-
-        """
-        controller_info = dict()
-        disks_info = dict()
-        if vm_obj is None:
-            return disks_info
-
-        controller_types = {
-            vim.vm.device.VirtualLsiLogicController: 'lsilogic',
-            vim.vm.device.ParaVirtualSCSIController: 'paravirtual',
-            vim.vm.device.VirtualBusLogicController: 'buslogic',
-            vim.vm.device.VirtualLsiLogicSASController: 'lsilogicsas',
-            vim.vm.device.VirtualIDEController: 'ide'
-        }
-
-        controller_index = 0
-        for controller in vm_obj.config.hardware.device:
-            if isinstance(controller, tuple(controller_types.keys())):
-                controller_info[controller_index] = dict(
-                    key=controller.key,
-                    controller_type=controller_types[type(controller)],
-                    bus_number=controller.busNumber,
-                    devices=controller.device
-                )
-                controller_index += 1
-
-        disk_index = 0
-        for disk in vm_obj.config.hardware.device:
-            if isinstance(disk, vim.vm.device.VirtualDisk):
-                disks_info[disk_index] = dict(
-                    key=disk.key,
-                    label=disk.deviceInfo.label,
-                    summary=disk.deviceInfo.summary,
-                    backing_filename=disk.backing.fileName,
-                    backing_datastore=disk.backing.datastore.name,
-                    controller_key=disk.controllerKey,
-                    unit_number=disk.unitNumber,
-                    capacity_in_kb=disk.capacityInKB,
-                    capacity_in_bytes=disk.capacityInBytes,
-                )
-                if isinstance(disk.backing, vim.vm.device.VirtualDisk.FlatVer1BackingInfo):
-                    disks_info[disk_index]['backing_type'] = 'FlatVer1'
-                    disks_info[disk_index]['backing_writethrough'] = disk.backing.writeThrough
-
-                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.FlatVer2BackingInfo):
-                    disks_info[disk_index]['backing_type'] = 'FlatVer2'
-                    disks_info[disk_index]['backing_writethrough'] = bool(disk.backing.writeThrough)
-                    disks_info[disk_index]['backing_thinprovisioned'] = bool(disk.backing.thinProvisioned)
-                    disks_info[disk_index]['backing_eagerlyscrub'] = bool(disk.backing.eagerlyScrub)
-                    disks_info[disk_index]['backing_diskmode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_disk_mode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_uuid'] = disk.backing.uuid
-
-                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.LocalPMemBackingInfo):
-                    disks_info[disk_index]['backing_type'] = 'LocalPMem'
-                    disks_info[disk_index]['backing_volumeuuid'] = disk.backing.volumeUUID
-                    disks_info[disk_index]['backing_uuid'] = disk.backing.uuid
-
-                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.PartitionedRawDiskVer2BackingInfo):
-                    disks_info[disk_index]['backing_type'] = 'PartitionedRawDiskVer2'
-                    disks_info[disk_index]['backing_descriptorfilename'] = disk.backing.descriptorFileName
-                    disks_info[disk_index]['backing_uuid'] = disk.backing.uuid
-
-                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.RawDiskMappingVer1BackingInfo):
-                    disks_info[disk_index]['backing_type'] = 'RawDiskMappingVer1'
-                    disks_info[disk_index]['backing_devicename'] = disk.backing.deviceName
-                    disks_info[disk_index]['backing_diskmode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_disk_mode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_lunuuid'] = disk.backing.lunUuid
-                    disks_info[disk_index]['backing_uuid'] = disk.backing.uuid
-
-                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.RawDiskVer2BackingInfo):
-                    disks_info[disk_index]['backing_type'] = 'RawDiskVer2'
-                    disks_info[disk_index]['backing_descriptorfilename'] = disk.backing.descriptorFileName
-                    disks_info[disk_index]['backing_uuid'] = disk.backing.uuid
-
-                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.SeSparseBackingInfo):
-                    disks_info[disk_index]['backing_type'] = 'SeSparse'
-                    disks_info[disk_index]['backing_diskmode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_disk_mode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_writethrough'] = bool(disk.backing.writeThrough)
-                    disks_info[disk_index]['backing_uuid'] = disk.backing.uuid
-
-                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.SparseVer1BackingInfo):
-                    disks_info[disk_index]['backing_type'] = 'SparseVer1'
-                    disks_info[disk_index]['backing_diskmode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_disk_mode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_spaceusedinkb'] = disk.backing.spaceUsedInKB
-                    disks_info[disk_index]['backing_split'] = bool(disk.backing.split)
-                    disks_info[disk_index]['backing_writethrough'] = bool(disk.backing.writeThrough)
-
-                elif isinstance(disk.backing, vim.vm.device.VirtualDisk.SparseVer2BackingInfo):
-                    disks_info[disk_index]['backing_type'] = 'SparseVer2'
-                    disks_info[disk_index]['backing_diskmode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_disk_mode'] = disk.backing.diskMode
-                    disks_info[disk_index]['backing_spaceusedinkb'] = disk.backing.spaceUsedInKB
-                    disks_info[disk_index]['backing_split'] = bool(disk.backing.split)
-                    disks_info[disk_index]['backing_writethrough'] = bool(disk.backing.writeThrough)
-                    disks_info[disk_index]['backing_uuid'] = disk.backing.uuid
-
-                for controller_index in range(len(controller_info)):
-                    if controller_info[controller_index]['key'] == disks_info[disk_index]['controller_key']:
-                        disks_info[disk_index]['controller_bus_number'] = controller_info[controller_index]['bus_number']
-                        disks_info[disk_index]['controller_type'] = controller_info[controller_index]['controller_type']
-
-                disk_index += 1
-        return disks_info
+from ansible_collections.community.vmware.plugins.module_utils.vm_device_helper import PyVmomiDeviceHelper
 
 
 def main():
@@ -300,14 +176,15 @@ def main():
         # so we should leave the input folder path unmodified
         module.params['folder'] = module.params['folder'].rstrip('/')
 
-    pyv = PyVmomiHelper(module)
+    pyv = PyVmomi(module)
+    device_helper = PyVmomiDeviceHelper(module)
     # Check if the VM exists before continuing
     vm = pyv.get_vm()
 
     if vm:
         # VM exists
         try:
-            module.exit_json(guest_disk_info=pyv.gather_disk_info(vm))
+            module.exit_json(guest_disk_info=device_helper.gather_disk_info(vm))
         except Exception as exc:
             module.fail_json(msg="Failed to gather information with exception : %s" % to_text(exc))
     else:


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
@@ -554,3 +554,57 @@
   assert:
     that:
       - test_remove_sata_nvme_disk is changed
+
+- name: create new disk with IDE controller
+  vmware_guest_disk:
+    hostname: "{{ vcenter_hostname }}"
+    username: "{{ vcenter_username }}"
+    password: "{{ vcenter_password }}"
+    datacenter: "{{ dc1 }}"
+    validate_certs: false
+    name: test_vm1
+    disk:
+      - datastore: "{{ rw_datastore }}"
+        disk_mode: "independent_persistent"
+        controller_type: 'ide'
+        controller_number: 0
+        unit_number: 1
+        size_gb: 1
+        state: present
+        type: thin
+        shares:
+          level: custom
+          level_value: 1200
+  register: test_create_ide_disk
+
+- debug:
+    msg: "{{ test_create_ide_disk }}"
+
+- name: assert that changes were made
+  assert:
+    that:
+      - test_create_ide_disk is changed
+
+- name: remove IDE 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: 'ide'
+        controller_number: 0
+        unit_number: 1
+        destroy: true
+  register: test_remove_ide_disk
+
+- debug:
+    msg: "{{ test_remove_ide_disk }}"
+
+- name: assert that changes were made
+  assert:
+    that:
+      - test_remove_ide_disk is changed
\ No newline at end of file