Access variable in other play - Ansible - ansible

Ansible Version: 2.4.2.0
From here and here, I was able write below playbook
$ cat test.yml
- name: Finding Master VMs
hosts: all-compute-host
remote_user: heat-admin
tasks:
- name: Getting master VM's hostname
shell: hostname
register: hostname_output
- name: Access in different play
hosts: localhost
connection: local
tasks:
- name: Testing vars
debug: var='{{ hostvars[item]['hostname_output']['stdout'] }}'
with_items: groups['all-compute-host']
I don't want use gather_facts: true and access hostname from it. Getting below error when I try to above playbook
-----------OUTPUT REMOVED----------------
TASK [Testing vars] *******************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: u\"hostvars['groups['all-compute-host']']\" is undefined\n\nThe error appears to have been in '/tmp/test.yml': line 18, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: Testing vars\n ^ here\n\nexception type: <class 'ansible.errors.AnsibleUndefinedVariable'>\nexception: u\"hostvars['groups['all-compute-host']']\" is undefined"}
to retry, use: --limit #/tmp/test.retry
-----------OUTPUT REMOVED----------------
I tried below things
debug: var=hostvars[item]['hostname_output']['stdout']
debug: var=hostvars.item.hostname_output.stdout'
I have also tried direct host group instead of iterating item like below
debug: var=hostvars.all-compute-host.hostname_output.stdout'
debug: var=hostvars['all-compute-host']['hostname_output']['stdout']
ok: [localhost] => {
"hostvars['all-compute-host']['hostname_output']['stdout']": "VARIABLE IS NOT DEFINED!"
}
I have also try direct host name.But no use
debug: var='hostvars.compute01.hostname_output.stdout'

The problem is with your debug statement:
tasks:
- name: Testing vars
debug: var='{{ hostvars[item]['hostname_output']['stdout'] }}'
with_items: groups['all-compute-host']
There are two issues:
The value of the var argument to the debug module is evaluated in a Jinja templating context. That means you must not use the {{...}} template markers.
On the hand, the argument to with_items does need the {{...}} markers; without that, you're iterating over a list consisting of a single item, the literal string groups['all-compute-host'].
With both of those problems fixed (and a few minor stylistic changes), you get:
tasks:
- name: Testing vars
debug:
var: hostvars[item].hostname_output.stdout
with_items: "{{ groups['all-compute-host'] }}"

Related

Ansible The conditional check failed. The error was error while evaluating conditional

Why is the conditional check failed ?
My CSV file:
No.,OS,Information
1,**Linux**,CentOS 8.3
2,**Windows**,Windows 2016
---
- name: Test_CSV
hosts: localhost
gather_facts: True
tasks:
- read_csv:
path: test.csv
delimiter: ','
register: servers
- include_tasks: Linux.yml
when: vm.OS == "Linux"
- include_tasks: Windows.yml
when: vm.OS == "Windows"
loop: "{{ servers.list }}"
loop_control:
loop_var: vm
Linux.yml
---
- debug:
msg: "OS = Linux"
Windows.yml
---
- debug:
msg: "OS = Windows"
The error I get is this:
fatal: [localhost]: FAILED! => {
"msg": "The conditional check 'vm.OS == "Linux"' failed. The error was: error while evaluating conditional (vm.OS == to be in '/itoa/condition/20210920/Test_CSV.yml': line 13, column 7, but may\nbe elsewhere in the file depending on the eto be:\n\n\n - include_tasks: Linux.yml\n ^ here\n"
}
or is there another way Please help guide me.
Thanks,
The problem is the loop. You can not loop over two tasks. You have to define a block (maybe this will not work with include_tasks).
BUT anyway what you try to implement is the core functionality of Ansible. Do do not need to loop over hosts. Ansible exists to do this for you.
Define the hosts in your inventory. Add the Linux systems to a group "linux". Add the Windows systems to a group "windows". Use the groups as a "hosts" argument.
Now Ansible will execute the tasks for all hosts.
If you want to use your CSV file as an inventory, you have to write a dynamic inventory script.

Unable to retrieve some Ansible facts about Windows clients

