Setting and using environment variable in Ansible - ansible

I want to set one value as an environment variable in Ansible and then use it another playbook.
Below is my playbook:
get_cmd.yaml
[root#a6296ab33a34 test_code]# vi get-cwd.yaml
- hosts: localhost
connection: local
gather_facts: False
tasks:
#- name: Get directory
# shell: export ACWD="{{ playbook_dir }}"
# when: platform == 'jenkins'
- name: Get CWD
shell: "export ACWD=/test_code_demo"
when: platform != 'jenkins'
- name: DEMO
shell: echo $ACWD
Output
[root#a6296ab33a34 test_code]# vi get-cwd.yaml
[root#a6296ab33a34 test_code]# ansible-playbook get-cwd.yaml --extra-vars="#deploy-vars.yaml" -vv
[WARNING] Ansible is being run in a world writable directory (/test_code), ignoring it as an ansible.cfg source. For more information see https://docs.ansible.com/ansible/devel/reference_appendices/config.html#cfg-in-world-writable-dir
ansible-playbook 2.8.4
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 2.7.5 (default, Jun 20 2019, 20:27:34) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
Using /etc/ansible/ansible.cfg as config file
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAYBOOK: get-cwd.yaml *********************************************************************************************************************************************************************************************************************
1 plays in get-cwd.yaml
PLAY [localhost] ***************************************************************************************************************************************************************************************************************************
META: ran handlers
TASK [Get CWD] *****************************************************************************************************************************************************************************************************************************
task path: /test_code/get-cwd.yaml:11
changed: [localhost] => {"changed": true, "cmd": "export ACWD=/test_code_demo", "delta": "0:00:00.713703", "end": "2019-12-13 14:43:37.054390", "rc": 0, "start": "2019-12-13 14:43:36.340687", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [DEMO] ********************************************************************************************************************************************************************************************************************************
task path: /test_code/get-cwd.yaml:15
changed: [localhost] => {"changed": true, "cmd": "echo $ACWD", "delta": "0:00:00.705605", "end": "2019-12-13 14:43:37.919962", "rc": 0, "start": "2019-12-13 14:43:37.214357", "stderr": "", "stderr_lines": [], "stdout": "/test_code_dinesh", "stdout_lines": ["/test_code_dinesh"]}
META: ran handlers
META: ran handlers
PLAY RECAP *********************************************************************************************************************************************************************************************************************************
localhost : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root#a6296ab33a34 test_code]#
You can see, though I have tried to set the value to test_code_demo, still old value test_code_dinesh is reflecting.
Please let me know way to resolve the above issue.

Remember that when you set an environment variable (anywhere, not just in Ansible), it only effects the current process and its children.
When you run something like this:
- name: Get CWD
shell: "export ACWD=/test_code_demo"
when: platform != 'jenkins'
You are:
Spawning a shell
Setting the environment variable ACWD in that shell
Exiting the shell
At this point, the environment is destroyed. There's no way to set an environment variable in one task and have it effect another task. You can set per-task environment variables using the environment key on your task, like this:
- name: DEMO
shell: echo $ACWD
environment:
ACWD: '/test_code_demo'
If you need to apply the environment setting to multiple tasks, you can set it on a play instead:
- hosts: localhost
environment:
ACWD: '/test_code_demo'
tasks:
- command: 'echo $ACWD'
register: output1
- command: 'echo $ACWD'
register: output2
- debug:
msg:
- "{{ output1.stdout }}"
- "{{ output2.stdout }}"

Related

Ansible export variable not working as expected

Inside my Ansible role i'd like to create an export variable which can be used by another script later in the task. But the export is not working for some reason, what am I missing?
- name: export php1_release
shell: export php1_release=8.0
- name: Echo my_env_var again
shell: echo $php1_release
register: php
- debug: var=php
I see the following output:
ok: [example.com] => {
"php": {
"changed": true,
"cmd": "echo $php1_release",
"delta": "0:00:00.003415",
"end": "2022-10-14 20:43:48.084293",
"failed": false,
"msg": "",
"rc": 0,
"start": "2022-10-14 20:43:48.080878",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
Setting an environment only affects the current process and any subprocesses that it spawns. Each shell task in your playbook starts a new, unrelated shell process, so environment variables set in one won't be visible in another (this isn't an Ansible issue; that's just how environment variables work).
You can set the variables with Ansible instead. Here, we set the variables at the play level so they will be visible in all tasks:
- hosts: somehost
environment:
php1_release: "8.0"
tasks:
- name: Echo my_env_var again
shell: echo $php1_release
register: php
- debug:
var: php.stdout
Which will output:
TASK [debug] ********************************************************************************************
ok: [localhost] => {
"php.stdout": "8.0"
}
You can also set environment variables per task:
- hosts: localhost
tasks:
- name: Echo my_env_var again
shell: echo $php1_release
register: php
environment:
php1_release: "8.0"
- debug:
var: php.stdout
This will produce the same output, but the environment variable is only visible in the Echo my_env_var again task.

Ansible Regex: Get a integer from command & pass to other command to run

I have to execute below 2 commands whose value depends on the system.
# sysctl -w kernel.shmmax= parse_from_shm.sh script #For example 17179869184
# sysctl -w kernel.shmall= parse_from_shm.sh script #For example 4194304
./shm.sh will echo both system values required in the below format
kernel.shmmax=4185686016
kernel.shmall=1021896
So I have to parse & get integer value above result & execute ultimately below 2 commands
# sysctl -w kernel.shmmax=4185686016
# sysctl -w kernel.shmall=1021896
I have tried to register & parse the integer values using regex. But I couldn't able to process it perfectly. Any help would be of great help.
---
- hosts: fossology_test
become: true
become_user: root
environment:
HOME: /usr/ansible
gather_facts: no
tasks:
- name: run shell script
become: true
become_user: root
command: ./shm.sh
args:
chdir: /usr/local/src/
register: results
- set_fact:
shmmax: "{{ results.stdout | regex_search(shmmaxregexp, '\\1' ) }}"
shmall: "{{ results.stdout | regex_search(shmallregexp, '\\1' ) }}"
vars:
shmmaxregexp: 'shmmax=([^\"]+)'
shmallregexp: 'shmall=([^\"]+)'
- name: sysctl -w kernel.shmmax="{{ shmmax | int }}"
become: true
become_user: root
command: sysctl -w kernel.shmmax="{{ shmmax | int }}"
- name: sysctl -w kernel.shmall="{{ shmall }}"
become: true
become_user: root
command: sysctl -w kernel.shmall="{{ shmall }}"
This is the output
dinesh#dinesh-VirtualBox:~/Documents/remote/Ansible-Playbook/fossology_playbook$ ansible-playbook regex.yml -K -v
Using /etc/ansible/ansible.cfg as config file
BECOME password:
PLAY [fossology_test] ************************************************************************************
TASK [run shell script] **********************************************************************************
changed: [fossology_test] => {"changed": true, "cmd": ["./shm.sh"], "delta": "0:00:00.005912", "end": "2020-03-28 05:25:42.022156", "rc": 0, "start": "2020-03-28 05:25:42.016244", "stderr": "", "stderr_lines": [], "stdout": "kernel.shmmax=4185686016\nkernel.shmall=1021896", "stdout_lines": ["kernel.shmmax=4185686016", "kernel.shmall=1021896"]}
TASK [set_fact] ******************************************************************************************
ok: [fossology_test] => {"ansible_facts": {"shmall": ["1021896"], "shmmax": ["4185686016\nkernel.shmall=1021896"]}, "changed": false}
TASK [sysctl -w kernel.shmmax="0"] ***********************************************************************
changed: [fossology_test] => {"changed": true, "cmd": ["sysctl", "-w", "kernel.shmmax=0"], "delta": "0:00:00.003133", "end": "2020-03-28 05:25:42.574223", "rc": 0, "start": "2020-03-28 05:25:42.571090", "stderr": "", "stderr_lines": [], "stdout": "kernel.shmmax = 0", "stdout_lines": ["kernel.shmmax = 0"]}
TASK [sysctl -w kernel.shmall="[u'1021896']"] ************************************************************
changed: [fossology_test] => {"changed": true, "cmd": ["sysctl", "-w", "kernel.shmall=[u'1021896']"], "delta": "0:00:00.003558", "end": "2020-03-28 05:25:43.071811", "rc": 0, "start": "2020-03-28 05:25:43.068253", "stderr": "sysctl: setting key \"kernel.shmall\": Invalid argument", "stderr_lines": ["sysctl: setting key \"kernel.shmall\": Invalid argument"], "stdout": "kernel.shmall = [u'1021896']", "stdout_lines": ["kernel.shmall = [u'1021896']"]}
PLAY RECAP ***********************************************************************************************
fossology_test : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
I am using ansible 2.9.6
dinesh#dinesh-VirtualBox:/$ ansible --version
ansible 2.9.6
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/dinesh/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/dist-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.17 (default, Nov 7 2019, 10:07:09) [GCC 7.4.0]
As you can very clearly see in the set_fact results dict, the output of regexp_search is a list of matched strings, not the just the capture group. And, because your regex is imprecise, that's why your shmmax is the numbers plus a newline plus the rest of the text.
The accurate regex is shmmax=([0-9]+) because those values aren't "any character except a double quote" it's "any number after the equals sign"

Ansible single task variable on top of global variable

I have a playbook where I am configuring environment variables for multiple hosts.
these are the global vars set in defaults\main.yml:
environment:
http_proxy: blabla
https_proxy: blabla
Now I have a single task where I need to set another environment variable for the python library.
However, when I set the environment var for that single task it overwrites the global environment vars.
- name: some task
command: command
environment:
ENV_VAR: "blabla"
I want the ENV_VAR for the single task to be added on top of the global vars. But is that even possible?
https://docs.ansible.com/ansible/latest/user_guide/playbooks_environment.html
this page didn't give me anything conclusive.
Could I use the with_items option to achieve this possibly?
The following playbook demonstrates a possible implementation for your requirement using the combine filter associated with default. Run this with -v option to see output of shell commands:
---
- name: Parse several results as json strings
hosts: localhost
gather_facts: false
# This will automatically combine `default_env` (default to empty if it does not exists)
# with `more_env` if this latest var is defined somewhere
environment: "{{ default_env | default({}) | combine(more_env | default({})) }}"
vars:
# Define default environment variables
default_env:
http_proxy: blabla
https_proxy: blabla
tasks:
- name: Show some vars
vars:
# Inject more environment variables for this task
more_env:
toto: titi
shell: |-
echo $http_proxy
echo $https_proxy
echo $toto
- name: Same with default env
shell: |-
echo $http_proxy
echo $https_proxy
echo $toto
Which gives:
$ ansible-playbook test.yml -v
PLAY [Default env override] ****************************************************************************************************************************************************************************************************************************
TASK [Show some vars] ***************************************************************************************************************************************************************************************************************************************************
changed: [localhost] => {"changed": true, "cmd": "echo $http_proxy\necho $https_proxy\necho $toto", "delta": "0:00:00.002207", "end": "2020-01-07 09:57:30.178989", "rc": 0, "start": "2020-01-07 09:57:30.176782", "stderr": "", "stderr_lines": [], "stdout": "blabla\nblabla\ntiti", "stdout_lines": ["blabla", "blabla", "titi"]}
TASK [Same with default env] ********************************************************************************************************************************************************************************************************************************************
changed: [localhost] => {"changed": true, "cmd": "echo $http_proxy\necho $https_proxy\necho $toto", "delta": "0:00:00.001875", "end": "2020-01-07 09:57:30.626163", "rc": 0, "start": "2020-01-07 09:57:30.624288", "stderr": "", "stderr_lines": [], "stdout": "blabla\nblabla", "stdout_lines": ["blabla", "blabla"]}
PLAY RECAP **************************************************************************************************************************************************************************************************************************************************************
localhost : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

basic telnet script to copy to flash drive

I am trying to use ansible to telnet into cisco switches and apply a copy startup-config disk0 command.
Ansible seems to never be able to pass
(?i)"Destination filename": "work please" through the expect command
---
- hosts: all
gather_facts: false
connection: local
tasks:
- name: telnet,login and execute command
ignore_errors: true
expect:
command: telnet "{{ inventory_hostname }}"
responses:
(?i)password: "{{ password}}"
(?i)#: copy startup-config disk0
(?i)"Destination filename": "{{ lookup('pipe','date') }"
echo: yes
register: telnet_output
What i am getting as an output
ansible-playbook 2.7.6
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
Using /etc/ansible/ansible.cfg as config file
/var/lib/awx/projects/6500/hosts did not meet host_list requirements, check plugin documentation if this is unexpected
/var/lib/awx/projects/6500/hosts did not meet script requirements, check plugin documentation if this is unexpected
PLAYBOOK: copy-startup.yml *************************************************************************************************************************************************************************************************************
1 plays in copy-startup.yml
PLAY [all] *****************************************************************************************************************************************************************************************************************************
META: ran handlers
TASK [telnet,login and execute command] ************************************************************************************************************************************************************************************************
task path: /var/lib/awx/projects/6500/copy-startup.yml:6
fatal: [66.90.19.18]: FAILED! => {"changed": true, "cmd": "telnet \"66.90.19.18\"", "delta": "0:00:30.370396", "end": "2019-02-12 10:09:41.473716", "msg": "command exceeded timeout", "rc": null, "start": "2019-02-12 10:09:11.103320", "stdout": "Trying 66.90.19.18...\r\r\nConnected to 66.90.19.18.\r\r\nEscape character is '^]'.\r\r\n\r\n\r\nUser Access Verification\r\n\r\nPassword: \r\nLAB-6500-SUP2T#copy startup-config disk0\r\nDestination filename [disk0]? ", "stdout_lines": ["Trying 66.90.19.18...", "", "Connected to 66.90.19.18.", "", "Escape character is '^]'.", "", "", "", "User Access Verification", "", "Password: ", "LAB-6500-SUP2T#copy startup-config disk0", "Destination filename [disk0]? "]}
...ignoring
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
66.90.19.18 : ok=2 changed=1 unreachable=0 failed=0
It seems to never want to write the Destination Filename[disk0]?
Any ideas
(?i)"Destination filename" matches for string with double quotes.
You need:
responses:
'(?i)password': "{{ password}}"
'(?i)#': copy startup-config disk0
'(?i)Destination filename': "{{ lookup('pipe','date') }"
---
- hosts: '6500'
gather_facts: true
connection: local
tasks:
- name: telnet,login and execute command
ignore_errors: true
expect:
command: telnet "{{ inventory_hostname }}"
responses:
(?i)Password: {{ password }}
(?i)Destination filename [disk0]? : "{{ lookup('pipe','date +%Y-%m-%d-%H-%M') }} {{ inventory_hostname }}"
(?i)#: copy startup-config disk0
(?i){{COMMAND}}: exit
echo: yes
register: telnet_output
This seems to be the best solution to what I need. I changed the order of operations and it was rocking,

Ansible include tasklist with become

I want to execute a certain list of tasks (within a role in a playbook) in ansible as a specific user. The user will actually come from a variable, but in the minimal example I'm hard-codi ng it to "dev". (This user does exist). I can't work out why the following doesn't work
My main.yml in the roles/foo/tasks is
- include_tasks: "{{ role_path }}/tasks/content.yml"
become: yes
become_user: dev
While the content.yml just fetches the current user:
- command: whoami
register: whoami
- debug:
var: whoami
My playbook is
- hosts: dev
become: true
remote_user: root
roles:
- foo
I am getting the following output:
PLAY [dev] ********************************************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************************************************
ok: [adco-test-webdev]
TASK [foo : include_tasks] ****************************************************************************************************************************************************************************************************************************************************
included: /smbshare/ansible/roles/foo/tasks/content.yml for adco-test-webdev
TASK [foo : command] **********************************************************************************************************************************************************************************************************************************************************
changed: [adco-test-webdev]
TASK [foo : debug] ************************************************************************************************************************************************************************************************************************************************************
ok: [adco-test-webdev] => {
"whoami": {
"changed": true,
"cmd": [
"whoami"
],
"delta": "0:00:00.002194",
"end": "2018-07-25 02:05:54.879601",
"failed": false,
"rc": 0,
"start": "2018-07-25 02:05:54.877407",
"stderr": "",
"stderr_lines": [],
"stdout": "root",
"stdout_lines": [
"root"
]
}
}
Why is it giving the user as root? I know I connect as root, but I then become dev for the includes don't I?
If this is how it's meant to work, then how should I configure a role so that a whole list of tasks are run as a certain user? DO I have to remember the become and become_user on every item?
Use import_tasks instead of include_tasks:
- import_tasks: "{{ role_path }}/tasks/content.yml"
become: yes
become_user: dev
In future versions (starting with 2.7) you will be able to do it with the a new parameter apply:
- include_tasks: "{{ role_path }}/tasks/content.yml"
args:
apply:
become: yes
become_user: dev

Resources