3

I'm trying to make a report with installed packages and their version from a couple of machines.

The report must be created on the machine from where the playbook is executed.

Here is my current playbook


---
- name: main
  hosts: all
  gather_facts: no
  become: true
  tasks:
  - setup:
        gather_subset:
         - '!all'

  - name: Gather rpm packages
    package_facts:
          manager: auto
    ignore_errors: true

  - name: Create the result file
    local_action:
     module: copy
     content: |
          {% for h in groups.all %}
          {{h}}; OS: {{hostvars[h]['ansible_distribution']|default('N/A')}}; Release: {{hostvars[h]['ansible_distribution_version']|default('N/A')}}

          List of instaled packages:.......
          #==============================================
          {% for k,v  in  hostvars[h].ansible_facts.packages.iteritems() %}
          package {{ k.rjust(24) }}      version {{ v[0].version }}
          {%endfor%}
          #==============================================
          {%endfor%}
     dest: '/reports/OS_info.txt'

Which is run with

ansible-playbook -i rh_inventory  -u ansuser02  os_extract_info.yml

Now, if all hosts are reachable, the report is created, however, if one or more hosts are unreachable the playbook execution fails with:

fatal: [INFRA-116]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'packages'

And I can't figure out what could be the best approach to overcome this issue.

β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83

2 Answers2

3

You have to apply a default filter to that fact, as you did for the other information:

hostvars[h].ansible_distribution | default('N/A')

In this case, since you want to loop over the key / value pair of a dictionary, you can default the packages fact to any empty one:

{% for k, v in (hostvars[h].packages | default({})).items() %}
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
0

After a really exhaustive research I found out the procedure:

First in the playbook set the fact installed_packages:

- name: Gather the package facts
  package_facts:
    manager: auto

- name: Get only list of name of installed packages
  set_fact:
    installed_packages: "{{ ansible_facts.packages.keys() }}"

Secondly, define the jinja2 template as follows:

{% for item in installed_packages %}
{{ item }} = {{ ansible_facts.packages.get(item).0.version }}
{% endfor %}

The output/template produces the package inventory in the target server(s).

Kevin C
  • 4,851
  • 8
  • 30
  • 64