Use variable from another host - ansible

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

Related

Is there a way to get a list of unreachable hosts in an ansible playbook

I have the ansible role coded below.
---
- name: Get host facts
set_fact:
serverdomain: "{{ansible_domain}}"
server_ip: "{{ansible_ip_addresses[1]}}"
- name: Host Ping Check
failed_when: false
win_ping:
register: var_ping
- name: Get Host name
debug: msg="{{the_host_name}}"
- name: Set Execution File and parameters
set_fact:
scriptfile: "{{ansible_user_dir}}\\scripts\\host_check.ps1"
params: "-servername '{{the_host_name}}' -response var_ping.failed"
- name: Execute script
win_command: powershell.exe "{{scriptfile}}" "{{params}}"
It works the way it should do but of course unreachable hosts are not touched at all. I would like to generate a list or is there a variable which contains all the unreachable hosts. Is it possible to have this in a comma delimmeted list and stored in a variable ?
Lastly, how/where do i need to set gather_facts: no. I tried several places to no avail.
EDIT 1
- name Unreachable servers
set_fact:
down: "{{ ansible_play_hosts_all | difference(ansible_play_hosts)}}"
- name: Set Execution File and parameters
set_fact:
scriptfile: "{{ansible_user_dir}}\\scripts\\host_check.ps1"
params: "-servername '{{the_host_name}}' -response var_ping.failed -unreachable_hosts {{ down }}"
- name: Execute script
win_command: powershell.exe "{{scriptfile}}" "{{params}}"
when: inventory_hostname == {{ db_server_host }}
Thanks for the answers, I have now been able to use thesame login in my ansible role, and it appears to work.
I do however have some questions. My playbook runs against hosts defined in my inventory, in this case what I want to achieve is a situation where the unreachable hosts is passed onto a powershell script right at the end and at once. So for example, 100 hosts, 10 were unreachable. The playbook should gather the 10 unreachable hosts, and pass the list of hosts in an array format to a powershell script or as a json data type.
All I want to do is be able to process the list of unreachable servers from my powershell script.
At the moment, I get
[
"server1",
"server2"
]
MY script will work with a format like this "server1","server2"
Lastly.The process of logging the unreachable servers at the end, only needs to happen once to a specific server which does the logging to a database. I created a task to do this as seen above.
db_server_host is being passed as a extra variables from ansible tower. The reason i added the when is that I only want it to run on the DB server and not on every host. I get the error The conditional check inventory_hostname == {{ db_server_host }} failed. The error was error while evaluating conditional inventory_hostname == {{ db_server_host }} 'mydatabaseServerName' is undefined
Q: "Get a list of unreachable hosts in an Ansible playbook."
Short answer: Create the difference between the lists below
down: "{{ ansible_play_hosts_all|difference(ansible_play_hosts) }}"
Details: Use Special Variables. Quoting:
ansible_play_hosts_all:
List of all the hosts that were targeted by the play.
ansible_play_hosts:
List of hosts in the current play run, not limited by the serial. Failed/Unreachable hosts are excluded from this list.
For example, given the inventory
shell> cat hosts
alpha
beta
charlie
delta
The playbook
- hosts: alpha,beta,charlie
gather_facts: true
tasks:
- block:
- debug:
var: ansible_play_hosts_all
- debug:
var: ansible_play_hosts
- set_fact:
down: "{{ ansible_play_hosts_all|difference(ansible_play_hosts) }}"
- debug:
var: down
run_once: true
gives (bridged) if alpha is unreachable (see below)
ansible_play_hosts_all:
- alpha
- beta
- charlie
ansible_play_hosts:
- beta
- charlie
down:
- alpha
Host alpha was unreachable
PLAY [alpha,beta,charlie] *************************************************
TASK [Gathering Facts] ****************************************************
fatal: [alpha]: UNREACHABLE! => changed=false
msg: 'Failed to connect to the host via ssh: ssh: connect to host test_14 port 22: No route to host'
unreachable: true
ok: [charlie]
ok: [beta]
...
Note
The dictionary hostvars keeps all hosts from the inventory, e.g.
- hosts: alpha,beta,charlie
gather_facts: true
tasks:
- debug:
var: hostvars.keys()
run_once: true
gives (abridged)
hostvars.keys():
- alpha
- beta
- charlie
- delta
tasks:
- ping:
register: ping_out
# one can include any kind of timeout or other stall related config here
- debug:
msg: |
{% for k in hostvars.keys() %}
{{ k }}: {{ hostvars[k].ping_out.unreachable|default(False) }}
{% endfor %}
yields (when an inventory consisting of only an alive alpha host):
msg: |-
alpha: False
beta: True
charlie: True
Lastly, how/where do i need to set gather_facts: no. I tried several places to no avail.
It only appears one time in the playbook keywords and thus it is a play keyword:
- hosts: all
gather_facts: no
tasks:
- name: now run "setup" for those who you wish to gather_facts: yes
setup:
when: inventory_host is awesome

