when condition not being evaluated with include statement - variables

I have a tikitaka3.yml (main yml file) and a tikitaka3a.yml (playbook to be included).
I prompt the user for a variable, and then in the tasks section I call it, like so:
---
- hosts: all
vars:
khan:
# contents: "{{ lookup('file', '/home/imran/Desktop/tobefetched/file1.txt') }}"
vars_prompt:
- name: targetenv
prompt: 1.)EPC 2.)CLIENTS 3)TESTERS
private: False
default: "1"
gather_facts: no
tasks:
- name: Inlude playbook tikitaka3a
include: /home/khan/Desktop/playbooks/tikitaka3a.yml target=umar
when: targetenv.stdout|int < 2 #this statement has no effect
#when: targetenv == 1 #Neither does this statement
#when: targetenc == "1" #and neither does this statement have affect
#- name: stuff n stuff # This task will give an error if not commented
# debug: var=targetenv.stdout
The include statement always comes into affect, without the when condition ever being evaluated.
Why is this happening?

When you include an Ansible task file it will attach the when: condition to all included tasks. This means that you will see the tasks displayed even when the when: condition is false though all tasks will be skipped.
One problem with your code above is targetenv.stdout, here is a working version with proper formatting:
- hosts: all
gather_facts: no
vars_prompt:
- name: targetenv
prompt: 1.)EPC 2.)CLIENTS 3)TESTERS
private: False
default: "1"
tasks:
- name: Inlude playbook tikitaka3a
include: roles/test/tasks/tikitaka3a.yml target=umar
when: targetenv|int < 2

Related

Is there a way in Ansible to retrieve a variable located on a different host, to get it on the localhost

I have the following playbook:
- name: Some action on the workers
hosts: workers
gather_facts: false
run_once: true
tasks:
- name: Set var for server information
set_fact:
server_info:
"name": "winserver"
"os": "Microsoft Windows Server 2019 Datacenter"
- name: Some action on the localhost
hosts: localhost
gather_facts: false
run_once: true
tasks:
- name: Show script stdout
debug:
msg:
- "{{ server_info }}"
The hosts is actually a group of servers put in a group named workers (for example server1, server2 and server3), where just one is chosen (arbitrary) to run this task. Now I need to retrieve the information from this variable on the localhost, but as I don't know on which server the first task runs, I cannot explicitly reference it by using:
"{{ hostvars['server2']['server_info'] }}"
Does someone know if there is a way to retrieve this variable on the localhost?
Q: "I don't know on which server the first task runs."
A: It's irrelevant which server the first task runs on. The variable server_info will be declared on all of them. For example, given the inventory
shell> cat hosts
[workers]
server1
server2
server3
The playbook
- hosts: workers
gather_facts: false
run_once: true
tasks:
- set_fact:
server_info: winserver
- debug:
var: hostvars[item]['server_info']
loop: "{{ ansible_play_hosts_all }}"
gives
TASK [debug] *********************************************************
ok: [server1] => (item=server1) =>
ansible_loop_var: item
hostvars[item]['server_info']: winserver
item: server1
ok: [server1] => (item=server2) =>
ansible_loop_var: item
hostvars[item]['server_info']: winserver
item: server2
ok: [server1] => (item=server3) =>
ansible_loop_var: item
hostvars[item]['server_info']: winserver
item: server
You can pick any host you like. For example,
- hosts: localhost
gather_facts: false
run_once: true
tasks:
- debug:
var: hostvars.server2.server_info
gives
TASK [debug] ************************************************************
ok: [localhost] =>
hostvars.server2.server_info: winserver
I just found the answer to this question myself: through the use of
delegate_to: localhost
delegate_facts: true
This way the variable gets stored on the localhost.
- name: Some action on the workers
hosts: workers
gather_facts: false
run_once: true
tasks:
- name: Set var for server information
set_fact:
server_info:
"name": "winserver"
"os": "Microsoft Windows Server 2019 Datacenter"
delegate_to: localhost
delegate_facts: true
- name: Some action on the localhost
hosts: localhost
gather_facts: false
run_once: true
tasks:
- name: Show script stdout
debug:
msg:
- "{{ server_info }}"

Build a variable in a playbook with the hostname and call it in a task

