Issue passing nested variable as parameter to ansible shell module - shell

I'm not able to figure out how I can pass a nested variable as parameter to Ansible's shell module & invoke the script "check.sh" however, below is what I tried.
---
- name: "Find the details here "
hosts: localhost
tasks:
- name: set_fact
set_fact:
fpath_APP: "{{ fpath_APP + [ item.split('.')[0] ~ '/' ~ item | basename ] }}"
with_items:
- "{{ Source_Files.split(',') }}"
vars:
fpath_APP: []
- name: Invoke shell script
- shell: "./check.sh {{ Number }} '{{ vars['fpath_' + Layer] }}' > hello.txt"
tasks:
- name: Ansible find files multiple patterns examples
find:
paths: /home/examples
patterns: "*.db"
recurse: yes
register: files_matched
- name: Search for Number in the matched files
command: grep -i {{ Number }} {{ item.path }}
with_items:
- "{{ files_matched.files }}"
The above playbook runs but does not invoke the shell module and completes without doing anything. See Output below:
$ ansible-playbook fpath.yml -e " Source_Filenames=/tmp/logs/filename1.src,/tmp/logs/33211.sql,/app/axmw/Jenkins/file1.mrt
Layer=APP Number=57550" [WARNING]: provided hosts list is empty, only
localhost is available. Note that the implicit localhost does not
match 'all'
[WARNING]: While constructing a mapping from fpath.yml, line 2,
column 3, found a duplicate dict key (tasks). Using last defined value
only.
PLAY [Find the details here]
**************************************************************************************************************************************************
TASK [Gathering Facts]
******************************************************************************************************************************************************** ok: [localhost]
PLAY RECAP
******************************************************************************************************************************************************************** localhost : ok=1 changed=0 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0
Below are my failed attempts at changing the shell module syntax:
- shell: "./check.sh {{ Number }} '{{ 'fpath_' + vars[Layer] }}' > hello.txt"
Does not invoke Shell module
- shell: "./check.sh {{ Number }} '/"{{ vars['fpath_' + Layer] }}/"' > hello.txt"
Gives Syntax Error.
- shell: "./check.sh {{ Number }} /"'{{ vars['fpath_' + Layer] }}'/" > hello.txt"
Gives Syntax Error.
I'm on the latest version of ansible and python version is 2.7.5.

You want to use the vars lookup plugin: https://docs.ansible.com/ansible/latest/plugins/lookup/vars.html
For your example, above you would want to do:
- shell: "./check.sh {{ Number }} {{ lookup('vars', 'fpath_' + Layer) }}" > hello.txt"

Related

How to calculate ansible_uptime_seconds and output this in os.csv

I am trying to create a csv file that can be used to review certain systems details. One of these items is the system uptime, which is reflected in unix seconds. But in the os.csv output file I would like to see it as days, HH:MM:SS.
Below my yaml script:
---
- name: playbook query system and output to file
hosts: OEL7_systems
vars:
output_file: os.csv
tasks:
- block:
# For permisison setup.
- name: get current user
command: whoami
register: whoami
run_once: yes
- name: clean_file
copy:
dest: "{{ output_file }}"
content: 'hostname,distribution,version,release,uptime'
owner: "{{ whoami.stdout }}"
run_once: yes
- name: fill os information
lineinfile:
path: "{{ output_file }}"
line: "{{ ansible_hostname }},\
{{ ansible_distribution }},\
{{ ansible_distribution_version }},\
{{ ansible_distribution_release }},\
{{ ansible_uptime_seconds }}"
# Tries to prevent concurrent writes.
throttle: 1
delegate_to: localhost
Any help is appreciated.
tried several conversions but can't get it to work.
There is actually a (somewhat hard to find) example in the official documentation on complex data manipulations doing exactly what you are looking for (check at the bottom of the page).
Here is a full example playbook to run it on localhost
---
- hosts: localhost
tasks:
- name: Show the uptime in days/hours/minutes/seconds
ansible.builtin.debug:
msg: Uptime {{ now().replace(microsecond=0) - now().fromtimestamp(now(fmt='%s') | int - ansible_uptime_seconds) }}
which gives on my machine:
PLAY [localhost] ************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************
ok: [localhost]
TASK [Show the uptime in days/hours/minutes/seconds] ************************************************************************************************************
ok: [localhost] => {
"msg": "Uptime 1 day, 3:56:34"
}
PLAY RECAP ******************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Evaluate variable lazily