I currently want to select specifically the Windows adapter name ONLY from the ansible facts.
So my problem is that I cannot retrieve this value only.
Ansible 2.8.2_1 with Winrm & Kerberos Authentication are running on the server.
I've tried to launch this playbook :
- hosts: win_clients
gather_facts: true
strategy: free
tasks:
- name: Get Ansible network facts
debug:
msg: "{{ ansible_facts['interfaces'] }}"
and it works fine but I have all the informations about the interfaces. I just want the "connection_name".
When I put this line in the playbook :
msg: "{{ ansible_facts['interfaces']['connection_name'] }}"
It shows this message at the execution :
FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'list object' has no attribute 'connection_name'\n\nThe error appears to be in '/home/sopra/git/rnd-windows/automation/playbooks/Dns/test.yaml': line 5, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: Get Ansible network facts\n ^ here\n"}
I don't understand because the variable "connection_name" is well defined.
Can somebody help me? Thanks.
Have a good day !
If you want to list the connection_name, use below, as ansible_facts['interfaces'] is an array
- hosts: win_clients
gather_facts: true
strategy: free
tasks:
- name: Get Ansible network facts
debug:
msg: "{{ item.connection_name }}"
with_items:
- "{{ ansible_facts['interfaces'] }}"
Thank you very much for your support. I did resolve my problem.
Basically, my playbook consists in changing the DNS configuration if the occurrence of one (old) DNS's IP if found.
# tasks file for configureDnsServerAddresses
# Get the configuration state about DNS
# If one occurrence of 'old_dnsserver' is found...
- name: Get DNS configuration
win_shell: ipconfig /all | findstr {{ old_dnsserver }}
register: check_old_dns
changed_when: false
# '.rc' means the return code
failed_when: check_old_dns.rc != 0 and check_old_dns.rc != 1
# ... it will be replaced by 2 new ones
- name: Change the DNS only if the IP {{ old_dnsserver }} is found
win_dns_client:
adapter_names: "{{ item.connection_name }}"
ipv4_addresses:
- "{{ dnsserver1 }}"
- "{{ dnsserver2 }}"
# Array based on Ansible facts
with_items:
- "{{ ansible_facts['interfaces'] }}"
# Apply only if 'check_old_dns' is not empty, which means that the old DNS is found
when: check_old_dns.stdout | length > 0
This playbook is role-based, so the variables are stored in a "defaults" folder.
The code mentioned above was intended for testing purposes.

Reformat ip from ansible_facts without filter

I'm trying to dynamically update and reformat a host IP address for a template to use. I need to get the host IP, and reformat it from typical format into a format without a supporting filter.
I'm very new to ansible. Very new.
However, from what I've gathered...
I should be able to get the host ip "fact" from my playbook. I'm struggling with the syntax to get it to run, but I'm pretty confident that's something I will be able to do.
Once I have the ip, I need to reformat it from 11.22.33.44 into 11\\.22\\.33\\.44 .
So far, I can't even get the syntax right for grabbing the ip fact, let alone reformat it. With regard to the formatting, I've scoured the filters, but didn't find any (explicit) descriptions that would indicate a filter method that would format in the manner I need (though... I'd suspect it exists).
name: "test gathering a fact"
debug: var= "{{ hostvars[groups['webservers'][0]]['ansible_eth0']['ipv4']['address'] }}"
I expected something along the lines of...
11.22.33.44
But I'm getting:
ERROR! Syntax Error while loading YAML.
did not find expected key
The error appears to have been in '/home/my_playbook.yml': line 14, column 13, but may be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: "test gathering a fact"
debug: var= "{{ hostvars[groups['webservers'][0]]['ansible_eth0']['ipv4']['address'] }}"
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}""
Once I have the ip, I need to reformat it from 11.22.33.44 into 11\\.22\\.33\\.44 .
- debug:
msg: >-
{{ the_host.ansible_default_ipv4.address | regex_replace('\.', '\\\\.') }}
# watch out if you choose not to use the `>-` syntax
# as then yaml quoting will become a real PITA
vars:
the_host: '{{ hostvars[groups.webservers[0]] }}'
You also might be happier using ansible_default_ipv4.address instead of ansible_eth0.ipv4.address for machines that don't always use eth0 (which is some modern ubuntu flavors, freebsd, etc). That is to say, you likely care about the machine's network identity, and not -- specifically -- what address is bound to a NIC named eth0
indentation is wrong. Instead of
- name: "test gathering a fact"
debug: var= ...
The correct syntax is
- name: "test gathering a fact"
debug: var= ...
I prefer to use the dot notation:
- name: first debug
debug:
msg: "{{ hostvars[groups['webservers'][0]].ansible_enp0s25.ipv4.address }}"
And that code returns this in the output:
TASK [first debug] **********************************************************************
ok: [localhost] => {
"msg": "192.168.65.105"
}
So combining these together into this playbook:
---
- hosts: all
gather_facts: true
tasks:
- name: first debug
debug:
msg: "{{ hostvars[groups['webservers'][0]].ansible_enp0s25.ipv4.address }}"
- name: second debug
debug:
msg: >-
{{ hostvars[groups['webservers'][0]].ansible_enp0s25.ipv4.address | regex_replace('\.', '\\\\.') }}
Gives this output:
PLAY [all] ******************************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [localhost]
TASK [first debug] **********************************************************************
ok: [localhost] => {
"msg": "192.168.65.105"
}
TASK [second debug] *********************************************************************
ok: [localhost] => {
"msg": "192\\\\.168\\\\.65\\\\.105"
}
PLAY RECAP ******************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0

