Unable to retrieve some Ansible facts about Windows clients - ansible

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.

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.

Ansible - Problem with using Hostvars to use variables across different hosts. Error: Undefined Variable

The problem I'm having is fairly simple. I have a Windows Server host I'm connecting to, to make a new AD User based off some data. It's static for now, but will be dynamic in the future. It takes some variables plus randomization for uniqueness and puts them in some variables.
The next play needs to use those same variables for deploying a Windows 10 virtual machine. I used the "{{ hostvars['host']['variablename'] }}" to take them over to the next play. But no matter what I try, I always get the Undefined Variable error.
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: \"hostvars['windowsDA']\" is undefined\n\nThe error appears to be in '/etc/ansibleplaybooks/Orchestration/onboarduser': line 67, 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: giveinfo\n ^ here\n"}
I've tried gather_facts. I've tried putting the original vars in vars: ... than putting them under set_fact, I've tried multiple types of syntax. Yet it doesn't want to work. Here is a shortened version of my playbook. The rest Isn't needed to know. If the debug msg works, then it should work everywhere.
- name: Make AD User
hosts: windowsDA
tasks:
- name: Set variables as fact
set_fact:
var_random_string: "{{ lookup('community.general.random_string', length=3, special=false, base64=false) }}"
var_name: Pieter
var_lastname: Post
var_department: IT
var_underscore: _
- name: Create User
community.windows.win_domain_user:
enabled: yes
name: "{{var_name+var_lastname+var_underscore+var_random_string}}"
firstname: "{{ var_name }}"
surname: "{{ var_lastname }}"
company: Poliforma
password: P#ssw0rd
password_expired: yes
path: OU={{var_department}},DC=poliforma,DC=com
state: present
description: Werknemer van {{var_department}}Afdeling
upn: "{{var_name+var_lastname+var_underscore+var_random_string}}#poliforma.com"
user_cannot_change_password: no
attributes:
department: "{{var_department}}Afdeling"
- name: Clone the template and customize
hosts: localhost
vars:
test: "{{ hostvars['windowsDA']['var_name'] }}"
#hostvar_fact_var_name: #"{{hostvars['localhost']['fact_var_name']}}"
#hostvar_fact_var_lastname: #"{{hostvars['localhost']['fact_var_lastname']}}"
#hostvar_fact_var_underscore: #"{{hostvars['localhost']['fact_var_underscore']}}"
#hostvar_fact_var_random_string: #"{{hostvars['localhost']['fact_var_random_string']}}"
tasks:
- name: giveinfo
debug: msg="{{test}}"
Can someone help me?
I believe it would work if you set your inventory as the following.
[your_group_name]
windowsDA ansible_host=188.88.88.88 etc.

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

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