Ansible - passing vars from a playbook to another - linux

I am working with Ansible and I have defined a var (varx) in inventory file (inventory1.yml) like this (only for env2):
env1:
hosts:
env1.domain.com:
env2:
hosts:
env2.domain.com:
vars:
varx: 'valuex'
I am running playbook1 and calling playbook2 like this:
ansible-playbook -i inventory/inventory1.yml playbooks/playbook1.yml --extra-vars "env=env1"
playbook1.yml:
---
roles:
- role1
role1 - main.yml:
---
- name: role1
command: bash script.sh {{ env }} {{ 'varx='~varx if varx is defined else '' }}
Inside script.sh (linux bash) I am calling playbook2:
#!/bin/bash
ENV=$1
varx=$2
do_stuff() {
local arguments= "env=$ENV { 'varx='~varx if varx is defined else '' }}"
ansible-playbook -i inventory/inventory2.yml playbook2.yml --extra-vars "$arguments"
}
do_stuff
The idea is to pass varx from inventory1.yml if it exists in inventory1.yml to script.sh when it runs playbook2.yml. If it doesn't exist in inventory1.yml it will look for it in inventory2.yml.
The code as it is its looking for it in inventory2.yml, so I am not being able to retrieve it from inventory1.yml.
I believe that there is some issue in script.sh.
How can I achieve to bring varx from inventory1.yml and if doesn't exist to capture it from inventory2.yml?
I want to make some changes in role1 so that I can pass the vars to script.sh (in a string for example,or in a better way - using ansible-playbook and passing the vars) and than capturing the vars in script.sh and launching playbook2. Any ideas how I can acomplish that?
Basically what I want to do is something like this:
bash script.sh args
and the arguments should all go inside args variable (args= env varx).
What i have done is:
role1 - main.yml:
---
- name: role1
command: bash script.sh arguments
arguments: "{{ env }} {{ 'varx='~varx if varx is defined else '' }}"
But when It reaches script.sh the varx is not being read.

Minimal reproducible example
Given the inventory
shell> cat inventory1
env1:
hosts:
env1.domain.com:
ansible_host: 10.1.0.61
ansible_user: admin
env2:
hosts:
env2.domain.com:
ansible_host: 10.1.0.62
ansible_user: admin
vars:
varX: valueX
, the playbook
shell> cat pb1.yml
- hosts: all
gather_facts: false
tasks:
- command: "sh -c '/tmp/script.sh {{ env }} {{ _varX }}'"
register: out
vars:
_varX: "varX={{ varX|default('') }}"
- debug:
var: out.stdout
, and the scripts at the remote hosts
shell> ssh admin#10.1.0.61 cat /tmp/script.sh
echo ansible-playbook -i inventory2 pb2.yml -e "$1 $2"
shell> ssh admin#10.1.0.62 cat /tmp/script.sh
echo ansible-playbook -i inventory2 pb2.yml -e "$1 $2"
The playbook gives
shell> ansible-playbook -i inventory1 pb1.yml -e "env=env1"
PLAY [all] ************************************************************************************
TASK [command] ********************************************************************************
changed: [env2.domain.com]
changed: [env1.domain.com]
TASK [debug] **********************************************************************************
ok: [env1.domain.com] =>
out.stdout: ansible-playbook -i inventory2 pb2.yml -e env1 varX=
ok: [env2.domain.com] =>
out.stdout: ansible-playbook -i inventory2 pb2.yml -e env1 varX=valueX
PLAY RECAP ************************************************************************************
env1.domain.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
env2.domain.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Fo me it worked like this:
---
- name: role1
command: bash script.sh
env={{env}}
{{ 'varx='~varx if varx is defined else '' }}
In the shell script I capture vars like this:
#!/bin/bash
for arg in "$#"; do
arguments+="$arg "
done
do_stuff() {
ansible-playbook -i inventory/inventory2.yml playbook2.yml --extra-vars "$arguments"
}
do_stuff

Related

Ansible tasks after delegate_to:127.0.0.1 are skipped

