I need to create a check very similar to that one explained here: Ansible to check diskspace for mounts mentioned as variable
Except I need it only for specified paths (for example /var).
{{ ansible_mounts }} is an array of dictionaries, each containing variable mount that is the actual path. I need to perform the check in a loop for all items in {{ ansible_mounts }} only if mount is equal to some value.
Example of what I want to achieve in pseudo code:
foreach (mountpoint in ansible_mounts)
{
if (mountpoint["mount"] == "/var" || mountpoint["mount"] == "/opt")
{
// do the check
}
}
How can I do this in Jinja / Ansible? This code does the check for every single item. I need to filter it only for explicitly specified paths:
- name: Ensure that free space on the tested volume is greater than 15%
assert:
that:
- mount.size_available > mount.size_total|float * 0.15
msg: Disk space has reached 85% threshold
vars:
mount: "{{ ansible_mounts | selectattr('mount','equalto',item.mount) | list | first }}"
with_items:
- "{{ ansible_mounts }}"
you'll need to add a when condition, for example
vars:
my_mounts:
- '/var/log'
- '/var/logs/foo'
tasks:
- name: do the check
when: item.mount in my_mounts
with_items: '{{ ansible_mounts }}'
Related
I am trying to use a register in Ansible playbook to store my output. Below is the code which i am using.
I have tried below code
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: {{ item }}_service_status
with_items:
- XXX
- YYY
- ZZZ
I need different outputs to be stored in different register variables based on the items as mentioned in the code. It is failing and not able to proceed. Any help would be appreciated.
Updated answer
I think you need to put quotes around it:
register: "{{ item }}_service_status"
Or you can use set_fact (1, 2, 3, 4)
register all the output to a single static variable output and then use a loop to iteratively build a new variable service_status (a list) by looping over each item in the static variable output
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: output
with_items:
- XXX
- YYY
- ZZZ
- name: Setting fact using output of loop
set_fact:
service_status:
- rc: "{{ item.rc }}"
stdout: "{{ item.stdout }}"
id: "{{ item.id }}"
with_items:
- "{{ output }}"
- debug:
msg: "ID and stdout: {{ item.id }} - {{ item.stdout }}"
with_items:
- "{{ service_status }}"
Initial Answer
IIUC, this link from the Ansible docs shows how to use register inside a loop (see another example in this SO post).
A couple of points
it may be more convenient to assign the list (XXX, YYY, ZZZ) to a separate variable (eg. 1, 2)
I don't know if this is part of the problem, but with_items is no longer the recommended approach to loop over a variable: instead use loop - see here for an example
vars:
items:
- XXX
- YYY
- ZZZ
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: service_status
loop: "{{ items|flatten(levels=1) }}"
- name: Show the return code and stdout
debug:
msg: "Cmd {{ item.cmd }}, return code {{ item.rc }}, stdout {{ item.stdout }}"
when: item.rc != 0
with_items: "{{ service_status.results }}"
I am trying to create a list of unused disks from gather facts
-
key | search ("sd")
with_dict: "{{ ansible_devices }}"
But its only displaying one disk, like if the server have two unused disks sdb and sdc , its only displaying sdb. How can I modify my code to include all unused disks.
the way you have it, set_fact gets equal to the "current" item from the iteration, probably this is why you see only 1 disk in the final result. You need to set the disks as a list of elements and append to that list the current item.key. you can use this syntax:
set_fact:
disks: "{{ disks|default([]) + ['/dev/{{item.key}}'] }}"
to understand how many results you have in the loops of the with_dict clause, you can try a debug task:
- name: Print disk result
debug:
msg: "/dev/{{item.key}}"
when:
- not item.value.partitions
- not item.value.holders
- not item.value.links.ids
- item.key | search ("sd")
with_dict: "{{ ansible_devices }}"
(indentation may need fixes, i just copied from your code)
hope it helps
thanks for the reply, I used the mentioned code for printing the disk result, it was displaying multiple disks, but when I used set_fact, and the msg to display the variable, its showing like this:-
"disks": [
"/dev/sdc",
"/dev/{{item.key}}"
]
- name: Print disk result
set_fact:
disks: "{{ disks|default([]) + ['/dev/{{item.key}}'] }}"
when:
- not item.value.partitions
- not item.value.holders
- not item.value.links.ids
- item.key | search ("sd")
with_dict: "{{ ansible_devices }}"
- debug: var=disks
If anyone is ever looking for the answer, this works for me:
- name: Print disk result
set_fact:
disks: "{{ disks|default([]) + ['/dev/' + item.key] }}"
when:
- not item.value.partitions
- not item.value.holders
- not item.value.links.ids
- item.key | regex_search ("sd")
with_dict: "{{ ansible_devices }}"
- name: debug
debug:
msg: "{{disks}}"
It returns:
ok: [localhost] => {
"msg": [
"/dev/sdb"
]
}
When a task is skipped on the basis of condition and the result of register also differ which cause of another task has been failed.
- name: Check if the partition is already mounted
shell: df | grep "{{item.partition}}" | wc -l
with_items:
- "{{ ebs_vol }}"
register: ebs_checked
when: ebs_vol is defined
- name: Make filesystem of the partition
filesystem: fstype=ext4 dev={{item.item.partition}} force=no
when: ( ebs_vol is defined and "{{item.stdout}} == True" )
changed_when: True
with_items:
- ebs_checked.results
Use default filter to handle corner cases:
- name: Make filesystem of the partition
filesystem: fstype=ext4 dev={{item.item.partition}} force=no
when: item.stdout | bool
changed_when: True
with_items: "{{ ebs_checked.results | default([]) }}"
This will iterate over empty list (read "will do nothing") if there is no results in ebs_checked.
Also you should not check for ebs_vol is defined because when statement in looped tasks is applied inside a loop, and keeping in mind that you check for ebs_vol is defined in the previous task, makes this check unnecessary inside a loop.
I am new to ansible and currently working on a play which will see if disk space of remote machines has reached 70% threshold. If they have reached it should throw error.
i found a good example at : Using ansible to manage disk space
but at this example the mount names are hard coded. And my requirement is to pass them dynamically. So i wrote below code which seems to not work:
name: test for available disk space
assert:
that:
- not {{ item.mount == '{{mountname}}' and ( item.size_available <
item.size_total - ( item.size_total|float * 0.7 ) ) }}
with_items: '{{ansible_mounts}}'
ignore_errors: yes
register: disk_free
name: Fail the play
fail: msg="disk space has reached 70% threshold"
when: disk_free|failed
This play works when i use:
item.mount == '/var/app'
Is there any way to enter mountname dynamically ? and can i enter multiple mount names ??
I am using ansible 2.3 on rhel
Thanks in advance :)
Try this:
name: Ensure that free space on {{ mountname }} is grater than 30%
assert:
that: mount.size_available > mount.size_total|float * 0.3
msg: disk space has reached 70% threshold
vars:
mount: "{{ ansible_mounts | selectattr('mount','equalto',mountname) | list | first }}"
that is a raw Jinja2 expression, don't use curly brackets in it.
why do you use separate fail task, if assert can fail with a message?
For those who cannot use selectattr (like me), here is a variant of the first answer using when and with_items to select the mount point to check.
name: 'Ensure that free space on {{ mountname }} is grater than 30%'
assert:
that: item.size_available > item.size_total|float * 0.3
msg: 'disk space has reached 70% threshold'
when: item.mount == mountname
with_items: '{{ ansible_mounts }}'
Note: To be able to use the variable {{ ansible_mounts }} you need to turn gather_facts to yes that can be limited to gather_subset=!all,hardware.
I'm running Ansible 2.5 and was able to get Konstantin Suvorov's solution to work with a slight mod by adding with_items. Sample code below:
- name: Ensure that free space on the tested volume is greater than 15%
assert:
that:
- mount.size_available > mount.size_total|float * 0.15
msg: Disk space has reached 85% threshold
vars:
mount: "{{ ansible_mounts | selectattr('mount','equalto',item.mount) | list | first }}"
with_items:
- "{{ ansible_mounts }}"
Thanks to other stackoverflow users, I have managed to pull some data out of a variable registered by the digital_ocean ansible module. I attempted to use loop_control to print only part of the huge variable that is registered. Here is an extract from the role:
- name: Add droplet
digital_ocean: >
{ some parameters }
with_dict: "{{ droplets_up }}"
register: my_droplet
- debug: msg="Droplet IP is {{ item.droplet.ip_address }}"
with_items: "{{ my_droplet.results }}"
loop_control:
label: "{{ item }}"
I'm obviously doing it wrong here, as it prints the whole variable as well as the debug message. I don't quite understand loop_control at this point, but does anyone know if it's possible to use it in this manner with this module?
debug action has result['_ansible_verbose_always'] = True, so it will always print full item, no matter what your label is (although label: "{{item}}" doesn't change anything, try label: "{{ item.droplet.ip_address }}").
If you just need to list all your IP addresses, use map filter and single debug statement:
- name: Print droplets IP
debug:
msg: "{{ my_droplet.results | map(attribute='droplet.ip_address') | list }}"