Q: "Set env variable SYSTEM_VERSION by reading a file that is updated during playbook execution."
A: You can set environment in a play, role, block, or task. See Playbook Keywords. If you must read the value during the execution of the playbook set the environment to a block. For example, the playbook
- hosts: test_11
gather_facts: false
tasks:
- file:
state: directory
path: system-versions
- shell: uname -sr > system_version.txt
- fetch:
src: system_version.txt
dest: system-versions
- block:
- command: 'echo $SYSTEM_VERSION'
register: result
- debug:
var: result.stdout
environment:
SYSTEM_VERSION: "{{ lookup('file', system_version_path) }}"
vars:
system_version_path: "system-versions/{{ inventory_hostname}}/system_version.txt"
creates the dictionary system-versions where the files will be stored. The next task creates the file system_version.txt at the remote host
shell> ssh admin@test_11 cat system_version.txt
FreeBSD 13.0-RELEASE
The next task fetches the file and stores it in the directory system-versions/test_11
shell> cat system-versions/test_11/system_version.txt
FreeBSD 13.0-RELEASE
The block then reads this file at the controller and sets the environment for the tasks in the block
TASK [debug] *********************************************
ok: [test_11] =>
result.stdout: FreeBSD 13.0-RELEASE
The next option is to fetch the files in the 1st play and use them in the 2nd play. For example, given the files at the remote hosts
shell> ssh admin@test_11 cat system_version.txt
System A
shell> ssh admin@test_12 cat system_version.txt
System B
The playbook
- hosts: test_11,test_12
gather_facts: false
tasks:
- file:
state: directory
path: system-versions
run_once: true
- fetch:
src: system_version.txt
dest: system-versions
- hosts: test_11,test_12
gather_facts: false
vars:
system_version_path: "system-versions/{{ inventory_hostname}}/system_version.txt"
environment:
SYSTEM_VERSION: "{{ lookup('file', system_version_path) }}"
tasks:
- command: 'echo $SYSTEM_VERSION'
register: result
- debug:
var: result.stdout
fetches the files in the 1st play
shell> cat system-versions/test_11/system_version.txt
System A
shell> cat system-versions/test_12/system_version.txt
System B
and set the environment in the 2nd play. Gives (abridged)
TASK [debug] ***********************************************
ok: [test_11] =>
result.stdout: System A
ok: [test_12] =>
result.stdout: System B
Notes
Ansible works by connecting to your nodes and pushing out scripts called “Ansible modules” to them. Most modules accept parameters that describe the desired state of the system. Ansible then executes these modules (over SSH by default), and removes them when finished. ...
- You can take a look at what environment a module is working in. For example, given the inventory
shell> cat hosts
[test]
test_11
[test:vars]
ansible_connection=ssh
ansible_user=admin
the playbook
shell> cat playbook.yml
- hosts: test_11
gather_facts: false
tasks:
- command: '/bin/sh -c set'
register: result
- debug:
var: result.stdout
gives when you enable connection debugging (-vvvv)
shell> ansible-playbook -i hosts playbook.yml -vvvv
...
<test_11> ESTABLISH SSH CONNECTION FOR USER: admin
<test_11> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="admin"' -o ConnectTimeout=10 -o ControlPath=/export/home/vlado.config/.ansible/cp/9d96571b11 -tt test_11 '/bin/sh -c '"'"'/usr/local/bin/python3.8 /home/admin/.ansible/tmp/ansible-tmp-1649217448.1346543-1545740-216049530990371/AnsiballZ_command.py && sleep 0'"'"''
<test_11> (0, b'\r\n{"changed": true, "stdout": "BLOCKSIZE=K\nHOME=/home/admin\nIFS=$' \\t\n'\nLANG=C.UTF-8\nLOGNAME=admin\nMAIL=/var/mail/admin\nMM_CHARSET=UTF-8\nOPTIND=1\nPATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/admin/bin\nPPID=26056\nPS1='$ '\nPS2='> '\nPS4='+ '\nPWD=/home/admin\nSHELL=/bin/sh\nSSH_CLIENT='10.1.0.184 50874 22'\nSSH_CONNECTION='10.1.0.184 50874 10.1.0.61 22'\nSSH_TTY=/dev/pts/0\nTERM=xterm-256color\nUSER=admin", "stderr": "", "rc": 0, "cmd": ["/bin/sh", "-c", "set"], "start": "2022-04-06 03:57:29.500158", "end": "2022-04-06 03:57:29.516366", "delta": "0:00:00.016208", "msg": "", "invocation": {"module_args": {"_raw_params": "/bin/sh -c set", "_uses_shell": false, "warn": false, "stdin_add_newline": true, "strip_empty_ends": true, "argv": null, "chdir": null, "executable": null, "creates": null, "removes": null, "stdin": null}}}\r\n', b'OpenSSH_8.2p1 Ubuntu-4ubuntu0.2, OpenSSL 1.1.1f 31 Mar 2020\r\ndebug1: Reading configuration data /home/vlado/.ssh/config\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug1: /etc/ssh/ssh_config line 2: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug2: mux_client_hello_exchange: master version 4\r\ndebug3: mux_client_forwards: request forwardings: 0 local, 0 remote\r\ndebug3: mux_client_request_session: entering\r\ndebug3: mux_client_request_alive: entering\r\ndebug3: mux_client_request_alive: done pid = 1545744\r\ndebug3: mux_client_request_session: session request sent\r\ndebug3: mux_client_read_packet: read header failed: Broken pipe\r\ndebug2: Received exit status from master 0\r\nShared connection to test_11 closed.\r\n')
result.stdout: |-
BLOCKSIZE=K
HOME=/home/admin
IFS=$' \t
'
LANG=C.UTF-8
LOGNAME=admin
MAIL=/var/mail/admin
MM_CHARSET=UTF-8
OPTIND=1
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/admin/bin
PPID=26008
PS1='$ '
PS2='> '
PS4='+ '
PWD=/home/admin
SHELL=/bin/sh
SSH_CLIENT='10.1.0.184 50834 22'
SSH_CONNECTION='10.1.0.184 50834 10.1.0.61 22'
SSH_TTY=/dev/pts/0
TERM=xterm-256color
USER=admin
- Optionally, you can let Ansible collect the facts
shell> cat playbook.yml
- hosts: test_11
gather_facts: true
tasks:
- debug:
var: ansible_env
gives
ansible_env:
BLOCKSIZE: K
HOME: /home/admin
LANG: C.UTF-8
LOGNAME: admin
MAIL: /var/mail/admin
MM_CHARSET: UTF-8
PATH: /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/admin/bin
PWD: /home/admin
SHELL: /bin/sh
SSH_CLIENT: 10.1.0.184 51008 22
SSH_CONNECTION: 10.1.0.184 51008 10.1.0.61 22
SSH_TTY: /dev/pts/0
TERM: xterm-256color
USER: admin
For example, the playbook
- hosts: test_11
gather_facts: false
tasks:
- shell: 'echo $SHELL'
register: result
- debug:
var: result.stdout
- shell: 'export MYVAR1=test; echo $MYVAR1'
register: result
- debug:
var: result.stdout
- shell: 'echo $MYVAR1'
register: result
- debug:
var: result.stdout
gives
TASK [shell] ********************************************************
changed: [test_11]
TASK [debug] ********************************************************
ok: [test_11] =>
result.stdout: /bin/sh
TASK [shell] ********************************************************
changed: [test_11]
TASK [debug] ********************************************************
ok: [test_11] =>
result.stdout: test
TASK [debug] ********************************************************
changed: [test_11]
TASK [debug] ********************************************************
ok: [test_11] =>
result.stdout: ''
- You can see that the environment variable hasn't been set persistently. Each module creates a new login. The solution is using the keyword environment. For example
- hosts: test_11
gather_facts: false
environment:
MYVAR1: test
tasks:
- shell: 'echo $MYVAR1'
register: result
- debug:
var: result.stdout
gives as expected
result.stdout: test