My code is as below, I am reading from a local csv file use those values for tasks on remote hosts
---
- name: Empty Topics
hosts: remote_host
gather_facts: no
vars:
kafka_topics: /bin/kafka-topics
bootstrap_server: "list_of_broker_hosts"
retention_ms: 604800000
command_config: /etc/kafka/client.properties
kafka_log_dirs: /usr/bin/kafka-log-dirs
#ansible_connection: ssh
#ansible_user: ansible
#ansible_become: true
tasks:
- name: "Reading Topic Names"
read_csv:
path: topics_list.csv
register: topics
delegate_to: 127.0.0.1
- name: "Setting Topic Retention to 0"
become: yes
become_user: root
shell:
{{ kafka_topics }} --bootstrap_server {{bootstrap_server}} --alter --topic "{{ item.topic_name }}" --config retention.ms=0 --command_config #{{command_config}}
#touch /tmp/producer_test_1
loop: "{{ topics.list }}"
- name: "waiting for size to go zero "
become: yes
become_user: root
shell:
topic_size=1
while [ $topic_size -ne 0 ]
do
topic_size=`{{kafka_log_dirs}} --command_config {{command_config}} --bootstrap_server {{bootstrap_server}} --topic-list "{{ item.topic_name }}" --describe | grep -oP '(?<=size":)\d+' | awk '{ sum += $1 } END { print sum }' `
sleep 40
done
loop: "{{ topics.list }}"
- name : "Setting Topic Retention to 7"
become: yes
become_user: root
shell:
#{{ kafka_topics }} --bootstrap_server {{bootstrap_server}} --alter --topic "{{ item.topic_name }}" --config retention.ms={{retention_ms}} --command_config {{command_config}}
#touch /tmp/producer_test_2
loop: "{{ topics.list }}"
here the tasks after first task "Reading Topic Names" are skipped , if I remove this task, they succeed but that means I have to hard code values on subsequent tasks
execution log as below. How can I avoid this. current ansible version is 2.9.19 This playbook had previously worked as is on ansible version 2.9.6 in my previous organization, not sure what settings may be changed in my new company.
I tried delegate_to: localhost as well as delegate_to: 127:0:0:1
ansible#localhost[~] $ ansible-playbook empty_topics.pb -i /home/ansible/inv_sit.yml -l all
PLAY [Empty Topics] ***********************************************************************************************************
TASK [Reading Topic Names] ****************************************************************************************************
ok: [remotehost]
TASK [Setting Topic Retention to 0] *******************************************************************************************
TASK [waiting for size to go zero] ********************************************************************************************
TASK [Setting Topic Retention to 7] *******************************************************************************************
PLAY RECAP ********************************************************************************************************************
remotehost : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
ansible#localhost[~] $ ansible-playbook empty_topics.pb -i /home/ansible/inv_sit.yml -l all -vvv
ansible-playbook 2.9.19
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/ansible/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 3.6.8 (default, Jun 14 2022, 12:54:58) [GCC 8.5.0 20210514 (Red Hat 8.5.0-10)]
Using /etc/ansible/ansible.cfg as config file
host_list declined parsing /home/ansible/inv_sit.yml as it did not pass its verify_file() method
script declined parsing /home/ansible/inv_sit.yml as it did not pass its verify_file() method
Parsed /home/ansible/inv_sit.yml inventory source with ini plugin
Skipping callback 'actionable', as we already have a stdout callback.
Skipping callback 'counter_enabled', as we already have a stdout callback.
Skipping callback 'debug', as we already have a stdout callback.
Skipping callback 'dense', as we already have a stdout callback.
Skipping callback 'dense', as we already have a stdout callback.
Skipping callback 'full_skip', as we already have a stdout callback.
Skipping callback 'json', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'null', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.
Skipping callback 'selective', as we already have a stdout callback.
Skipping callback 'skippy', as we already have a stdout callback.
Skipping callback 'stderr', as we already have a stdout callback.
Skipping callback 'unixy', as we already have a stdout callback.
Skipping callback 'yaml', as we already have a stdout callback.
PLAYBOOK: empty_topics.pb *****************************************************************************************************
1 plays in empty_topics.pb
PLAY [Empty Topics] ***********************************************************************************************************
META: ran handlers
TASK [Reading Topic Names] ****************************************************************************************************
task path: /home/ansible/empty_topics.pb:18
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: ansible
<127.0.0.1> EXEC /bin/sh -c 'echo ~ansible && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/ansible/.ansible/tmp `"&& mkdir "` echo /home/ansible/.ansibl e/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492 `" && echo ansible-tmp-1672893960.0795922-3957982-94418260356492="` echo /home/ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492 `" ) && sleep 0'
Using module file /usr/lib/python3.6/site-packages/ansible/modules/files/read_csv.py
<127.0.0.1> PUT /home/ansible/.ansible/tmp/ansible-local-3957970ixug96xw/tmpn373dahz TO /home/ansible/.ansible/tmp/ansible-tmp- 1672893960.0795922-3957982-94418260356492/AnsiballZ_read_csv.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492/ /home/ ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492/AnsiballZ_read_csv.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/libexec/platform-python /home/ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-944 18260356492/AnsiballZ_read_csv.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492/ > /dev/ null 2>&1 && sleep 0'
ok: [remotehost] => {
"changed": false,
"dict": {},
"invocation": {
"module_args": {
"delimiter": null,
"dialect": "excel",
"fieldnames": null,
"key": null,
"path": "topics_list.csv",
"skipinitialspace": null,
"strict": null,
"unique": true
}
},
"list": []
}
TASK [Setting Topic Retention to 0] *******************************************************************************************
task path: /home/ansible/empty_topics.pb:23
TASK [waiting for size to go zero] ********************************************************************************************
task path: /home/ansible/empty_topics.pb:31
TASK [Setting Topic Retention to 7] *******************************************************************************************
task path: /home/ansible/empty_topics.pb:42
META: ran handlers
META: ran handlers
PLAY RECAP ********************************************************************************************************************
remotehost : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
ansible#localhost[~] $
I tried delegate_to: localhost as well as delegate_to: 127:0:0:1
As suggested by β.εηοιτ.βε, I checked the csv file, although there were contents , it was missing the header row, hence the issue. Now with header row added to the csv file, the code works.

