# Buggy code
def get_nic_inventory(self):
    result = {}
    nic_details = []
    nic_list = []
    key = "EthernetInterfaces"

    # Search for 'key' entry and extract URI from it
    response = self.get_request(self.root_uri + self.systems_uri)
    if response["ret"] is False:
        return response
    result["ret"] = True
    data = response["data"]

    ethernetinterfaces_uri = data[key]["@odata.id"]

    # Get a list of all network controllers and build respective URIs
    response = self.get_request(self.root_uri + ethernetinterfaces_uri)
    if response["ret"] is False:
        return response
    result["ret"] = True
    data = response["data"]

    for nic in data["Members"]:
        nic_list.append(nic["@odata.id"])

    for n in nic_list:
        nic = {}
        uri = self.root_uri + n
        response = self.get_request(uri)
        if response["ret"] is False:
            return response
        data = response["data"]

        nic["Name"] = data["Name"]
        nic["FQDN"] = data["FQDN"]
        for d in data["IPv4Addresses"]:
            nic["IPv4"] = d["Address"]
            if "GateWay" in d:  # not always available
                nic["Gateway"] = d["GateWay"]
            nic["SubnetMask"] = d["SubnetMask"]
        for d in data["IPv6Addresses"]:
            nic["IPv6"] = d["Address"]
        for d in data["NameServers"]:
            nic["NameServers"] = d
        nic["MACAddress"] = data["PermanentMACAddress"]
        nic["SpeedMbps"] = data["SpeedMbps"]
        nic["MTU"] = data["MTUSize"]
        nic["AutoNeg"] = data["AutoNeg"]
        if "Status" in data:  # not available when power is off
            nic["Health"] = data["Status"]["Health"]
            nic["State"] = data["Status"]["State"]
        nic_details.append(nic)
    result["entries"] = nic_details
    return result


