ansible match exact string from register result - ansible

I have below ansible tasks which compares list of packages against register output obtained from yum module.
- hosts: localhost
vars:
pkgs: [ 'git', 'rsync', 'python36' ]
tasks:
- name: stats for installed pkgs
yum:
state: installed
register: installed
- name: Compare against register
set_fact:
unwanted_pkgs: >-
[
{% for value in installed.results %}
{% for pkg in pkgs %}
{% if value.name | regex_search(pkg) %}
" {{ value.name }}",
{% endif %}
{% endfor %}
{% endfor %}
]
- name: print
debug:
msg: "{{ unwanted_pkgs }}"
Upon executing above playbook, debug task print output as :
git
git-core
git-core-doc
python36
python36-devel
While executing the task it prints additional packages (eg: git-core, git-core-doc and python36-devel which I have not defined in pkgs variable). How this can be avoided ?

Is this what you want?
- debug:
msg: |-
{% for value in installed.results %}
{% for pkg in pkgs %}
{% if value.name == pkg %}
{{ value.name }}
{% endif %}
{% endfor %}
{% endfor %}
gives
msg: |-
git
python36
The same can be achieved by intersecting the lists
unwanted_pkgs: "{{ installed.results|map(attribute='name')|intersect(pkgs) }}"
gives
unwanted_pkgs:
- git
- python36

Related

How to exclude an host in Ansible Jinja2 template for-loop?

I have a template named foo.yml.j2 used in an Ansible task to generate a foo.yml file:
{% for host in ansible_play_hosts_all %}
{{ host }},
{% endfor %}
Everything works fine except I need something like the following statement: For every host in ansible_play_hosts_all except for host==bar do this or that.
Is this achievable or the only way to do this is to categorize my hosts in different groups and use ansible_play_hosts_group?
You can use the reject filter to take your host out of the list so that it is not part of your loop:
{% for host in ansible_play_hosts_all | reject('==', 'bar') %}
{{ host }},
{% endfor %}
There are more options. The trivial one is using the condition in Jinja
{% for host in ansible_play_hosts_all %}
{% if host != 'bar' %}
{{ host }},
{% endif %}
{% endfor %}
Fit the format to your needs.
Example of a complete playbook for testing
- hosts: host_1,host_2,host_3
gather_facts: false
tasks:
- debug:
msg: |
{% for host in ansible_play_hosts_all %}
{% if host != 'host_2' %}
{{ host }},
{% endif %}
{% endfor %}
run_once: true
gives (abridged)
msg: |-
host_1,
host_3,
The next option is to remove blacklisted hosts from the loop, e.g.
blacklist: [host_2]
The template below gives the same result
{% for host in ansible_play_hosts_all|difference(blacklist) %}
{{ host }},
{% endfor %}

Add lines to a local file from a Jinja2 Template with Ansible

im a newbie to ansible and got problems with this Task.
I want to get some data from various hosts. The Idea is, to use a jinja2 template, get the data from the host and add this data in to a file local on the Ansible machine.
How is it possible to get all the data in one file on the local machine? The way i try to do it brings me the result from just one host. Thanks for your Help!
---
- name: "Server Report"
hosts: all
tasks:
- name: "check packages"
package_facts:
manager: auto
- name: "get PHP info"
shell: "php -v | grep -E ^PHP | awk '{print $2}'"
register: php_version
when: "'php-common' in ansible_facts.packages"
- name: "get MySQL info"
shell: "mysql -V | awk '{print $5}' | sed 's/,//g'"
register: mysql_version
when: "'mysql-common' in ansible_facts.packages"
- name: "Use Template to create File"
template:
src: vrsn.j2
dest: /opt/data.txt
delegate_to: localhost
This is the Jinjer2 Code:
{% if ansible_facts['hostname'] is defined %}{{ ansible_facts['hostname'] }},{% else %}NoINstalled,{% endif %}
{% if ansible_facts['distribution'] is defined %}{{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }},{% else %}NotInstalled,{% endif %}
{% if php_version.stdout is defined %}{{ php_version.stdout }},{% else %}NotInstalled,{% endif %}
{% if mysql_version.stdout is defined %}{{ mysql_version.stdout }},{% else %}NotInstalled,{% endif %}
{% if ansible_facts.packages['apache2'][0].version is defined %}
apache2-version {{ ansible_facts.packages['apache2'][0].version }},
{% elif ansible_facts.packages['apache'][0].version is defined %}
apache-version {{ ansible_facts.packages['apache'][0].version }},
{% elif ansible_facts.packages['nginx-common'][0].version is defined %}
nginx-version {{ ansible_facts.packages['nginx-common'][0].version }},
{% else %}NotInstalled{% endif %}
I'm not sure I fully understand your output format, but the following example should give you a clue to go on:
vrsn.j2
{% for h in groups['all'] %}
Inventory host: {{ h }}
hostname: {{ hostvars[h].ansible_hostname | default('N/A') }}
distribution: {{ hostvars[h].ansible_distribution | default('N/A') }}
php: {{ hostvars[h].php_version.stdout | default('N/A') }}
# add more here now you got the concept
---
{% endfor %}
And you should call your template like so in your play:
- name: "Dump all host info to local machine"
template:
src: vrsn.j2
dest: /opt/data.txt
delegate_to: localhost
run_once: true

"AnsibleError: template error while templating string: unexpected 'end of statement block'

I have a jinja2 template that looks like this:
token: {{ RANCHER_SERVER_TOKEN}}
server: https://{{ RANCHER_RKE2_SERVER }}:9345
{% endif %}{% if RANCHER_TLS_SAN is defined %}
tls-san:{% for item in RANCHER_TLS_SAN +%}
- {{ item }}{% endfor +%}
{% endif %}
{% if RANCHER_NODE_LABELS is defined %}
node-label:{% for item in RANCHER_NODE_LABELS +%}
- {{ item }}{% endfor +%}
{% endif %}
{% if RANCHER_NODE_TAINTS is defined %}
node-taint:{% for item in RANCHER_NODE_TAINTS +%}
- {{ item }}{% endfor +%}
{% endif %}
in my inventory group in group_vars I have this data structure
---
RANCHER_TLS_SAN:
- k3-crontroller-1.prometheus.internal
RANCHER_NODE_TAINTS:
- "CriticalAddonsOnly=true:NoExecute"
I test it through this link: https://ansible.sivel.net/test/
and it renders out great.
However I get this issue when running the playbook:
fatal: [k3-rancher-controller-1]: FAILED! => {"changed": false, "msg": "AnsibleError: template error while templating string: unexpected 'end of statement block'. String: {%if RANCHER_DOWNSTREAM_SERVER_AGENT_NODE is defined %}\ntoken: {{ RANCHER_SERVER_TOKEN }}\nserver: https://{{ RANCHER_RKE2_SERVER }}:9345\n{% endif %}{% if RANCHER_TLS_SAN is defined %}\ntls-san:{% for item in RANCHER_TLS_SAN +%}\n - {{ item }}{% endfor %}\n{% endif %}\n{% if RANCHER_NODE_LABELS is defined %}\nnode-label:{% for item in RANCHER_NODE_LABELS +%}\n - {{ item }}{% endfor %}\n{% endif %}\n{% if RANCHER_NODE_TAINTS is defined +%}\nnode-taint:{% for item in RANCHER_NODE_TAINTS +%}\n - {{ item }}{% endfor %}\n{% endif %}"}
My playbook looks like this:
---
- name: Create VM for Rancher Kubernetes Control Plane Nodes
hosts: master
gather_facts: no
become: yes
become_user: root
tasks:
- name: create directory /etc/rancher/rke2
file:
path: /etc/rancher/rke2
state: directory
- name: Create template and copy to Agent nodes
template:
src: playbooks/templates/config.j2
dest: /etc/rancher/rke2/config.yaml
I am using ansible 2.9.27.
Does anyone know what is going on?
Any help is much appreciated. Many thanks

Ansible concat vars to string

I've spent most of the day trying to solve this problem and have thus far failed. I am building some playbooks to automate functions in Splunk, and am attempting to convert a list of hosts from an inventory group E.G.
[search_head]
1.2.3.4
5.6.7.8
My expected (desired) result from the debug output of the play should be:
https://1.2.3.4:8089, https://5.6.7.8:8089
I am attempting to complete this by running the following playbook against a running host:
---
- name: Build search head list to initialize the captain
hosts: search_head
remote_user: ansible
vars:
inventory_file: ./inventory-ec2-single-site
search_head_uri: "{{ lookup('template', './bootstrap-sh-deployer.j2') }}"
pre_tasks:
- include_vars:
dir: 'group_vars'
extensions:
- yml
- yaml
tasks:
- name: dump array
debug:
msg: "{{ search_head_uri }}"`
With the template bootstrap-sh-deployer.j2:
{%- set search_head_uri = [] %}
{% for host in groups['search_head'] %}
{%- if search_head_uri.append("https://{{ host }}:8089") %}
{%- endif %}
{%- if not loop.last %}, {% endif -%}
{%- endfor %}
However, the current play returns search_head_uri: ", " which tells me that the loop is running, but {{ host }} is not resolving.
Once you open a Jinja2 expression or a statement you should use Jinja2 syntax. You cannot nest them (i.e. you can't use {{ }} inside {% %}).
{%- if search_head_uri.append("https://" + host + ":8089") %}
This worked - Combination of the answer above to fix jinja formatting and using hostvars to get to the ansible_nodename.
{%- set search_head_uri = [] %}
{% for host in groups['search_head'] %}
{{ "https://" + hostvars[host]['ansible_nodename'] + ":8089" }}
{%- if not loop.last %}, {% endif -%}
{%- endfor %}

Vague deprecation error when running ansible playbook

My playbook contains vars that are passed to a role. When I run it, I get [DEPRECATION WARNING]: Skipping task due to undefined Error, in the future this will be a fatal error..
Here's what I have:
---
- hosts: hadoopL0X
become: yes
become_method: sudo
vars:
logrotate_scripts:
- name: "{{ item }}"
with_items:
- zookeeper
- sa
path: "/var/log{{ item }}/{{ item }}.log "
options:
- daily
- rotate 3
- missingok
- compress
- notifempty
roles:
- log-rotation
...
The role is as such:
log-rotation/tasks/main.yml
---
- name: Setup logrotate.d scripts
template:
src: logrotate.d.j2
dest: "{{ logrotate_conf_dir }}{{ item }}"
with_items: "{{ logrotate_scripts }}"
...
log-rotation/defaults/main.yml
---
logrotate_conf_dir: "/etc/logrotate.d/"
logrotate_scripts: []
...
log-rotation/templates/logrotate.d.j2
# {{ ansible_managed }}
"{{ item.path }}" {
{% if item.options is defined -%}
{% for option in item.options -%}
{{ option }}
{% endfor -%}
{% endif %}
{%- if item.scripts is defined -%}
{%- for name, script in item.scripts.iteritems() -%}
{{ name }}
{{ script }}
endscript
{% endfor -%}
{% endif -%}
}
Any help would be much appreciated!
with_items can only be used with tasks, it cannot be used when defining variables, and because of that item isn't defined. It also looks like that the service variable isn't defined as well.

Resources