How to use Ansible to add Linux environment variables

I'm trying to add environment variables to a Linux machine using vars like below:
vars:
app_env_variables:
- key: APP_NAME
value: App demo
- key: APP_ENV
value: demo
- key: APP_KEY
value: xxxxx
I'm using this task to add the variables to /etc/environment.
- name: customize /etc/environment
ansible.builtin.lineinfile:
path: /etc/environment
state: present
regexp: "^{{ item.key }}="
line: "{{ item.key }}={{ item.value }}"
with_items: "{{ app_env_variables }}"
But I'm getting the error below:
TASK [customize /etc/environment] **********************************************
fatal: [default]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'key'\n\nThe error appears to be in 'demo-playbook.yaml': line 423, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n ssh-add /root/.ssh/id_rsa\n - name: customize /etc/environment\n ^ here\n"}
What am I missing here?
The playbook below
shell> cat playbook.yml
- hosts: localhost
vars:
app_env_variables:
- key: APP_NAME
value: App demo
- key: APP_ENV
value: demo
- key: APP_KEY
value: xxxxx
tasks:
- name: customize /tmp/environment
ansible.builtin.lineinfile:
create: true
path: /tmp/environment
state: present
regexp: "^{{ item.key }}="
line: "{{ item.key }}={{ item.value }}"
with_items: "{{ app_env_variables }}"
works as expected
shell> ansible-playbook playbook.yml
PLAY [localhost] *****************************************************************************
TASK [customize /tmp/environment] ************************************************************
changed: [localhost] => (item={'key': 'APP_NAME', 'value': 'App demo'})
changed: [localhost] => (item={'key': 'APP_ENV', 'value': 'demo'})
changed: [localhost] => (item={'key': 'APP_KEY', 'value': 'xxxxx'})
PLAY RECAP ***********************************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
and created the file
shell> cat /tmp/environment
APP_NAME=App demo
APP_ENV=demo
APP_KEY=xxxxx
I only added the parameter create: true to avoid error
msg: Destination /tmp/environment does not exist !
'demo-playbook.yaml': line 423, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem
i think your having some syntax error in your .yaml file

Why can't I capture an environment variable with Ansible?

I am trying to get and print the value of a given environment variable (ENV_VAR):
$ cat ~/.bash_profile
ENV_VAR=Updated
ENV_VAR2=Updated
$ source ~/.bash_profile && echo $ENV_VAR
Updated
I can successfully retrieve it via terminal, however by using the Ansible playbook below I get an error:
# YAML
---
- hosts: all
vars:
env_var: "{{ lookup('env','ENV_VAR') }}"
tasks:
- name: Add/Update an environment variable to the remote user's shell
lineinfile:
dest: ~/.bash_profile
regexp: '^ENV_VAR='
line: "ENV_VAR=Updated2"
- name: Get the value of the environment variable we just added
shell: source ~/.bash_profile && echo $ENV_VAR
register: env_var_updated
- name: Print the value of the environment variable
debug:
msg: "var1: {{ env_var }} - var2 {{ env_var_updated.stdout }}"
Executing:
$ ansible-playbook playbook.yml
PLAY [all] *********************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************
ok: [192.168.0.222]
TASK [Add/Update an environment variable to the remote user's shell] ***********************************************
ok: [192.168.0.222]
TASK [Get the value of the environment variable we just added] *****************************************************
fatal: [192.168.0.222]: FAILED! => {"changed": true, "cmd": "source ~/.bash_profile && echo $ENV_VAR", "delta": "0:00:00.002337", "end": "2020-12-02 10:20:21.963968", "msg": "non-zero return code", "rc": 127, "start": "2020-12-02 10:20:21.961631", "stderr": "/bin/sh: 1: source: not found", "stderr_lines": ["/bin/sh: 1: source: not found"], "stdout": "", "stdout_lines": []}
PLAY RECAP *********************************************************************************************************
192.168.0.222 : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Results after execution:
$ cat ~/.bash_profile
ENV_VAR=Updated2
ENV_VAR2=Updated
$ source ~/.bash_profile && echo $ENV_VAR
Updated2
I am logged as the same user (In the terminal window and SSH for Ansible)
As shown by the following guide:
https://docs.ansible.com/ansible/2.5/modules/shell_module.html
Ansible shell actually runs in /bin/sh and not /bin/bash. You can specify the shell as /bin/bash through:
- name: Get the value of the environment variable we just added
shell: source ~/.bash_profile && echo $ENV_VAR
register: env_var_updated
args:
executable: /bin/bash

Skip current host and print the rest in a config file ansible

Folks, I'm trying to achieve the below while running my task to edit an XML
Requirement:
Skip current host in which config file is created and print the rest of host from the inventory group to the config file
<ManagerNode ip = "**node IP**" port = "**node port**"/> <haNodes>IP2:port,IP3:port</haNodes> <!-- Comma Seperated Node IPs with port, ,Except the Same Node -->
Can anyone help with achieving this goal?
Q: "Skip current host ... and print the rest of hosts from the inventory group."
A: Create a list of all IPs and use filter difference to remove the current IP. For example the inventory
shell> cat hosts
[ha]
test_01 IP=10.1.0.11
test_02 IP=10.1.0.12
test_03 IP=10.1.0.13
[ha:vars]
port=4567
and the playbook
shell> cat playbook.yml
- hosts: ha
tasks:
- set_fact:
all_IP: "{{ groups.ha|map('extract', hostvars, 'IP')|list }}"
run_once: true
- debug:
msg: "{{ all_IP|difference([IP])|
product([port])|
map('join', ':')|
list }}"
give (abridged)
shell> ansible-playbook -i hosts playbook.yml
ok: [test_01] =>
msg:
- 10.1.0.12:4567
- 10.1.0.13:4567
ok: [test_02] =>
msg:
- 10.1.0.11:4567
- 10.1.0.13:4567
ok: [test_03] =>
msg:
- 10.1.0.11:4567
- 10.1.0.12:4567
Limit the play to test_01 gives abridged
shell> ansible-playbook -i hosts -l test_01 playbook.yml
ok: [test_01] =>
msg:
- 10.1.0.12:4567
- 10.1.0.13:4567
defined a variable
tg_hosts: : "{{ groups['tgzone']|map('extract',hostvars,'ansible_host')|list }}"
used template as:
{{ tg_hosts | difference([ansible_host])| list | join(':port,') + ':port' }}

ansible-playbook extra vars passing from command line

My playbook looks like:
---
- name: Install and configure AD authentication
hosts: test
become: yes
become_user: root
vars:
hostname: "{{ host_name }}"
vars_prompt:
- name: "bind_password"
prompt: "Password for xxx.local\\user"
private: yes
tasks:
- name: Ansible prompt example.
debug:
msg: "{{ bind_password }}"
- name: Ansible prompt example.
debug:
msg: "{{ host_name }}"
and i am using below command to pass the variable
ansible-playbook hostname_set.yml --extra-vars "host_name= 'xxx.xxx.local'"
but i am not getting exact variable value what i am using for setting up hostname.
Password for xxx.xxx\user:
PLAY [Install and configure AD authentication]
TASK [Gathering Facts]
ok: [x.x.x.x]
TASK [Ansible prompt example.]
ok: [x.x.x.x] => {
"msg": "wel"
}
TASK [Ansible prompt example.]
ok: [x.x.x.x] => {
"msg": ""
}
TASK [Setup the hostname]
changed: [x.x.x.x]
PLAY RECAP
x.x.x.x : ok=4 changed=1 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
You have an extra space in your command line that ruins how ansible is interpreting the extra vars. Just remove it:
--extra-vars "host_name='xxx.xxx.local'"
Note that you don't even need all those quotes. The following should also work as expected:
--extra-vars host_name=xxx.xxx.local

Resources