ansible yum check update parse output to have list of packages - linux

I want to parse the output of yum check-update ansible equivalent to get only the list of package in human readable format.
My code so far:
- name: check for updates
hosts: localhost
gather_facts: true
tasks:
- name: check for updates (yum)
yum: list=updates update_cache=true
register: yumoutput
when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'
- debug: msg={{ yumoutput.stdout | from_json }}
but I get:
fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ yumoutput.stdout | from_json }}): expected string or buffer"}
EDIT: the complete playbook:
---
- name: check for updates
hosts: localhost
gather_facts: true
tasks:
- name: check for updates (yum)
yum: list=updates update_cache=true
register: yumoutput
when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'
- debug: var=yumoutput
msg: "{{ yumoutput.results | map(attribute='name') | list }}

yum module does not register stdout key ― you can see it using debug: var=yumoutput.
You need to extract the package names from the list of dictionaries, for example:
debug:
msg: "{{ yumoutput.results | map(attribute='name') | list }}"

Some minor syntax errors in the complete playbook. This did it for me
---
- name: check for updates
hosts: localhost
gather_facts: true
tasks:
- name: check for updates (yum)
yum: list=updates update_cache=true
register: yumoutput
when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'
- debug:
msg: "{{ yumoutput.results | map(attribute='name') | list }}"

In addition to the above-mentioned solution. You can use call back plugin for ease of reading the output.
Below is one of the human-readable call-back plugin:
https://github.com/n0ts/ansible-human_log
More info about call back plugins:
http://docs.ansible.com/ansible/devel/plugins/callback.html

Related

how to traverse through each line of a text file in ansible

I have to traverse through package list file which contains list of packages with their architecture. How can I feed those input to my playbook file? I found a way to get the package names alone but architecture version is not coming. This is my package_list file
nginx | x86_64
telnet| x86_64
openssh | i386
This is my playbook
- name: get contents of package.txt
command: cat "/root/packages.txt"
register: _packages
- name: get contents of architecture from packages.txt
command: cat "/root/packages.txt" | awk '{print $3}'
register: _arch
- name: Filter
theforeman.foreman.content_view_filter:
username: "admin"
password: "mypass"
server_url: "myhost"
name: "myfilter"
organization: "COT"
content_view: "M_view"
filter_type: "rpm"
architecture: "{{ _arch }}"
package_name: "{{ item }}"
inclusion: True
loop: "{{ _packages.stdout_lines }}"
loop: "{{ _arch.stdout_lines }}"
Any help would be appreciated
The required output is package name and architecture should be read from packages.txt file through ansible-playbook
try this playbook:
- name: Reproduce issue
hosts: localhost
gather_facts: no
tasks:
- name: get contents of package.txt
command: cat "/root/packages.txt"
register: _packages
- debug:
msg: "package: {{ line.0 }}, arch: {{ line.1 }}"
loop: "{{ _packages.stdout_lines }}"
vars:
line: "{{ item.split('|')|list }}"
result:
ok: [localhost] => (item=nginx | x86_64) => {
"msg": "package: nginx , arch: x86_64 "
}
ok: [localhost] => (item=telnet| x86_64) => {
"msg": "package: telnet, arch: x86_64 "
}
ok: [localhost] => (item=openssh | i386) => {
"msg": "package: openssh , arch: i386 "
}
for your case:
- name: Filter
theforeman.foreman.content_view_filter:
:
:
architecture: "{{ line.1 }}"
package_name: "{{ line.0 }}"
inclusion: True
loop: "{{ _packages.stdout_lines }}"
vars:
line: "{{ item.split('|')|list }}"
following the version of ansible you could write too line: "{{ item | split('|') | list }}"
You need to split up the line into the necessary values by filtering.
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Gahter package list
shell:
cmd: cat package.txt
register: _packages
- name: Show packages
debug:
msg: "Name: {{ item.split('|')[0] }}, Arch: {{ item.split('|')[1] }}"
loop: "{{ _packages.stdout_lines }}"
Further Documentation
Playbook filters - Manipulating strings
Jinja Template Designer - Filters
Further Q&A
Split string into list in Jinja?