Ansible: variable is defined but error shows not defined

I have an ansible playbook as follows:
---
- name: test variables
hosts: all
tasks:
- name: test
command: echo {{ ansible_role_dir }}
register: result
- name: show result
debug:
msg="{{ result.stdout }}"
#roles: #line12
# - "{{ ansible_role_dir }}/testrole" #line13
the variable ansible_role_dir is defined under group_vars/all.yaml.
if I run the playbook which comments out the line12 and line13, it shows the result of variable correctly. Obviously it knows where the variable ansible_role_dir is defined. But if I uncomment line12 and line13, it shows error ERROR! 'ansible_role_dir' is undefined. Why it does not know where the ansible_role_dir is defined this time?
Ansible does not like jinja tags without quotes. try this:
---
- name: test variables
hosts: all
tasks:
- name: test
command: "echo {{ ansible_role_dir }}"
register: result
- name: show result
debug:
msg="{{ result.stdout }}"
#roles: #line12
# - "{{ ansible_role_dir }}/testrole" #line13
EDIT:
sorry, i think i misread the question.
have you tried putting in the real path instead of the var, just to see if it works? usually role paths are given in ansible's config, i never saw them run with a direct path

Variable is defined but still getting undefined error

I am trying to write a playbook that completes some of its tasks on the machine that the playbook is running on. I know i can use local_action for this but I am just testing if the playbook works for now. Eventually I will need to use the delegate_to. I have defined the variable and I am using delegate_to: 'variable name' but I am getting this error. : " fatal [target node]: FAILED! => { msg": "'variablename' is undefined. Below is my playbook:
name: Create certs
gather_facts: true
vars:
master: "{{ nameofhost }}"
tasks:
- name: Run command
shell: Command to run
delegate_to: "{{ master }}"
You need to target your play to a target hosts of an inventory
name: Create certs
gather_facts: true
hosts: target_hosts
vars:
master: "{{ nameofhost }}"
tasks:
- name: Run command
shell: Command to run
delegate_to: "{{ master }}"
``` 
Your inventory files may look like that:
[target_hosts]
master ansible_host=your_master_dns_or_ip
And then ansible can target that inventory group and then reduce the task scope to master host. Or you can just use the localhost as target.

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.

How to get value of --limit argument inside an Ansible playbook?

In ansible, is it possible to get the value of the argument to the "--limit" option within a playbook? I want to do is something like this:
---
- hosts: all
remote user: root
tasks:
- name: The value of the --limit argument
debug:
msg: "argument of --limit is {{ ansible-limit-arg }}"
Then when I run he command:
$ ansible-playbook getLimitArg.yaml --limit webhosts
I'll get this output:
argument of --limit is webhost
Of course, I made up the name of the variable "ansible-limit-arg", but is there a valid way of doing this? I could specify "webhosts" twice, the second time with --extra-args, but that seems a roundabout way of having to do this.
Since Ansible 2.5 you can access the value using a new magic variable ansible_limit, so:
- debug:
var: ansible_limit
Have you considered using the {{ ansible_play_batch }} built-in variable?
- hosts: all
become: "False"
gather_facts: "False"
tasks:
- name: The value of the --limit argument
debug:
msg: "argument of --limit is {{ ansible_play_batch }}"
delegate_to: localhost
It won't tell you exactly what was entered as the argument but it will tell you how Ansible interpreted the --limit arg.
You can't do this without additional plugin/module. If you utterly need this, write action plugin and access options via cli.options (see example).
P.S. If you try to use --limit to run playbooks agains different environments, don't do it, you can accidentally blow your whole infrastructure – use different inventories instead.
Here is the small code block to achieve the same
- block:
- shell: 'echo {{inventory_hostname}} >> /tmp/hosts'
- shell: cat /tmp/hosts
register: servers
- file:
path: /tmp/hosts
state: absent
delegate_to: 127.0.0.1
- debug: var=servers.stdout_lines
Then use stdout_lines output as u wish like mine
- add_host:
name: "{{ item }}"
groups: cluster
ansible_user: "ubuntu"
with_items:
- "{{ servers.stdout_lines }}"

Resources