Repository: ansible-collections/community.general

Issue:
Obtain redfish information on storage controllers for HPe servers
### Summary

I want to get storage controllers properties from redfish. I have no problem with DELL servers, but can't get properties on HPe servers.

### Issue Type

Bug Report

### Component Name
redfish_info
redfish_utils

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.14.5]
  config file = /home/pyfontan/.ansible.cfg
  configured module search path = ['/home/pyfontan/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/pyfontan/virtualenv/ansible/lib/python3.10/site-packages/ansible
  ansible collection location = /home/pyfontan/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/pyfontan/virtualenv/ansible/bin/ansible
  python version = 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0] (/home/pyfontan/virtualenv/ansible/bin/python3)
  jinja version = 3.1.2
  libyaml = True
```


### Community.general Version

```console (paste below)
$ ansible-galaxy collection list community.general
# /home/pyfontan/.ansible/collections/ansible_collections
Collection        Version
----------------- -------
community.general 7.3.0 
```


### Configuration

```console (paste below)
$ ansible-config dump --only-changed
CONFIG_FILE() = /home/pyfontan/.ansible.cfg
HOST_KEY_CHECKING(/home/pyfontan/.ansible.cfg) = False
RETRY_FILES_ENABLED(/home/pyfontan/.ansible.cfg) = True
```


### OS / Environment

_No response_

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
---
  - hosts: localhost
    connection: local
    gather_facts: false

    tasks:
      - name: Get Storage Controllers Inventory
        community.general.redfish_info:
          category: Systems
          command: GetStorageControllerInventory
          baseuri: "{{manager_ip}}"
          username: "{{manager_user}}"
          password: "{{manager_password}}"
        register: controllers_inventory

      - ansible.builtin.debug:
          var: controllers_inventory
```

### Expected Results

I expect to have the storage controller properties for HPe servers

### Actual Results

On DELL:
```
TASK [ansible.builtin.debug] ***********************************************************************************************************************************
ok: [localhost] => {                                                                                                                                            
    "controllers_inventory": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python3"
        },                         
        "changed": false,                                                                                                                                       
        "failed": false,                                                                                                                                        
        "redfish_facts": {                                                                                                                                      
            "storage_controller": {                                                                                                                             
                "entries": [                                                    
                    [                                                           
                        {                                                                                                                                       
                            "system_uri": "/redfish/v1/Systems/System.Embedded.1"                                                                               
                        },                                                                                                                                      
                        [                                                                                                                                       
                            {                                                                                                                                   
                                "FirmwareVersion": "21.3.0-0009",                                                                                               
                                "Identifiers": [                                                                                                                
                                    {                                                                                                                           
                                        "DurableName": "5B083FE0DB915200",                                                                                      
                                        "DurableNameFormat": "NAA"                                                                                              
                                    }                                           
                                ],                                              
                                "Manufacturer": "DELL",                         
                                "Model": "PERC H710P Mini",                     
                                "Name": "PERC H710P Mini",                      
                                "SpeedGbps": 6,                                                                                                                 
                                "Status": {                                                                                                                     
                                    "Health": "OK",                                                                                                             
                                    "HealthRollup": "OK",
                                    "State": "Enabled"                          
                                }
                            }
                        ]
                    ]
                ],
                "ret": true
            }
        }
    }
}
```

On HPe:
```
TASK [ansible.builtin.debug] ***********************************************************************************************************************************
ok: [localhost] => {
    "controllers_inventory": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python3"
        },
        "changed": false,
        "failed": false,
        "redfish_facts": {
            "storage_controller": {
                "entries": [
                    [
                        {
                            "system_uri": "/redfish/v1/Systems/1/"
                        },
                        []
                    ]
                ],
                "ret": true
            }
        }
    }
}
```

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:

Resolving patch:
diff --git a/plugins/module_utils/redfish_utils.py b/plugins/module_utils/redfish_utils.py
--- a/plugins/module_utils/redfish_utils.py
+++ b/plugins/module_utils/redfish_utils.py
@@ -717,7 +717,8 @@ def get_storage_controller_inventory(self, systems_uri):
         properties = ['CacheSummary', 'FirmwareVersion', 'Identifiers',
                       'Location', 'Manufacturer', 'Model', 'Name', 'Id',
                       'PartNumber', 'SerialNumber', 'SpeedGbps', 'Status']
-        key = "StorageControllers"
+        key = "Controllers"
+        deprecated_key = "StorageControllers"
 
         # Find Storage service
         response = self.get_request(self.root_uri + systems_uri)
@@ -745,7 +746,30 @@ def get_storage_controller_inventory(self, systems_uri):
                 data = response['data']
 
                 if key in data:
-                    controller_list = data[key]
+                    controllers_uri = data[key][u'@odata.id']
+
+                    response = self.get_request(self.root_uri + controllers_uri)
+                    if response['ret'] is False:
+                        return response
+                    result['ret'] = True
+                    data = response['data']
+
+                    if data[u'Members']:
+                        for controller_member in data[u'Members']:
+                            controller_member_uri = controller_member[u'@odata.id']
+                            response = self.get_request(self.root_uri + controller_member_uri)
+                            if response['ret'] is False:
+                                return response
+                            result['ret'] = True
+                            data = response['data']
+
+                            controller_result = {}
+                            for property in properties:
+                                if property in data:
+                                    controller_result[property] = data[property]
+                            controller_results.append(controller_result)
+                elif deprecated_key in data:
+                    controller_list = data[deprecated_key]
                     for controller in controller_list:
                         controller_result = {}
                         for property in properties:
@@ -800,7 +824,25 @@ def get_disk_inventory(self, systems_uri):
                         return response
                     data = response['data']
                     controller_name = 'Controller 1'
-                    if 'StorageControllers' in data:
+                    if 'Controllers' in data:
+                        controllers_uri = data['Controllers'][u'@odata.id']
+
+                        response = self.get_request(self.root_uri + controllers_uri)
+                        if response['ret'] is False:
+                            return response
+                        result['ret'] = True
+                        cdata = response['data']
+
+                        if cdata[u'Members']:
+                            controller_member_uri = cdata[u'Members'][0][u'@odata.id']
+
+                            response = self.get_request(self.root_uri + controller_member_uri)
+                            if response['ret'] is False:
+                                return response
+                            result['ret'] = True
+                            cdata = response['data']
+                            controller_name = cdata['Name']
+                    elif 'StorageControllers' in data:
                         sc = data['StorageControllers']
                         if sc:
                             if 'Name' in sc[0]:
@@ -904,15 +946,7 @@ def get_volume_inventory(self, systems_uri):
                         return response
                     data = response['data']
                     controller_name = 'Controller %s' % str(idx)
-                    if 'StorageControllers' in data:
-                        sc = data['StorageControllers']
-                        if sc:
-                            if 'Name' in sc[0]:
-                                controller_name = sc[0]['Name']
-                            else:
-                                sc_id = sc[0].get('Id', '1')
-                                controller_name = 'Controller %s' % sc_id
-                    elif 'Controllers' in data:
+                    if 'Controllers' in data:
                         response = self.get_request(self.root_uri + data['Controllers'][u'@odata.id'])
                         if response['ret'] is False:
                             return response
@@ -930,6 +964,14 @@ def get_volume_inventory(self, systems_uri):
                                 else:
                                     controller_id = member_data.get('Id', '1')
                                     controller_name = 'Controller %s' % controller_id
+                    elif 'StorageControllers' in data:
+                        sc = data['StorageControllers']
+                        if sc:
+                            if 'Name' in sc[0]:
+                                controller_name = sc[0]['Name']
+                            else:
+                                sc_id = sc[0].get('Id', '1')
+                                controller_name = 'Controller %s' % sc_id
                     volume_results = []
                     volume_list = []
                     if 'Volumes' in data:


Test patch: