"Undefined variable" error on Ansible when run over Windows machines - windows

This is a very simple Ansible playbook I run from AWX to get information about hosts, and it works as intended on Linux machines:
---
- name: Get some info
debug:
msg: "{{ ansible_hostname }} {{ ansible_default_ipv4.address }} {{ ansible_distribution }}"
However, when run over Windows machines, it returns this error:
fatal: [MYWINHOST1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible_default_ipv4' is undefined\n\nThe error appears to be in '/tmp/bwrap_21138_4q41r57e/awx_21138_is8pox6p/project/roles/windows/tasks/getsomeinfo.yml': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Get some info\n ^ here\n"}
How do I access and print the same Ansible facts values from a Windows machine?

From the documentation:
ansible_facts
This key should contain a dictionary which will be appended to the facts assigned to the host. These will be directly accessible and don’t require using a registered variable.
Source: https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#ansible-facts
So, if printing hostvars[inventory_hostname] shows you a variable ansible_facts.ip_addresses then you can access it via ansible_ip_addresses — if that node only have one IP address assigned, see below if this is not the case:
- debug:
msg: >-
{{ ansible_hostname }}
{{ ansible_ip_addresses }}
{{ ansible_distribution }}
Mind that there is a bug that has been reported to the Ansible tracker about Windows machine having multiple IP addresses, and that it does not seems to be as trivial of a consensus as though what really is the default IP address:
There's really not a great solution to this issue- the concept of a "default IP address" means different things to different people, and the Linux fact is wrong as much as it's right. Usually this comes down to locating an address on a particular subnet, which we have to filters to assist with given the list of IP addresses... Given the lack of clarity on this, I'm going to close this issue.
Source: nitzmahone's comment on the issue https://github.com/ansible/ansible/issues/17014
So, to clear things up, the fact gathering in Windows and Linux are not implementing the same variable, you sure can work around this, implementing an inline-if:
- debug:
msg: >-
{{ ansible_hostname }}
{{
ansible_ip_addresses
if ansible_os_family == "Windows"
else ansible_default_ipv4.address
}}
{#
Mind that you still have to implement your own logic
of what is the "default" IP if you have more
than one IP address on that Windows machine, as linked above
#}
{{ ansible_distribution }}

The first thing I would do is using the new notation (removing any possibility to have failures due to misinterpretation):
---
- name: Gather Info
hosts: all
gather_facts: yes
tasks:
- name: Get some info
debug:
msg: "{{ ansible_hostname }} {{ ansible_default_ipv4['address'] }} {{ ansible_distribution }}"
Unless you're using caching mechanisms like redis/memcache, sometimes it takes some time to get results and probably is more efficient to get minimum facts.
To address the issue, I can't assist too much but if there's a bug closed in the windows module only developers could help here, as either Ansible team address this somehow or you might need to develop a small module for your needs.
UPDATE #1:
For what I can see if you gather a subset, you miss some information that you require ...
If you activate the gather_facts it doesn't fail with The error was: 'ansible_default_ipv4' is undefined.
UPDATE #2:
In regards to your error message, looks like something copied didn't was properly aligned.
In regards to how to get access to the variables:
pre_tasks:
- name: Collect only minimum facts.
ansible.builtin.setup:
gather_subset: "!all"
register: facts
When I register the collection, I use: facts.ansible_facts.ansible_domain to get the domain. maybe that give you enough insight about how to get the variables you need.

Related

Access Ansible inventory variables using with_items and vmware_guest for vSphere

I'm trying to convert a playbook which deploys vSphere VMs. The current version
of the playbook gets individual IP addresses and source template information
from vars/main.yml in the role (I'm using the best practice directory layout.)
vms:
- name: demo-server-0
ip_address: 1.1.1.1
- name: demo-server-1
ip_address: 1.1.1.2
Template, and other information is stored elsewhere in the vars.yml file but
it makes more sense to use the standard inventory, so I created these entries
in the inventory file:
test_and_demo:
hosts:
demo-server-0:
ip-address: 1.1.1.1
demo-server-1:
ip-address: 1.1.1.2
vars:
vc_template: xdr-template-1
The play is pretty much unchanged, apart from this key change:
FROM:
with_items: '{{ vms }}'
TO:
with_items: "{{ query('inventory_hostnames', 'test_and_demo') }}"
But this throws the following error:
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ModuleNotFoundError: No module named 'pyVim'
failed: [localhost] (item=demo-deployer) => {"ansible_loop_var": "item", "changed": false, "item": "demo-deployer", "msg": "Failed to import the required Python library (PyVmomi) on lubuntu's Python /usr/bin/python3. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter"}
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ModuleNotFoundError: No module named 'pyVim'
I don't believe this is a platform issue, as reverting back to with_items: '{{ vms }}'
works just fine (vars\main.yml still exists and duplicates data).
I'm probably using query incorrectly but can anyone give me a hint what I'm
doing wrong?
Accessing sub-values
If I can get the VMs to deploy using with_items: + query I'd then need to
access the variables of the host and group for the various items I need to
specify, can someone advise me here, too.
Many thanks.
Although I was convinced the problem was in the way I was doing the query, it was in the root Play which I hadn't noticed. By adding become: yes I think it was switching to the root user which didn't have the module installed.
Once it was removed, the problem was resolved.
- hosts: localhost
roles:
- deploy_demo_servers
become: yes

Get Name interface of network with ansible

I want to deploy an ovirt template with Ansible, but the problem is that when I want to apply the cloud-init the template displays a different network interface file name every time, that is,
sometimes it is eth0, other times ens33 etc. How could I get this information to be able to apply the cloud init correctly.
Thank you.
How about the ovirt_nic_info module?
If you need to gather data there are many ovirt _info modules.
If you have further issues/questions you can open an issue on
https://github.com/ovirt/ovirt-ansible-collection
- ovirt_nic_info:
auth: "{{ ovirt_auth }}"
vm: centos8
register: result
- debug:
msg: "{{ result.ovirt_nics[0].reported_devices[0].name }}"

ansible the way to use consul_kv change between two versions

I need some help on using consul_kv module with ansible version since 2.8.x , maybe i missed something, but i took a look to the code of the module and i don't realy see changes between 2.7.x and 2.8.x that can explay the problem i got.
With ansible 2.7.x , when i try to get value from consul, i get consul host, port, path from my env vars and i execute my code like this:
# group_var/all
consul_path: "{{ lookup('env','ANSIBLE_CONSUL_PATH') }}"
consul_host: "{{ lookup('env','ANSIBLE_CONSUL_HOST') }}"
consul_port: "{{ lookup('env', 'ANSIBLE_CONSUL_PORT') }}"
- hosts: localhost
tasks:
- name: test ansible 2.8.5 with consul
debug:
msg: "{{ lookup('consul_kv', consul_path+'path/to/value' }}"
it works on 2.7.0 and i got my value, but doesn't work on 2.8.x , from those newer versions i need to specify host and port on each line which using lookup
msg: "{{ lookup('consul_kv', 'path/to/value', host='myconsulhost.com', port='80') }}"
Is there a way to continue to use env vars in ansible 2.8.x with this module ?
The fine manual says that the lookup now uses the $ANSIBLE_CONSUL_URL environment variable to determine the protocol, hostname, and port -- or (as you observed) using the inline kwargs to the lookup function. Those group_vars you mentioned no longer seem to be consulted
You'll also want to be careful as your group_vars/all (at least in this question, unknown if you are really doing it) has a trailing space in consul_path : which creates a variable named consul_path<space>

Ansible - vars are not correctly propagated to handlers when role run in loop

I am asking for help with a problem of deploying multiple versions (different variables) of the app with the same role run from one playbook.
We have an app with multiple product families, which are different code versions. Each version has separate uWSGI vassal config and Nginx virtualhost config(/api/v2, /api/v3, ...).
The desired state would be to run playbook and configure the server with all versions specified.
Sadly, ansible's import_role/import_tasks can't be used with with_items, so include_role/include_tasks must be used (pitty because they do not honor role tags).
The include_role method would not be the biggest problem, but we use handlers to notify uWSGI touch to reload - on a code change, link change, virtualenv change, app_config change, ...).
But when using loop (with_items), the variables passed from the loop does not correctly propagate to handlers.
I tried this scenarios
playbook.yml - with_items loop inside the playbook
PROBLEM: Handler is run only for the first iteration of the loop.
#!/usr/bin/env ansible-playbook
# HAndler is run only once, from first notifier
- hosts: localhost
gather_facts: no
vars:
app_root: "/tmp/test_ansible"
app_versions:
- app_product_family: 1
app_release: "v1.0.2"
- app_product_family: 3
app_release: "v4.0.7"
tasks:
- name: Deploy multiple versions of app
include_role:
name: app
with_items: "{{ app_versions }}"
loop_control:
loop_var: app_version
vars:
app_product_family: "{{ app_version.app_product_family }}"
app_release: "{{ app_version.app_release }}"
tags:
- app
- app_debug
playbook_v2.yml - with_items loop inside role task
PROBLEM: Handler is run with the default value from "Defaults"
#!/usr/bin/env ansible-playbook
- hosts: localhost
gather_facts: no
roles:
- app_v2
vars:
app_v2_root: "/tmp/test_ansible_v2"
app_v2_versions:
- app_v2_product_family: 1
app_v2_release: "v1.0.2"
- app_v2_product_family: 3
app_v2_release: "v4.0.7"
Tasks roles/app_v2/main.yml
---
# Workaround because import_tasks can't be run with_items
- include_tasks: deploy.yml
when: app_v2_versions
with_items: "{{ app_v2_versions }}"
loop_control:
loop_var: app_v2
vars:
app_v2_product_family: "{{ app_v2.app_v2_product_family }}"
app_v2_release: "{{ app_v2.app_v2_release }}"
tags:
- app_v2
- app_v2_deploy
...
One idea was about writing a separate role for each product family, but they share nginx and uWSGI, so it will be lots of copy-pasting and sharing tasks (so tags would not work properly).
For now, I solved it with shell script wrapper, but this is not an ideal solution and does not work from Ansible tower.
Sample repo with tasks to reproduce problem (tested with ansible 2.4, 2.5, 2.6)
Any ideas & recommendations are very welcome.
The order of overrides for variables is broken for includes in Ansible. F.e. even set_fact in the included role will be shadowed by role defaults.
See this bug: https://github.com/ansible/ansible/issues/22025
It's closed but not fixed. My advice: use include and variables really carefully.
In practice I never use role includes with loop. If you need loop, include a tasklist in this loop (and that tasklist, in turn, may import_role).
Ok, It is a bug as #George Shuklin posted.
I will use my shell wrapper, which reads group_vars yaml and then runs the playbook multiple times according to the variable list length.
Sadly I hit multiple annoying bugs in ansible in last few weeks, kinda losing my trust in it ):
And probably everybody is using microservices and kubernetes, so need to speed up our migration (:

Ansible - Unable to run certain JUNOS modules

I'm trying to run the Ansible modules junos_cli and junos_rollback and I get the following error:
ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.
The error appears to have been in '/home/quake/network-ansible/roles/junos-rollback/tasks/main.yml': line 2, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
---
- name: I've made a huge mistake
^ here
This is the role in question:
---
- name: I've made a huge mistake
junos_rollback:
host={{ inventory_hostname }}
user=ansible
comment={{ comment }}
confirm={{ confirm }}
rollback={{ rollback }}
logfile={{ playbook_dir }}/library/logs/rollback.log
diffs_file={{ playbook_dir }}/configs/{{ inventory_hostname }}
Here is the Juniper page:
http://junos-ansible-modules.readthedocs.io/en/1.3.1/junos_rollback.html
Their example's syntax is a little odd. host uses a colon while the rest uses = signs. I've tried mixing both and only using one or the other. I keep getting errors.
I also confirmed that my junos-eznc version is higher than 1.2.2 (I have 2.0.1)
I've been able to use junos_cli before, I don't know if a version mismatch happened. On the official Ansible documentation, there is no mention of junos_cli or junos_rollback. Perhaps they're not supported anymore?
http://docs.ansible.com/ansible/list_of_network_modules.html#junos
Thanks,
junos_cli & junos_rollback are part of Galaxy and not core modules. You can find them at
https://galaxy.ansible.com/Juniper/junos/
Is the content posted here has whole content of your playbook? if yes, You need to define other items too in your playbook such as roles, connection, local. For example
refer https://github.com/Juniper/ansible-junos-stdlib#example-playbook
```
---
- name: rollback example
hosts: all
roles:
- Juniper.junos
connection: local
gather_facts: no
tasks:
- name: I've made a huge mistake
junos_rollback:
host = {{inventory_hostname}}
----
----
```
Where have you saved the content of juniper.junos modules?. Can you post the content of your playbook and the output of the tree command to see your file structure? That could help.
I had a similar problem where Ansible was not finding my modules and what I did was to copy the juniper.junos folder to my roles folder and then added a tasks folder within it to execute the main.yaml from there.
Something like this:
/Users/macuared/Ansible_projects/roles/Juniper.junos/tasks
---
- name: "TEST 1 - Gather Facts"
junos_get_facts:
host: "{{ inventory_hostname}}"
user: "uuuuu"
passwd: "yyyyyy"
savedir: "/Users/macuared/Ansible_projects/Ouput/Facts"
ignore_errors: True
register: junos
- name: Checking Device Version
debug: msg="{{ junos.facts.serialnumber }}"
Additionally, I would add "" to the string values in your YAML. Something like this:
---
- name: I've made a huge mistake
junos_rollback:
host="{{ inventory_hostname }}"
user=ansible
comment="{{ comment }}"
confirm={{ confirm }}
rollback={{ rollback }}
logfile="{{ playbook_dir }}/library/logs/rollback.log"
diffs_file="{{ playbook_dir }}/configs/{{ inventory_hostname }}"
Regarding this "I've tried mixing both and only using one or the other. I keep getting errors."
I've used just colon and mine works fine even when in the documentation suggests = signs. See junos_get_facts

Resources