I have a variable reference to a variable that is not known when the Playbook starts and the reference is evaluated. Is there a way to lazy load the variable when it is actually accessed?
In the inventory:
all:
hosts:
l01lin08:
bamboo_agents_it:
- bamboo_agent_app_name: bamboo-agent-it
bamboo_agent_install_dir: /data/bamboo-agent-it
bamboo_agent_capabilities: "{{ bamboo_agent_capabilities_it }}"
- # ...
- # ...
bamboo_agent_capabilities_it:
# Error: bamboo_agent_install_dir is not known when evaluating the variable
capabilitiy: '{{ bamboo_agent_install_dir }}/bla/blubb'
another.one: 123
is.something: true
bamboo_agent_capabilities_it.capability references to bamboo_agents_it[].bamboo_agent_install_dir which is not known in this context.
The capabilities is a set of key-value-pairs which can be everything. The values are not always paths and the keys are not always the same. Thus I cannot tell when to add a parent path and when not in the target task.
In the playbook I call a role in a loop over bamboo_agents_it:
tasks:
Install all bamboo agents
- include_role:
name: bamboo-agent-linux
vars:
bamboo_agent_app_name: '{{ item.bamboo_agent_app_name }}'
bamboo_agent_install_dir: '{{ item.bamboo_agent_install_dir }}'
bamboo_agent_capabilities: '{{ item.bamboo_agent_capabilities }}'
loop: '{{ bamboo_agents_it }}'
In this loop item.bamboo_agent_install_dir is available but I want to have a generic config definition. I don't want to handle these single keys separately.
Is there a way to solve this problem in a generic way?
Maybe can I lazyload the variable in the task when it is accessed?
A workaround I'm using is to replace a placeholder insteed. But I hope there is more idiomatic way:
# Inventory
bamboo_agent_capabilities_it:
# Error: bamboo_agent_install_dir is not known when evaluating the variable
capabilitiy: '[bamboo_agent_install_dir]/bla/blubb'
# Task:
lineinfile:
path: '{{ bamboo_agent_install_dir }}/bin/bamboo-capabilities.properties'
line: '{{ item.key }}={{ item.value | replace("[bamboo_agent_install_dir]", bamboo_agent_install_dir) }}'
loop: '{{ bamboo_agent_default_capabilities | dict2items + bamboo_agent_capabilities | dict2items }}'
What you could do is to declare the name that you would expect the variable to be named after:
bamboo_agent_capabilities_it:
capability: /foo/bar
dir: bamboo_agent_install_dir
Then use the vars lookup to fetch the value of that variable, for example:
bamboo_agent_capabilities: "{{ lookup('vars', item.bamboo_agent_capabilities.dir) }}{{ item.bamboo_agent_capabilities.capability }}"
Given the playbook:
- hosts: localhost
gather_facts: no
vars:
bamboo_agents_it:
- bamboo_agent_capabilities: "{{ bamboo_agent_capabilities_it }}"
bamboo_agent_capabilities_it:
capability: /foo/bar
dir: bamboo_agent_install_dir
tasks:
- set_fact:
bamboo_agent_install_dir: /path/to/dir
- debug:
msg:
bamboo_agent_capabilities: "{{ lookup('vars', item.bamboo_agent_capabilities.dir) }}{{ item.bamboo_agent_capabilities.capability }}"
loop: "{{ bamboo_agents_it }}"
This yields:
PLAY [localhost] ***************************************************************************************************
TASK [set_fact] ****************************************************************************************************
ok: [localhost]
TASK [debug] *******************************************************************************************************
ok: [localhost] => (item={'bamboo_agent_capabilities': {'capability': '/foo/bar', 'dir': 'bamboo_agent_install_dir'}}) =>
msg:
bamboo_agent_capabilities: /path/to/dir/foo/bar
PLAY RECAP *********************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