I have a two main variable with subvariables. The main variable VELABx and VELABy match the ansible_hostnames. Following an example of the variables mentioned:
VELABx
location: "text1.1"
initialism: "text1.2"
VELABy
location: "text2.1"
initialism: "text2.2"
Now I'd like to run a task which replaces a regexp with the location variable based on the current ansible_hostname. So, I tried this code, but it leads into an error.
- name: Replace location for VELABx
replace:
dest: "/path/to/file"
regexp: 'location'
replace: "{{ {{ansible_hostname}}.location }}"
remote_user: rssuser
become: no
when: ansible_hostname == "VELABx"
What am I doing wrong? How can I solve this? Can anyone bring up a solution?
Things are always easier when you manage to create a proper structure of data. For example, given the dictionaries in a file
shell> cat velab.yml
VELABx:
location: "text1.1"
initialism: "text1.2"
VELABy:
location: "text2.1"
initialism: "text2.2"
you can include the data from the file into a dictionary, e.g.
- hosts: VELABx,VELABy,VELABz
tasks:
- include_vars:
file: velab.yml
name: velab
run_once: true
- debug:
var: velab
run_once: true
gives
velab:
VELABx:
initialism: text1.2
location: text1.1
VELABy:
initialism: text2.2
location: text2.1
The data you provided in the question are not YAML dictionaries. The colon is missing behind the keys. Either fix it, if you can or parse the file. Anyway, create the dictionary whatever is the source.
Then, given the files
shell> ssh admin#10.1.0.61 cat /tmp/velab.txt
location
shell> ssh admin#10.1.0.62 cat /tmp/velab.txt
location
shell> ssh admin#10.1.0.63 cat /tmp/velab.txt
location
the task to replace the location is simple
- name: Replace location for VELAB*
replace:
dest: /tmp/velab.txt
regexp: location
replace: "{{ velab[inventory_hostname]['location'] }}"
when: velab[inventory_hostname] is defined
gives
shell> ansible-playbook playbook.yml -CD
PLAY [VELABx,VELABy,VELABz] ******************************************
...
TASK [Replace location for VELAB*] ***********************************
skipping: [VELABz]
--- before: /tmp/velab.txt
+++ after: /tmp/velab.txt
## -1 +1 ##
-location
+text1.1
changed: [VELABx]
--- before: /tmp/velab.txt
+++ after: /tmp/velab.txt
## -1 +1 ##
-location
+text2.1
changed: [VELABy]
The next option is to remove the condition and use the default value, instead of skipping the host, when the host is missing in the dictionary
- name: Replace location for VELAB*
replace:
dest: /tmp/velab.txt
regexp: location
replace: "{{ velab[inventory_hostname]['location']|
default(default_location) }}"
vars:
default_location: "text99.1"
you must use loopkup, {{}} inside other {{}} is incorrect
---
- hosts: localhost
gather_facts: false
vars:
ansible_hostname: VELABx
VELABx:
location: "text1.1"
initialism: "text1.2"
VELABy:
location: "text2.1"
initialism: "text2.2"
tasks:
- name: DEBUG
debug:
msg: "{{ lookup('vars', ansible_hostname ).location }}"
- name: Replace location for VELABx
replace:
dest: "/path/to/file"
regexp: 'location'
replace: "{{ lookup('vars', ansible_hostname ).location }}"
when: ansible_hostname == "VELABx"

Ansible: variable registered on one server gets forgotten when running on another remote server

My tasks:
- name: Init a new swarm with default parameters
docker_swarm:
state: present
advertise_addr: "{{ manager_ip }}:2377"
register: rezult
when: "ansible_default_ipv4.address == '{{ manager_ip }}'"
- debug:
msg: '{{ rezult.swarm_facts.JoinTokens.Worker }}'
when: "ansible_default_ipv4.address == '{{ manager_ip }}'"
Now this works fine, but if I want to run it on another server (!=) with:
- debug:
msg: '{{ rezult.swarm_facts.JoinTokens.Worker }}'
when: "ansible_default_ipv4.address != '{{ manager_ip }}'"
I get:
FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'swarm_facts'\n\nThe error appears to be in '/home/ansible/docker-ansible/docker.yml': line 42, 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 - debug:\n ^ here\n"}
I do not get it. It is like ansible forgets the value of registered variable called "rezult" when running on another server even though I registered it and it should have a fixed value.
Yes, variables are always host specific, including ones declared by set_fact:; if you want that variable to appear on all your hosts, you'll have to have a special "propagation" action that reaches "over" to the one host that does have the value, and assign it to all the hosts:
- set_fact:
hello: I am a manager
when: ansible_default_ipv4.address == '{{ manager_ip }}'
- set_fact:
hello: '{{ hostvars[manager_host].hello }}'
when: hello is not defined
vars:
# you may have access to some less convoluted logic than this
# to know which inventory_hostname ran that "set_fact:"
manager_host: '{{ hostvars | dict2items
| selectattr("value.ansible_default_ipv4.address", "eq", manager_ip)
| map(attribute="key") | first }}'

