Ansible - Environment variables setting - ansible

I need to set the environment in the target machine. The environment variables are present in the file called .env337. There are several variables inside that file like
export AB_HOME=/tl/dev/abinitio/abinitio-V3 #/gcc3p32 # for 32-bit
export PATH=${AB_HOME}/bin:${PATH}
I have tried the below playbook to set the environment and register the environment variables in order to use them in the environment keyword to run the other commands in the registered environment, but it didn't worked.
- hosts: dev
gather_facts: false
tasks:
- name: To set the environment
shell: . ./.env337
register: output
Is there any other way to resolve this.

Q: "Set the environment and register the environment variables in order to use them in the environment keyword to run the other commands."
A: The environment variables set in the shell command can not be persistent. The shell process will be terminated after the execution of the command(s). For example
- shell: |
cat ./.env337
. ./.env337
echo "AB_HOME = $AB_HOME"
echo "PATH = $PATH"
exit 0
register: result
- debug:
var: result.stdout_lines
- shell: |
echo "AB_HOME = $AB_HOME"
echo "PATH = $PATH"
exit 0
register: result
- debug:
var: result.stdout_lines
give
"result.stdout_lines": [
"export AB_HOME=/tl/dev/abinitio/abinitio-V3 #/gcc3p32 # for 32-bit",
"export PATH=${AB_HOME}/bin:${PATH}",
"",
"AB_HOME = /tl/dev/abinitio/abinitio-V3",
"PATH = /tl/dev/abinitio/abinitio-V3/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/admin/bin"
]
"result.stdout_lines": [
"AB_HOME = ",
"PATH = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/admin/bin"
]
As expected the variables are missing in the second shell task.
Q: "what if I don't know what are all the variables present inside the env file. Is there any other way to print all variables instead of using echo."
A: Short answer: Create a dictionary env_dict_add with the environment variables. Use it in the shell module to create the environment environment: "{{ env_dict_add }}".
Details
1) Create a list of unknown variables. For example
- shell: cat ./.env337
register: result
- set_fact:
env_list: "{{ env_list|default([]) +
[item.split('=').0.split(' ').1|trim] }}"
loop: "{{ result.stdout_lines }}"
- debug:
var: env_list
gives
"env_list": [
"AB_HOME",
"PATH"
]
2) Create a dictionary with the environment. For example
- shell: |
. ./.env337
set
register: result
- set_fact:
env_dict: "{{ env_dict|default({})|
combine({my_key: my_value}) }}"
vars:
my_key: "{{ item.split('=').0 }}"
my_value: "{{ item.split('=').1|default('') }}"
loop: "{{ result.stdout_lines }}"
3) Use any environment variable from the dictionary. For example, print whatever variables have been exported by sourcing the file .env337
- debug:
msg: "var: {{ item }} value: {{ env_dict[item] }}"
loop: "{{ env_list }}"
gives
"msg": "var: AB_HOME value: /tl/dev/abinitio/abinitio-V3"
"msg": "var: PATH value: /tl/dev/abinitio/abinitio-V3/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/admin/bin"
4) Create a dictionary with the additional environment variables only. For example
- set_fact:
env_dict_add: "{{ env_dict_add|default({})|
combine({item: env_dict[item]}) }}"
loop: "{{ env_list }}"
- debug:
var: env_dict_add
gives
"env_dict_add": {
"AB_HOME": "/tl/dev/abinitio/abinitio-V3",
"PATH": "/tl/dev/abinitio/abinitio-V3/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/admin/bin"
}
5) Use the dictionary env_dict_add to create environment variables in the shell command. For example
- shell: echo ${{ item }}
loop: "{{ env_list }}"
register: result
environment: "{{ env_dict_add }}"
- debug:
msg: "{{ dict(result.results|json_query('[].[item, stdout]')) }}"
give
"msg": {
"AB_HOME": "/tl/dev/abinitio/abinitio-V3",
"PATH": "/tl/dev/abinitio/abinitio-V3/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/admin/bin"
}

Related

Ansible: Output of 'loop' with 'register' module