How can I reference a registered variable from one ansible play in another?

I need to check if VMs exist or not. The check is registered in one play, 'control' and referenced in another, 'production'. What is the correct format for this?
create_vm.yml:
---
- hosts: control
tasks:
- name: Check VM
virt:
command: "list_vms"
register: vms
- hosts: production
tasks:
- name: Create VM
STUFF
when: inventory_hostname not in groups['control']['vms']
I've tried different 'when' formats but they've all failed.
I have various errors depending on the format of when condition used; the following is for the specified condition.
fatal: [prod-operator]: FAILED! => {"failed": true, "msg": "The conditional check 'inventory_hostname not in groups['control']['vms']' failed. The error was: error while evaluating conditional (inventory_hostname not in groups['control']['vms']): Unable to look up a name or access an attribute in template string ({% if inventory_hostname not in groups['control']['vms'] %} True {% else %} False {% endif %}).\nMake sure your variable name does not contain invalid characters like '-': argument of type 'StrictUndefined' is not iterable\n\nThe error appears to have been in '/root/micks-ci-setup/production/virtual_machine/create-vm.yml': line 29, 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 - name: Create Production VM\n ^ here\n"}
From what I've seen I should be able to reference the registered value form another task using a reference to host but it just won't work for me. I'll move on with a workaround of performing another check in the hosts: production play as follows.
(I'm doing a round-robin deployment of VMs hence the delegate_to complexity)
---
- hosts: control
tasks:
- name: Check VM
virt:
command: "list_vms"
register: vms
- hosts: production
tasks:
- name: Check VMs
virt:
command: "list_vms"
register: vms
delegate_to: '{{ groups["control"][play_hosts.index(inventory_hostname) % groups["control"]|length] }}'
And when condition as follows:
when: inventory_hostname not in vms.list_vms
If anyone can provide the "correct" method or a reason why it's not working for me then please feel free to post another answer.

Use variable from another host

I have a playbook that executes a script on a Windows box that returns a value that I have to re-use later on in my playbook after switching to localhost.
How can I access this value after switching back to localhost?
Here is an example:
- hosts: windows
gather_facts: no
tasks:
- name: Call PowerShell script
win_command: "c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe c:\\psl_scripts\\getData.ps1"
register: value_to_reuse
- hosts: localhost
gather_facts: no
tasks:
- name: debug store_name from windows host
debug:
var: "{{ hostvars[windows][value_to_reuse][stdout_lines] }}"
What is the correct syntax accessing a variable from another host?
I'm receiving error message:
"msg": "The task includes an option with an undefined variable. The error was: 'windows' is undefined
Here is the code that works for a group in a loop:
- name: print value_to_reuse
debug:
var: hostvars[item].value_to_reuse.stdout_lines
loop: "{{ groups['windows'] }}"
Same code works without iterations:
- name: print value_to_reuse
debug:
var: hostvars[groups['windows'].0].value_to_reuse.stdout_lines
The syntax is:
- debug:
var: hostvars['windows']['value_to_reuse']['stdout_lines']
Three mistakes:
you should quote string values
var parameter takes the variable name, not a template (which should be an msg-parameter value)
windows in the given example should be the host name as all facts are bound to hosts, not group of hosts

Resources