# Traceback (KeyError)
OS / ENVIRONMENT
Gentoo GNU/Linux x86_64, Fedora GNU/Linux x86_64
STEPS TO REPRODUCE
Use this playbook (user, password and baseuri should be set to Redfish API credentials and endpoint):
- hosts: localhost
gather_facts: false
vars:
baseuri: redfish_api_entrypoint
user: test
password: test
tasks:
- name: Get all information available in all categories
redfish_facts:
category: all
command: all
baseuri: "{{ baseuri }}"
user: "{{ user }}"
password: "{{ password }}"
EXPECTED RESULTS
Facts about Redfish service are gathered and stored for later use.
ACTUAL RESULTS
Task failed during execution.
ansible-playbook 2.7.0b1.post0
config file = None
configured module search path = [u'/home/tadej/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /home/tadej/xlab/ansible/ansible/venv2/lib/python2.7/site-packages/ansible
executable location = /home/tadej/xlab/ansible/ansible/venv2/bin/ansible-playbook
python version = 2.7.15 (default, Jul 16 2018, 15:01:34) [GCC 7.3.0]
No config file found; using defaults
setting up inventory plugins
[WARNING]: Unable to parse /etc/ansible/hosts as an inventory source

[WARNING]: No inventory was parsed, only implicit localhost is available

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

Loading callback plugin default of type stdout, v2.0 from /home/tadej/xlab/ansible/ansible/venv2/lib/python2.7/site-packages/ansible/plugins/callback/default.pyc

PLAYBOOK: facts.yml ***************************************************************************************************************************************************
1 plays in facts.yml

PLAY [localhost] ******************************************************************************************************************************************************
META: ran handlers

TASK [Get all information available in all categories] ****************************************************************************************************************
task path: /home/tadej/xlab/wwt/ansible-playbooks/redfish-ansible-2.7-tests/facts.yml:9
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: tadej
<127.0.0.1> EXEC /bin/sh -c 'echo ~tadej &amp;&amp; sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597 `" &amp;&amp; echo ansible-tmp-1536174086.57-2660084232597="` echo /home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597 `" ) &amp;&amp; sleep 0'
Using module file /home/tadej/xlab/ansible/ansible/venv2/lib/python2.7/site-packages/ansible/modules/remote_management/redfish/redfish_facts.py
<127.0.0.1> PUT /home/tadej/.ansible/tmp/ansible-local-2609QiUJEu/tmpED3mGl TO /home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/AnsiballZ_redfish_facts.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/ /home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/AnsiballZ_redfish_facts.py &amp;&amp; sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/home/tadej/xlab/ansible/ansible/venv2/bin/python2 /home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/AnsiballZ_redfish_facts.py &amp;&amp; sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/ > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
The full traceback is:
Traceback (most recent call last):
File "/home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/AnsiballZ_redfish_facts.py", line 113, in <module>
_ansiballz_main()
File "/home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/AnsiballZ_redfish_facts.py", line 105, in _ansiballz_main
invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
File "/home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/AnsiballZ_redfish_facts.py", line 48, in invoke_module
imp.load_module('__main__', mod, module, MOD_DESC)
File "/tmp/ansible_redfish_facts_payload_Yfsq9X/__main__.py", line 267, in <module>
File "/tmp/ansible_redfish_facts_payload_Yfsq9X/__main__.py", line 206, in main
File "/tmp/ansible_redfish_facts_payload_Yfsq9X/ansible_redfish_facts_payload.zip/ansible/module_utils/redfish_utils.py", line 861, in get_psu_inventory
KeyError: u'Model'

fatal: [localhost]: FAILED! => {
"changed": false,
"module_stderr": "Traceback (most recent call last):\n  File \"/home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/AnsiballZ_redfish_facts.py\", line 113, in <module>\n    _ansiballz_main()\n  File \"/home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/AnsiballZ_redfish_facts.py\", line 105, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/tadej/.ansible/tmp/ansible-tmp-1536174086.57-2660084232597/AnsiballZ_redfish_facts.py\", line 48, in invoke_module\n    imp.load_module('__main__', mod, module, MOD_DESC)\n  File \"/tmp/ansible_redfish_facts_payload_Yfsq9X/__main__.py\", line 267, in <module>\n  File \"/tmp/ansible_redfish_facts_payload_Yfsq9X/__main__.py\", line 206, in main\n  File \"/tmp/ansible_redfish_facts_payload_Yfsq9X/ansible_redfish_facts_payload.zip/ansible/module_utils/redfish_utils.py\", line 861, in get_psu_inventory\nKeyError: u'Model'\n",
"module_stdout": "",
"msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
"rc": 1
}
to retry, use: --limit @/home/tadej/xlab/wwt/ansible-playbooks/redfish-ansible-2.7-tests/facts.retry

PLAY RECAP ************************************************************************************************************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1

# Fixed code
def get_nic_inventory(self):
    result = {}
    nic_list = []
    nic_results = []
    key = "EthernetInterfaces"
    # Get these entries, but does not fail if not found
    properties = [
        "Description",
        "FQDN",
        "IPv4Addresses",
        "IPv6Addresses",
        "NameServers",
        "PermanentMACAddress",
        "SpeedMbps",
        "MTUSize",
        "AutoNeg",
        "Status",
    ]

    # Search for 'key' entry and extract URI from it
    response = self.get_request(self.root_uri + self.systems_uri)
    if response["ret"] is False:
        return response
    result["ret"] = True
    data = response["data"]

    if key not in data:
        return {"ret": False, "msg": "Key %s not found" % key}

    ethernetinterfaces_uri = data[key]["@odata.id"]

    # Get a list of all network controllers and build respective URIs
    response = self.get_request(self.root_uri + ethernetinterfaces_uri)
    if response["ret"] is False:
        return response
    result["ret"] = True
    data = response["data"]

    for nic in data["Members"]:
        nic_list.append(nic["@odata.id"])

    for n in nic_list:
        nic = {}
        uri = self.root_uri + n
        response = self.get_request(uri)
        if response["ret"] is False:
            return response
        data = response["data"]

        for property in properties:
            if property in data:
                nic[property] = data[property]

        nic_results.append(nic)
    result["entries"] = nic_results
    return result