How store full host name as variable in ansible?

I need to use one out of two hosts as a variable. I do have inventory_hostname_short of both but I need a full host as a variable. Currently, for testing I am using a hardcoded value. My playbook will run on both hosts at a same time so How I can identify and store as a variable.
host_1_full = 123.abc.de.com
host_2_full = 345.abc.de.com
above both are hosts and I do have
---
- name: Ansible Script
hosts: all
vars:
host1_short : '123'
host2_short : '345'
tasks:
- name: set host
set_fact:
host1_full: "{{inventory_hostname}}"
when: inventory_hostname_short == host1_short
- name: print info
debug:
msg: "host - {{host1_full}}"
- name: block1
block:
- name:running PS1 file
win_shell: "script.ps1"
register: host1_output
when: inventory_hostname_short == host1_short
- name: block2
block:
- name: set host
set_fact:
IN_PARA: "{{ hostvars[host1_full]['host1_output']['stdout']}}"
- name:running PS1 file
win_shell: "main.ps1 -paramater {{ IN_PARA }}"
register: output
when: inventory_hostname_short == host2_short
SO to access any file from different host required full hostname. How can I get that full host name
Given the following inventories/test_inventory.yml
---
all:
hosts:
123.abc.de.com:
345.abc.de.com:
ansible will provide the needed result in inventory_hostname automagically as demonstrated by the following test.yml playbook
---
- name: print long and short inventory name
hosts: all
gather_facts: false
tasks:
- name: print info
debug:
msg: "Host full name is {{ inventory_hostname }}. Short name is {{ inventory_hostname_short }}"
which gives:
$ ansible-playbook -i inventories/test_inventory.yml test.yml
PLAY [print long and short inventory name] *********************************************************************************************************************************************************************************************
TASK [print info] **********************************************************************************************************************************************************************************************************************
ok: [345.abc.de.com] => {
"msg": "Host full name is 345.abc.de.com. Short name is 345"
}
ok: [123.abc.de.com] => {
"msg": "Host full name is 123.abc.de.com. Short name is 123"
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
123.abc.de.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
345.abc.de.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
As already suggested, the ansible_hostname and ansible_fqdn are automatic facts about hosts in your inventory. However, your requirement is a little unique. So we might have to apply a unique method to accomplish this. How about something like this?
Consider example inventory as below:
---
all:
hosts:
192.168.1.101: # 123.abc.de.com
192.168.1.102: # 345.abc.de.com
We can have a play like this:
- hosts: all
vars:
host1_short: 123
host2_short: 345
tasks:
- command: "hostname -f"
register: result
- block:
- set_fact:
host1_full: "{{ result.stdout }}"
- debug:
msg: "Host1 fullname: {{ host1_full }}"
when: host1_short in result.stdout

Using multi-valued variable in a playbook

I am following the redhat ansible course online and I followed the below steps to use multi-valued variable in a playbook. But I am hitting an error stating there's an undefined variable
Below is my arrays.yaml file
---
- name: show arrays
hosts: ansible1.example.com
vars_files:
- vars/users
tasks:
- name: print array values
debug:
msg: "User {{ item.username }} has homedirectory {{ item.homedir }} and shell {{ item.shell }}"
with_items: "{{ users }}"
And below is vars/users file
users:
linda:
username: linda
homedir: /home/linda
shell: /bin/bash
gokul:
username: gokul
homedir: /home/gokul
shell: /bin/bash
saha:
username: saha
homedir: /home/gokul/saha
shell: /bin/bash
And below is the error that I am hitting
ansible-playbook arrays.yaml
PLAY [show arrays] *****************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************************************************************************************************
ok: [ansible1.example.com]
TASK [print array values] **********************************************************************************************************************************************************************************************************************************
fatal: [ansible1.example.com]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'username'\n\nThe error appears to be in '/home/ansible/install/arrays.yaml': line 7, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: print array values\n ^ here\n"}
PLAY RECAP *************************************************************************************************************************************************************************************************************************************************
ansible1.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
However, when I try to refer individual values like below in the playbook, it works fine.
---
- name: show arrays
hosts: ansible1.example.com
vars_files:
- vars/users
tasks:
- name: print array values
debug:
msg: "User {{ users.gokul.username }} has homedirectory {{ users.gokul.homedir }} and shell {{ users.gokul.shell }}"
It's not possible to iterate a dictionary. Either the code or the data should be changed.
1. Change data
Use a list of users instead of a dictionary. For example, the list below
users:
- username: linda
homedir: /home/linda
shell: /bin/bash
- username: gokul
homedir: /home/gokul
shell: /bin/bash
- username: saha
homedir: /home/gokul/saha
shell: /bin/bash
would work as expected
- name: print array values
debug:
msg: "User {{ item.username }}
has homedirectory {{ item.homedir }}
and shell {{ item.shell }}"
loop: "{{ users }}"
2. Change code
It's possible to use the users dictionary with the filter dict2items. For example, the task below would give the same result
- name: print array values
debug:
msg: "User {{ item.value.username }}
has homedirectory {{ item.value.homedir }}
and shell {{ item.value.shell }}"
loop: "{{ users|dict2items }}"

Ansible Playbook - Can't pass variables between tasks in one play

I'm an Ansible AWX newbie. I'm trying to pass a variable between two tasks in a playbook. The playbook looks like this:
---
- name: start
hosts: all
gather_facts: no
tasks:
- name: Check Debian disk space
command: df --output=avail {{ a7_pcap_data_path }}
become: true
become_method: sudo
register: df_output
- name: Show Debian free space
vars:
a7_free_space_mb: "{{ (df_output.stdout_lines[1]|int / 1024)|round(0,'floor') }}"
a7_spare_space_mb: "{{ a7_free_space_mb|int - (a7_capture_volume_mb|int * 1.1) }}" # Allow 10% for safety
debug:
msg: "Spare space: {{ a7_spare_space_mb }} MB"
- name: Pass/fail check
debug:
msg: "Spare space: {{ a7_spare_space_mb }} MB"
The a7_pcap_data_pathand a7_capture_volume_mb are passed in as AWX variables. When I run this from the Job Template in AWX, I get this:
Identity added: /tmp/awx_57_PesTa2/credential_3 (/tmp/awx_57_PesTa2/credential_3)
SSH password:
PLAY [start] *******************************************************************
TASK [Check Debian disk space] *************************************************
changed: [ip-172-31-14-43.eu-west-1.compute.internal]
TASK [Show Debian free space] **************************************************
ok: [ip-172-31-14-43.eu-west-1.compute.internal] => {
"msg": "Spare space: 3020.0 MB"
}
TASK [Pass/fail check] *********************************************************
fatal: [ip-172-31-14-43.eu-west-1.compute.internal]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'a7_spare_space_mb' is undefined\n\nThe error appears to have been in '/var/lib/awx/projects/pre_checks/test.yml': line 21, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Pass/fail check\n ^ here\n"}
PLAY RECAP *********************************************************************
ip-172-31-14-43.eu-west-1.compute.internal : ok=2 changed=1 unreachable=0 failed=1
The variable a7_spare_space_mb obviously is available in the task Show Debian free space but not in the subsequent task.
It appears that the scope of the a7_spare_space_mb variable is only within the task in which it's defined, but from what I've read, the scope should be the entire playbook.
What am I doing wrong?
Thanks and regards...Paul
An option would be to use set_fact
- set_fact:
a7_free_space_mb: "{{ (df_output.stdout_lines[1]|int / 1024)|round(0,'floor') }}"
a7_spare_space_mb: "{{ a7_free_space_mb|int - (a7_capture_volume_mb|int * 1.1) }}" # Allow 10% for safety
- name: Show Debian free space
debug:
msg: "Spare space: {{ a7_spare_space_mb }} MB"
- name: Pass/fail check
debug:
msg: "Spare space: {{ a7_spare_space_mb }} MB"

Resources