Testing a task result which uses a loop?

So the first task is always skipped because RedHat 8 is detected which should trigger the fail module to run but this gets skipped also. Is works fine without the loop though.
- name: installing packages
hosts: ansible2
ignore_errors: true
vars_files: varsfile
tasks:
- name: install software based on OS distro and version
yum:
name: "{{ item.name }}"
state: latest
loop: "{{ packages }}"
when: >
( ansible_distribution == "RedHat" and ansible_distribution_major_version is version('12', '>=') )
or
( ansible_distribution == "CentOS" and ansible_distribution_major_version | int >= 8 )
register: result
- fail:
msg: error {{ ansible_hostname }} does not meet minimum requirements
when: result is skipped
Regarding
So the first task is always skipped because RedHat 8 is detected which should trigger the fail module to run but this gets skipped also.
with a small test setup and a debug task for the variable name to debug
---
- hosts: test.example.com
become: false
gather_facts: true
tasks:
- name: Install software based on OS distro and version
debug:
msg: "{{ ansible_distribution }} {{ ansible_distribution_major_version }}"
register: result
when: ansible_distribution == "RedHat" and ansible_distribution_major_version is version('12', '>=')
with_items: ['pkg1', 'pkg2']
- name: Show result
debug:
var: result
- fail:
msg: "Error: {{ ansible_hostname }} does not meet minimum requirements"
when: result.results[0].skipped
resulting into an output of
TASK [Gathering Facts] ********************************
ok: [test.example.com]
TASK [Show result] ************************************
ok: [test.example.com] =>
result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
changed: false
item: pkg1
skip_reason: Conditional result was False
skipped: true
...
TASK [fail] *******************************************
fatal: [test.example.com]: FAILED! => changed=false
msg: 'Error: test does not meet minimum requirements'
you can see that the loop will create a list.
- name: Show result
debug:
var: result.results | type_debug
TASK [Show result] ****************
ok: [test.example.com] =>
result.results | type_debug: list
Therefore you need to set the Conditional to when: result.results[0].skipped.
Regarding
Is works fine without the loop though.
it is recommended to simplify your use case with the following approach
- name: Install software based on OS distro and version
yum:
name: "{{ packages }}"
state: latest
according the yum module Notes
When used with a loop: each package will be processed individually, it is much more efficient to pass the list directly to the name option.
and as it is faster and consumes less resources. Furthermore the result set and conditionals are less complex.

Ansible Undefined variable in vars_files item but the variable was defined using set_fact