I'm trying to get the output of my Ansible script using register module but the loop I'm using is probably causing some issue.
Whats a default way of using register module with loop?
Code:
---
- name:
hosts:
gather_facts:
tasks:
- name: Execute file
ansible.builtin.shell:
environment:
"setting environment"
register: output
loop:
"value"
- debug:
vars: output.std_lines
Whats a default way of using register module with loop?
It is just registering the result.
The only difference will be, that a single task will provide you just with an dictionary result (or output in your example) and registering in a loop will provide with a list result.results (or output.results in your example). To access the .stdout_lines you will need to loop over the result set .results too.
You may have a look into the following example playbook which will show some aspects of Registering variables, Loops, data structures, dicts and lists and type debugging.
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Create STDOUT output (single)
command: 'echo "1"'
register: result
- name: Show full result (single)
debug:
var: result
- name: Show '.stdout' (single)
debug:
msg: "The result in '.stdout': {{ result.stdout }} is of type {{ result.stdout | type_debug }}"
- name: Create STDOUT output (loop)
command: 'echo "{{ item }}"'
register: result
loop: [1, 2, 3]
loop_control:
label: "{{ item }}"
- name: Show full result (loop)
debug:
var: result
- name: Show '.stdout' (loop)
debug:
msg: "The result in '.stdout': {{ item.stdout }} is of type {{ item.stdout | type_debug }}"
loop: "{{ result.results }}"
loop_control:
label: "{{ item.item }}"
By running it and going through the output you can get familiar with the differences in your tasks.
Further Q&A
Register Variables in Loop in an Ansible Playbook
Ansible: loop, register, and stdout
Register variables in loop in Ansible playbook
... and many more here on SO.

ansible assign shell results specific hosts in hostvars using with_items

Basically i want modify an existing hostvars.
I have a dynamically generated array of hosts named "flash_hosts"
flash_hosts = ['host1', 'host2']
and a shell script which looks up a value for each host.
In following non-working code i try to assign each host the specific result of the script
- name: Assign values to to host var
shell: "get-assigned-value.sh {{ item }}"
register: "{{ hostvars[item].mac=stdout }}"
with_items: "{{ flash_hosts }}"
How can i make this work in in ansible? Basically i understand that register will not allow me to assign the value to hostvars directly, but how can this be solved then, as i need to iterate over the hosts?
Use set_fact to debug your register results on host wise..
- name: Assign values to to host var
shell: "/path/to/get-assigned-value.sh {{ item }}"
register: fileout
with_items:
- host1
- host2
- set_fact:
firstHost: "{{ fileout.results[0] }}"
secondHost: "{{ fileout.results[1] }}"
- debug:
var: firstHost.stdout
- debug:
var: secondHost.stdout
in the above example, firstHost is whole result of shell script running on first host, and firstHost.stdout gives the output of corresponding host shell script result.
It's possible set_facts and delegate_to the flash_hosts with delegate_facts.
But, to create a variable in hostvars the host must be declared in the inventory(static or dynamic). It's not necessary the host is accessible. For example
$ cat hosts
host1
host2
The play below
- hosts: localhost
vars:
flash_hosts: ['host1', 'host2']
tasks:
- name: Assign values to to host var
command: "{{ playbook_dir }}/get-assigned-value.sh {{ item }}"
register: result
loop: "{{ flash_hosts }}"
- set_fact:
mac: "{{ item.stdout }}"
loop: "{{ result.results }}"
delegate_to: "{{ item.item }}"
delegate_facts: true
- debug:
msg: "{{ hostvars[item].mac }}"
loop: "{{ flash_hosts }}"
gives
ok: [localhost] => (item=host1) =>
msg: mac address of host1
ok: [localhost] => (item=host2) =>
msg: mac address of host2
with the script
$ cat get-assigned-value.sh
#!/bin/sh
case $1 in
host1)
printf "mac address of host1"
;;
host2)
printf "mac address of host2"
;;
*)
printf "unknown host"
exit 1
;;
esac
exit 0

How to read and print Ansible set_fact array in unix shell script

I created a String array using set_fact which contains path to different files as below.
- name: set_fact
set_fact
fpath: []
set_fact:
fpath: "{{ fpath + [ BASEPATH ~ '/' ~ item|basename ] }}"
loop: "{{ Source_Files.split(',') }}"
vars:
fpath: []
- name: Printing fpath
debug:
var: fpath
I pass the variable fpath to a shell script as below:
- shell: "~/backup.sh '{{ fpath }}' > ~/backup.log"
Below is my backup.sh
echo "Prameter 1:"$1 > ~/param.out
IFS=
FPATH=`python <<< "print ' '.join($FPATH)"`
echo "${FPATH[#]}"
for a in "$FPATH"; do
echo "Printing Array: $a"
echo $a >> ~/stuffarray.txt
done
Prameter 1 print all the three files in the below format
Output:
Prameter 1:[u/tmp/scripts/file1.src, u/var/logs/wow.txt, u/tmp.hello.exe]
However the conversion of $1 which is a python string array to a Unix shell script array is not happening and it does not print any value for Unix shell script array. This is more of a passing python style string array and reading it in the shell script by looking through the values.
I'm on the latest version of ansible and python.
Can you please suggest how can I pass the the python string array from ansible to a shell script variable so I could loop through it ?
The variable fpath is cleared on each iteration of the loop
- name: set_fact
set_fact:
fpath: "{{ fpath }} + [ '{{ BASEPATH }}/{{ item | basename }}' ]"
with_items:
- "{{ Source_Files.split(',') }}"
vars:
fpath: []
Correct
- name: set_fact
set_fact:
fpath: "{{ fpath|default([]) + [ BASEPATH ~ '/' ~ item|basename ] }}"
loop: "{{ Source_Files.split(',') }}"
, or if fpath might have been used before
- set_fact:
fpath: []
- set_fact:
fpath: "{{ fpath + [ BASEPATH ~ '/' ~ item|basename ] }}"
loop: "{{ Source_Files.split(',') }}"
(not tested)