Using variables from one yml file in another playbook

I am new to ansible and am trying to use variables from a vars.yml file in a playbook.yml file.
vars.yml
---
- firstvar:
id: 1
name: One
- secondvar:
id: 2
name: two
playbook.yml
---
- hosts: localhost
tasks:
- name: Import vars
include_vars:
file: ./vars.yml
name: vardata
- name: Use FirstVar
iso_vlan:
vlan_id: "{{ vardata.firstvar.id }}"
name: "{{ vardata.firstvar.name }}"
state: present
- name: Use Secondvar
iso_vlan:
vlan_id: "{{ vardata.secondvar.id }}"
name: "{{ vardata.secondvar.name }}"
state: present
So you can see here I am treating the imported variable data, which is stored in vardata, as object and trying to call each of them in other tasks. I am pretty sure these imported vars at the first task are only available in that very task. How can I use that in other tasks? It would output as variables undefined for each tasks. Any input is appreciated.
Your vars.yml file isn't formatted correctly.
Try this:
---
firstvar:
id: 1
name: One
secondvar:
id: 2
name: two
I used this to test it:
---
- hosts: localhost
tasks:
- name: Import vars
include_vars:
file: ./vars.yml
name: vardata
- name: debug
debug:
msg: "{{ vardata.firstvar.name }}"
- name: more debug
debug:
msg: "{{ vardata.secondvar.id }}"
On top of the error you made when declaring the variables (syntax is very important), you can also define include_vars: ./vars.yml such that you can just call {{ firstvar.name }}, {{ firstvar.id }} immediately. Much more leaner/shorter.

Create an arbitrary number of DigitalOcean droplets with Ansible

I want to create an arbitrary number of droplets when I call a playbook with ansible.
For example:
I need to create 10 droplets running some python code.
$ ansible-playbook install_pyapp_commission_new.yml --extra-vars "number_of_droplets_to_create=10"
I tried using with_sequence: count = X but you can't apply it to roles, or inside tasks (as far as I know). My playbook looks something like this:
- name: Digital Ocean Provisioning
hosts: 127.0.0.1
gather_facts: false
connection: local
roles:
- { role: do_provision, do_droplet_number: "{{ number_of_droplets_to_create | default(01) }}" }
- name: Setting up application
gather_facts: true
user: root
hosts: do_instances
roles:
- { role: application, wait_time: 60 }
So I pass the input number of droplets to do_provision as do_droplet_number because atm I create one per run (this way I can run 10 in parallel from bash, each with a different number, thus achieving my goal, but it's a dirty solution).
I wanted to do something like this:
- name: Digital Ocean Provisioning
hosts: 127.0.0.1
gather_facts: false
connection: local
roles:
- { role: do_provision, do_droplet_number: "{{ item }}" }
with_sequence: count={{ number_of_droplets_to_create }}
But this is not valid.
This should work using loop instead of with_sequence.
It shifts the loop into the role, because playbooks can't include the 'when'.
The 'when' is needed to prevent a droplet from being created when do_droplet_number is 0.
playbook
- name: list hosts
hosts: all
gather_facts: false
vars:
thiscount: "{{ mycount | default('0') }}"
roles:
- { role: do-provision, do_droplet_number: "{{ thiscount }}" }
roles/do-provision/task/main.yml
- name: display number
debug:
msg: "mycount {{ item }}"
loop: "{{ range(0, do_droplet_number|int) |list }}"
when: thiscount > 0