I'm trying to select a local file based on what motherboard version exists on the machine on which Ansible will deploy those files.
So my approach was to use dictionary in format {"<board_name>" : "<local_file>.yml"}. And use this dictionary to populate a new variable (pcu_config here) that will finally store the name of the file to be used by ansible. I've gotten so far as shown in my implementation, and I'm get undefined variable error at line
vars_files:
- "{{ playbook_dir }}/pcu_config/{{ pcu_config }}"
But as can be seen in the debug msg in the image of the output just before this play, pcu_config is indeed defined(and is the correct filename too).
- name: Find the pcu_config
hosts: vehicle
gather_facts : no
vars:
pcu_config_dict:
VirtualBox: virtual.yml
n1: n1.yml
n2: n2.yml
n3: n3.yml
n4a: n4a.yml
n4b: n4b.yml
tasks:
- name: Find the motherboard name
shell: cat /sys/devices/virtual/dmi/id/board_name
register: board_name
- name: Find the motherboard version
shell: cat /sys/devices/virtual/dmi/id/chassis_version
register: board_version
- debug:
msg: "board_name : {{ board_name.stdout }}, board_version: {{ board_version.stdout }}, {{pcu_config_dict}} "
- name: Assign the PCU_config file for other than n4's
set_fact:
pcu_config: '{{pcu_config_dict[ board_name.stdout | default("this cpu does not exist in the dict")] | default("") }}'
when: board_name.stdout != "n4"
- name: Assign the PCU_config file for n4
set_fact:
pcu_config: '{{pcu_config_dict[board_version.stdout | default("this cpu_version does not exist in the dict")] | default("") }}'
when: board_name.stdout == "n4"
- name : Check pcu_config is available elsewhere in playbook
hosts: vehicle
tasks:
- debug:
msg: "{{ pcu_config }}, {{ playbook_dir }}"
- name: Deploy software to vehicle
hosts: vehicle
vars_files:
- "{{ playbook_dir }}/pcu_config/{{ pcu_config }}"
- "{{ playbook_dir }}/os_config/deb-files-cache.yml"
- "{{ playbook_dir }}/os_config/python_dep.yml"
roles:
- role: logger_network
tags: base
Here is the output when I run this playbook on my virtual machine.
Suggestions welcome to solve the X or Y problem.(ref #Zeitounator's comment)
Not the best approach but to access the variables set by set_facts elsewhere in the playbook, using cacheable: yes works.
- name: Assign the PCU_config file for other than n4's
set_fact:
pcu_config: '{{pcu_config_dict[ board_name.stdout | default("this cpu does not exist in the dict")] | default("") }}'
cacheable: yes
when: board_name.stdout != "n4"
- name: Assign the PCU_config file for n4
set_fact:
pcu_config: '{{pcu_config_dict[board_version.stdout | default("this cpu_version does not exist in the dict")] | default("") }}'
cacheable: yes
when: board_name.stdout == "n4"

Getting a list of yum updates via ansible fails

- hosts: all
gather_facts: false
become: yes
user: username
tasks:
- name: List Available Patches (Non-Kernel)
yum:
list: updates
update_cache: true
exclude: kernel*
register: yumoutput
- debug: msg="{{ inventory_hostname}} {{ yumoutput.results }}"
MSG:
Unsupported parameters for (yum) module: register Supported parameters
include: allow_downgrade, bugfix, conf_file, disable_gpg_check,
disable_plugin, disablerepo, enable_plugin, enablerepo, exclude,
install_repoquery, installroot, list, name, security, skip_broken, state,
update_cache, update_only, validate_certs
to retry, use:
ansible --version
ansible 2.6.5
Same issue on 2.7.5 version.
This seems to be an indention error. register has to be on the same column as yum.
- hosts: all
gather_facts: false
become: yes
user: username
tasks:
- name: List Available Patches (Non-Kernel)
yum:
list: updates
update_cache: true
exclude: kernel*
register: yumoutput
- debug: msg="{{ inventory_hostname}} {{ yumoutput.results }}"

Why Ansible didn't see attribute in variable?

I have Ansible role "db" with simple task:
- name: Check repos
apt_repository: repo="{{ item.repo }}" state={{ item.state }}
with_items:
- "{{ apt_repos }}"
In /defaults/mail.yml:
apt_repos:
# Percona
- { state: present, repo: 'deb http://repo.percona.com/apt wheezy main', keyserver: 'keyserver.ubuntu.com', key: '1C4CBDCDCD2EFD2A', needkey: True }
- { state: present, repo: 'deb-src http://repo.percona.com/apt wheezy main', needkey: False }
When i try to run this ansible-playbook:
---
- hosts: test
roles:
- db
i see error:
fatal: [10.10.10.10] => One or more undefined variables: 'unicode object' has no attribute 'repo'
FATAL: all hosts have already failed -- aborting
But i have another role with same task and variable and it work perfectly. What's wrong?
You want to be doing this:
with_items: apt_repos
apt_repos is a list. By referencing it as - "{{ apt_repos }}" the extra - is turning it into a list of lists. You also don't need the quotes or braces in this case - those are pretty much just redundant in this type of situation.

Resources