Looking for way to fetch "just" size_available of a particular mount point on remote host from ansible_hosts fact and set that as fact variable in playbook. Can't really figure that out - please share code snippet.
For Ansible 2.8.2 I found that the above solution didn't work and failed with:
templating error while templating string: expected token ',', got 'string'.
The following, however, worked (moving the query text to a variable):
- debug:
msg: "{{ ansible_mounts|json_query(jmesquery) | first }}"
vars:
jmesquery: "[?mount == `/`].size_available"
gives:
"msg": "40047341568"
JSON Query Filter would do the job. For example size_available for mount: /
- debug:
msg: "{{ ansible_mounts|json_query('[?mount == `/`].size_available') }}"
gives:
"msg": [
40047341568
]
Related
I am trying to write an Ansible script which will compress files on multiple hosts, based on inventory file. The code and inventory file has given below.
tasks:
- name: Create a tar.gz archive of a single file.
community.general.archive:
path:
- "{{items.path}}"
dest:
- "{{items.dest}}"
format: gz
owner: ubuntu
become: true
when: "{{items.key}} in inventory_hostname"
with_items:
- {path: "/var/log/adobe/adobe.log", dest: "/tmp/adobe.log.gz", key: "adobe"}
- {path: "/usr/local/app/applc.log", dest: "/tmp/applc.log.gz", key: "applc"}
inventory file (hosts.ini) contains the hostname.
vm-stg-adobe-201
vm-stg-adobe-202
vm-stg-applc-101
But when I execute the code am getting the below error.
FAILED! => {"msg": "The conditional check '{{items.key}} in inventory_hostname' failed. The error was: error while evaluating conditional ({{items.key}} in inventory_hostname): 'items' is undefined
I tried changing items.key as follows but failed.
when: "'items.key' in inventory_hostname"
when: "'{{items.key}}' in inventory_hostname" [when I use this the host key skipped]
Any will be much appreciated. Thank you.
After fixing the variable name issue, next task is to make the when condition work based on the hostname and the item.key.
Since the hostnames in your inventory have a pattern, the ideal way would be to split the hostname on the - delimiter and try to match the 3rd column to the item.key. In code, you could do these by:
when: inventory_hostname.split('-')[2] == item.key
UPDATE:
If you want to just search if the inventory_hostname contains the item.key, you can use:
when: inventory_hostname is search(item.key)
cheers
Following is the piece of code, which is retrieving list of local zones and trying to enter rescue block if any one of the local zones is not in RUNNING state.
But the rescue block is failing, at 'Check if the zones are in running state'
Expectation is to send an email with the task name. But it is working well with other failed tasks.Can anyone please guide?
FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'item' is undefined\n\nThe error appears to be in '/etc/ansible/playbooks/misc/test1404.yml': line 23, column 9, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n rescue:\n - name: Sending an e-mail from Ansible controller node\n ^ here\n"}
- '{{ host }}'
tasks:
- block:
- name: Retrieve list of local zones
shell: /usr/sbin/zoneadm list | grep -v global
register: lzones
tags:
- local_zone_list
- debug:
msg: "{{ item }}"
with_items: "{{lzones.stdout_lines}}"
- name: Check if the zones are in running state
shell: /usr/sbin/zoneadm list | grep -v global | grep "{{ item }}" | awk '{print$3}'
register: status
with_items: "{{lzones.stdout_lines}}"
failed_when: status.stdout.find('running') == -1
< few other tasks>
rescue:
- name: Sending an e-mail from Ansible controller node
mail:
host: localhost
port: 25
to: xyz#abc.com
subject: Reboot Failed
body: Reboot FAILED at TASK - {{ ansible_failed_task.name }} with ERROR {{ ansible_failed_result }}
delegate_to: localhost
Well that was an absolutely fascinating rabbit hole.
Because in ansible jinja2 templates are rendered recursively, when it tries to render the failed message, which contains the failed template, it tries to re-render the failed template again, re-causing the error
This appears to be impacting you by the inclusion of the ansible_failed_task variable, since -- inexplicably -- it appears to be safe to include ansible_failed_result in the body
As best I can tell by experimenting with ansible 2.9.6, one must determine if it is possible to safely output the a*_task flavor variable before touching it, because I was wholly unable to find any combination of | string or |regex_replace or anything that allowed jinja2 to touch that variable so long as it contains the bogus variable reference:
- block:
- debug:
msg: this explodes {{ nope_not_a_var }}
rescue:
- set_fact:
is_undefined_error: '{{ "undefined variable" in ansible_failed_result.msg }}'
- name: variable is unsafe version
debug:
msg: >-
failed task action has an undefined variable in the task,
so we cannot show you the task, but here is the result: {{ ansible_failed_result }}
when: is_undefined_error
- name: variable is safe to output version
debug:
msg: Reboot FAILED at TASK - {{ ansible_failed_task.name }} with ERROR {{ ansible_failed_result }}
when: not is_undefined_error
It may be safe to inline that test of "..." in ansible_failed_result.msg into the when: lines directly, but since it (should) produce the same answer both times, there's no really good reason to evaluate it twice
This appears to me to be an ansible bug, but I don't have the emotional energy to take it up with their community -- however, I encourage you to file a bug with them
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.
I know accessing Ansible facts is well documented, but I can't get this code to work.
# site.yml
---
- name: get fact
hosts: webservers
tasks:
- debug: msg="{{ hostvars['web01.example.com']['ansible_all_ipv4_addresses'] }}"
- fail:
When I run it, I get this error:
fatal: [web01.example.com] => One or more undefined variables: 'dict object' has no attribute 'ansible_all_ipv4_addresses'
Yet when I run the command "ansible -i inventory -m setup", I do see the dictionary key:
web01.example.com | success >> {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"<ip_address>"
],
(other objects...)
}
}
This is my inventory file:
# inventory
[webservers]
web01.example.com ansible_host=<ip_address>
I also tried the following hostvars setting but I get the same error:
hostvars['web01.example.com']['ansible_facts']['ansible_all_ipv4_addresses']
What am I doing wrong here? It seems like this should be pretty easy.
It is a little confusing with ansible, but you just use (without ansible_facts in the middle):
hostvars['web01.example.com']['ansible_all_ipv4_addresses']
Or as #oley posted
hostvars[inventory_hostname]['ansible_all_ipv4_addresses']
for the respective host in a task
In documentation you posted it is also always without ansible_facts in the middle, but it is just easy to overlook :)
This should do the trick:
- debug: msg="{{ hostvars[inventory_hostname]['ansible_all_ipv4_addresses'] }}"
I cannot get this seemingly simple example to work in Ansible 1.8.3. The variable interpolation does not kick in the task name. All examples I have seen seem to suggest this should work. Given that the variable is defined in the vars section I expected the task name to print the value of the variable. Why doesn't this work?
Even the example from the Ansible documentation seems to not print the variable value.
---
- hosts: 127.0.0.1
gather_facts: no
vars:
vhost: "foo"
tasks:
- name: create a virtual host file for {{ vhost }}
debug: msg="{{ vhost }}"
This results in the following output:
PLAY [127.0.0.1]
**************************************************************
TASK: [create a virtual host file for {{ vhost }}]
****************************
ok: [127.0.0.1] => {
"msg": "foo"
}
PLAY RECAP
********************************************************************
127.0.0.1 : ok=1 changed=0 unreachable=0 failed=0
Update
This works with 1.7.2 but does not work with 1.8.3. So either this is a bug or a feature.
Variables are not resolved inside the name. Only inside the actual tasks/conditions etc. the placeholders will be resolved. I guess this is by design. Imagine you have a with_items loop and use the {{ item }}in the name. The tasks name will only be printed once, but the {{ item }} would change in every iteration.
I see the examples, even the one in the doc you linked to, use variables in the name. But that doesn't mean the result would be like you expected it. The docs are community managed. It might be someone just put that line there w/o testing it - or maybe it used to work like that in a previous version of Ansible and the docs have not been updated then. (I'm only using Ansible since about one year). But even though it doesn't work like we wish it would, I'm still using variables in my name's, just to indicate that the task is based on dynamic parameters. Might be the examples have been written with the same intention.
An interesting observation I recently made (Ansible 1.9.4) is, default values are written out in the task name.
- name: create a virtual host file for {{ vhost | default("foo") }}
When executed, Ansible would show the task title as:
TASK: [create a virtual host file for foo]
This way you can avoid ugly task names in the output.
Explanation
Whether the variable gets interpolated depends on where it has been declared.
Imagine You have two hosts: A and B.
If variable foo has only per-host values, when Ansible runs the play, it cannot decide which value to use.
On the other hand, if it has a global value (global in a sense of host invariance), there is no confusion which value to use.
Source: https://github.com/ansible/ansible/issues/3103#issuecomment-18835432
Hands on playbook
ansible_user is an inventory variable
greeting is an invariant variable
- name: Test variable substitution in names
hosts: localhost
connection: local
vars:
greeting: Hello
tasks:
- name: Sorry {{ ansible_user }}
debug:
msg: this won't work
- name: You say '{{ greeting }}'
debug:
var: ansible_user
I experienced the same problem today in one of my Ansible roles and I noticed something interesting.
When I use the set_fact module before I use the vars in the task name, they actually get translated to their correct values.
In this example I wanted to set the password for a remote user:
Notice that I use the vars test_user and user_password that I set as facts before.
- name: Prepare to set user password
set_fact:
user_password: "{{ linux_pass }}"
user_salt: "s0m3s4lt"
test_user: "{{ ansible_user }}"
- name: "Changing password for user {{ test_user }} to {{ user_password }}"
user:
name: "{{ ansible_user }}"
password: "{{ user_password | password_hash('sha512', user_salt) }}"
state: present
shell: /bin/bash
update_password: always
This gives me the following output:
TASK [install : Changing password for user linux to LiNuXuSeRPaSs#]
So this solved my problem.
It might be ugly, but you can somewhat workaround with something like this:
- name: create a virtual host file
debug:
msg: "Some command result"
loop: "{{ [ vhost ] }}"
or
- name: create a virtual host file
debug:
msg: "Some command result"
loop_control:
label: "{{ vhost }}"
loop: [1]
I wouldn't do this in general, but it shows how you can use items or label to give information outside of the command result. While it might not
Source: https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html