Setup module does not return hw-info on AIX VIO servers

setup module returns no hw-info on AIX VIOS.

we run some playbooks against AIX servers. To complete the picture, we decided to also use ansible vor VIO servers.
All AIX servers includings VIOs have python 3.9.16 installed!
We gather facts from all servers using the setup module and save these to files on a central node, where we produce excel sheets from these facts.

This works well for standard AIX (7.2 or 7.3), but we do not see hardware related facts for vio servers.
Here is a code snippet:

- name: "Get facts from server"
  setup:
    gather_subset:
      - 'hardware'
      - 'network'
      - 'virtual'
      - '!facter'
      - '!ohai'

- name: "save to local file"
  copy:
    content: "{{ ansible_facts }}"
    dest: "{{ factfile }}"
    mode: '0644'
  delegate_to: "{{ factfile_host }}"
  become: no
```

I tried to look into the python code and also  added a number of print statements in /usr/lib/python3.9/site-packages/ansible/module_utils/facts/hardware/aix.py
```
    def get_dmi_facts(self):
        dmi_facts = {}

        rc, out, err = self.module.run_command("/usr/sbin/lsattr -El sys0 -a fwversion")
        data = out.split()
        dmi_facts['firmware_version'] = data[1].strip('IBM,')
        lsconf_path = self.module.get_bin_path("lsconf")
        print("# lsconf_path", lsconf_path)
        if lsconf_path:
            rc, out, err = self.module.run_command(lsconf_path)
            if rc == 0 and out:
                print("# out", out)
                for line in out.splitlines():
                    data = line.split(':')
                    if 'Machine Serial Number' in line:
                        dmi_facts['product_serial'] = data[1].strip()
                        print("# prod_ser:", dmi_facts['product_serial'])
                    if 'LPAR Info' in line:
                        dmi_facts['lpar_info'] = data[1].strip()
                    if 'System Model' in line:
                        dmi_facts['product_name'] = data[1].strip()
        print("## dmi_facts:", dmi_facts)
        return dmi_facts

```


The ouput show my print statements, which prove, that the OS-commands are ran correctly from the modified code, but the resulting facts, that are returned, do not contain the infos.

My python/ansible skills end here. Can anyone provides some help. Would be much appreciated!

Looks there’s an opportunity to improve the Ansible docs here about the supported target OSes.

The setup module itself does not mention what OSes it is capable of gathering facts from:

As best as I can tell, the Ansible core docs mention that Python needs to be installed on the target node, but that’s it.

I suspect that this is an OS support issue, but it’s hard to confirm with VIOS being closed source.

You might have luck checking out the ibm.power_vios collection, although it doesn’t specifically document that it has functionality to gather the same facts that setup would.

Hello,
Thanks for replying to my topic. I think, i described the issue ambiguously.
The setup module works for all vio servers, but does not return some facts for a number of vio servers.

I broke this down to vio servers using shared storage pools, which is a nice feature of vios and exists since about 15 years.

Adding print statements to the ansible code and executing the ansiballz-file on the vio server, I could find the place in the source dode, where an errot occurs (IndexError)

It is in …/site-packages/ansible/module_utils/facts/hardware/aix.py:

def get_mount_facts(self):

mount_facts = {}
mount_facts['mounts'] = []

mounts = []

# AIX does not have mtab but mount command is only source of info (or to use
# api calls to get same info)
mount_path = self.module.get_bin_path('mount')
rc, mount_out, err = self.module.run_command(mount_path)
if mount_out:
    for line in mount_out.split('\n'):
        fields = line.split()
        if len(fields) != 0 and fields[0] != 'node' and fields[0][0] != '-' and re.match('^/.*|^[a-zA-Z].*|^[0-9].*', fields[0]):
            if re.match('^/', fields[0]):
                # normal mount
                mount = fields[1]
                mount_info = {'mount': mount,
                              'device': fields[0],
                              'fstype': fields[2],
                              'options': fields[6],
                              'time': '%s %s %s' % (fields[3], fields[4], fields[5])}
                mount_info.update(get_mount_size(mount))

The code references fields[6], but the output for SSPs has only 6 fields. Sample:

     /var/vio/SSP/SSP_NAME/D_E_F_A_U_L_T_061310 /var/vio/SSP/SSP_NAME/D_E_F_A_U_L_T_061310 poolfs Aug 07 21:46

i added two lines adapting the logic for nfs or cifs mounts to the code:

                if re.match('^/', fields[0]):
                    # normal mount
                    if len(fields) < 7:   # KLF # to fix IndexError for SSP mounts
                        fields.append("") # KLF # to fix IndexError for SSP mounts

After these modifications, all facts are returned the same way as on the other vio servers.

I also found another issue in …/site-packages/ansible/module_utils/facts/system/loadavg.py.

The pythons os class for AIX does not have a method os.getloadavg. This leads to an AttributeError, which is not catched by the try/except in the code.

I “fixed” this by modifying the code with

except (OSError, AttributeError): # KLF # added AttributeError

The results looks good to me. Nevertheless, it is not yet in the current ansible code.

I think, i should raise a pull request on github, to get this code into the official repo.

Any ideas, if this would be the correct way?

Thanks a lot…

That’s right, you could submit a pull request and it would be much appreciated!

For an example of another PR that improved AIX support, see here: