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!
1 Like

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…

1 Like

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:

Hi Mark,

Thanks for your help.

I cloned the ansible repo, created a new branch based on devel branch. Then I did my file edits.

When I try to push my branch, I see this:

$ git push origin fredjupp_aix_setup

ERROR: Permission to ansible/ansible.git denied to fredjupp.

fatal: Could not read from remote repository.

Please make sure you have the correct access rights

and the repository exists.

$git remote -v

origin git@github.com:ansible/ansible.git (fetch)

origin git@github.com:ansible/ansible.git (push)

I have added my pub key to my account. So access should work. Looks like, I have not push rights to the ansible repo.

How can I get around this?

Cheers

Klaus (aka fredjupp)

Klaus,

To submit a pull request, you can fork the repo so you have a copy in your own Github account. Then you can push your changes to your own copy, and submit a pull request to request to merge the changes from your copy into the main copy.

My favorite way to manage this flow is using the Github CLI, which might be a good choice if use the command like regularly and may submit multiple PRs to things.

With that tool, here’s what the flow would be. From your branch you’ve made, you would use:

gh pr create

From there, an interactive command would launch that would help you set up a fork, push the branch there, and submit the PR.

Otherwise, you could you do the steps more manually, using the Github website to fork the repo and later to submit the PR once you pushed your fork.