Error while accessing variables in vars file in a role

As a follow up to this question How to read a particular part of file in ansible. I am trying to do the same but by using roles. The variables are stored in vars files
Here is the vars/main.yml file in the role
add:
commands: []
sub:
commands: []
multiply:
commands: []
div:
commands: []
Here's the code in tasks/main.yml file
- name: Getting the Add Commands
set_fact:
add.commands: "{{add.commands + [ item ]}}"
with_lines: "cat {{ {{playbook_dir}}/testing/files/data.txt }}"
when: item is search('^add')
- debug:
var: add.commands
- name: Getting the Sub Commands
set_fact:
sub.commands: "{{sub.commands + [ item ]}}"
with_lines: "cat {{ {{playbook_dir}}/testing/files/data.txt }}"
when: item is search('^sub')
- debug:
var: sub.commands
- name: Getting the Multiply Commands
set_fact:
multiply.commands: "{{multiply.commands + [ item ]}}"
with_lines: "cat {{ {{playbook_dir}}/testing/files/data.txt }}"
when: item is search('^multiply')
- debug:
var: multiply.commands
- name: Getting the Div Commands
set_fact:
div.commands: "{{div.commands + [ item ]}}"
with_lines: "cat {{ {{playbook_dir}}/testing/files/data.txt }}"
when: item is search('^div')
- debug:
var: div.commands
Code to execute the role
testing.yml
- name: Main Program
hosts: localhost
roles:
- testing
I thought that I would get the add commands for add.commands and similarly for others but I am getting the following error
"msg": "The variable name 'add.commands' is not valid. Variables must start with a letter or underscore character, and contain only letters, numbers and underscores."
Can anyone tell me how to troubleshoot this error and why it happened in the first place.
This is as expected and the error clearly states that.
Also as per ansible,
Variable names should be letters, numbers, and underscores. Variables
should always start with a letter.
So . can't be part of the variable name.

Return Variable from Included Ansible Playbook

I have seen how to register variables within tasks in an ansible playbook and then use those variables elsewhere in the same playbook, but can you register a variable in an included playbook and then access those variables back in the original playbook?
Here is what I am trying to accomplish:
This is my main playbook:
- include: sub-playbook.yml job_url="http://some-jenkins-job"
- hosts: localhost
roles:
- some_role
sub-playbook.yml:
---
- hosts: localhost
tasks:
- name: Collect info from Jenkins Job
script: whatever.py --url "{{ job_url }}"
register: jenkins_artifacts
I'd like to be able to access the jenkins_artifacts results back in main_playbook if possible. I know you can access it from other hosts in the same playbook like this: "{{ hostvars['localhost']['jenkins_artifacts'].stdout_lines }}"
Is it the same idea for sharing across playbooks?
I'm confused what this question is about. Just use the variable name jenkins_artifacts:
- include: sub-playbook.yml job_url="http://some-jenkins-job"
- hosts: localhost
debug:
var: jenkins_artifacts
This might seem complicated but I love doing this in my Playbooks:
rc defines the name of the variable which contains the return value
ar gives the arguments to the include tasks
master.yml:
- name: verify_os
include_tasks: "verify_os/main.yml"
vars:
verify_os:
rc: "isos_present"
ar:
image: "{{ os.ar.to_os }}"
verify_os/main.yml:
---
- name: check image on device
ios_command:
commands:
- "sh bootflash: | inc {{ verify_os.ar.image }}"
register: image_check
- name: check if available
shell: "printf '{{ image_check.stdout_lines[0][0] }}\n' | grep {{ verify_os.ar.image }} | wc -l"
register: image_available
delegate_to: localhost
- set_fact: { "{{ verify_os.rc }}": "{{ true if image_available.stdout == '1' else false }}" }
...
I can now use the isos_present variable anywhere in the master.yml to access the returned value.

Resources