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 }}"
Related
I try to increment a variable for each item contained in "with_items".
For exemple, I would like that the "counter" variable to increment by 1 for each item
- set_fact:
number: 0
- set_fact:
esx_conf:
counter : {{ number | int + 1 }}
value1 : {{ item.ansible_facts.hardware.memorySize }}
value2 : {{ item.ansible_facts.summary.quickStats.overallMemoryUsage }}
value3 :"{{ item.item.name }}
with_items: "{{ esxi_infos.results }}"
register: all_esx_conf
It would seem that this is not possible.
I tried to play with "with_sequence" or "with_nested" as well.
Do you have any idea ?
Thanks & regards,
Ansible is a declarative language, which makes that kind of thing tricky.
The whole point of the language is to just describe the tasks that you want done, and not the way to do them, which makes procedural tasks like those difficult to achieve.
You can take a look a the following stack overflow answer, that might help you getting what you are trying to achieve:
Using set_facts and with_items together in Ansible
However, maybe if you could give a little more info on what the high level objective is, there might be a better way to achieve it using Ansible than looping and incrementing a counter.
Thanks for your answer.
My goal is to have a list like this :
ESX 1 - RAM 50% - CPU 40%
ESX 2 - RAM 50% - CPU 40%
ESX 3 - RAM 50% - CPU 40%
....
Data is collected with "community.vmware.vmware_host_facts". Currently, here is my playbook :
- name: "ESX information"
community.vmware.vmware_host_facts:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: no
esxi_hostname: "{{ item.name }}"
schema: vsphere
properties:
- hardware.memorySize
- hardware.cpuInfo.numCpuCores
- hardware.cpuInfo.hz
- summary.quickStats.overallMemoryUsage
- summary.quickStats.overallCpuUsage
- config.fileSystemVolume.mountInfo
with_items: "{{ liste_ESX | json_query('*.value') }}"
register: esxi_infos
- set_fact:
esx_conf: "{{ item.item.name }} - RAM : {{ (( item.ansible_facts.summary.quickStats.overallMemoryUsage / ( item.ansible_facts.hardware.memorySize / (1024*1024) ) ) * 100 ) | int }}% - CPU : {{ (( item.ansible_facts.summary.quickStats.overallCpuUsage / ( item.ansible_facts.hardware.cpuInfo.numCpuCores * ( item.ansible_facts.hardware.cpuInfo.hz / 1000000 ) ) ) * 100) | int }}%"
with_items: "{{ esxi_infos.results }}"
register: all_esx_conf
- set_fact:
esx_conf: "{{ item.ansible_facts.esx_conf }}"
with_items: "{{ all_esx_conf.results }}"
register: all_esx_conf
- debug:
msg: "{{ all_esx_conf.results | map(attribute='ansible_facts.esx_conf') | list }}"
The result is :
TASK [debug] ***************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"ESX 1 - RAM : 74% - CPU : 11%",
"ESX 2 - RAM : 70% - CPU : 11%",
"ESX 3 - RAM : 65% - CPU : 13%",
...
]
}
After that, I have a pause :
- pause:
prompt: "ESX chosen ?"
register: prompt
So, with a counter for each "ITEM", the user will type 1,2,3...to choose the ESX.
What do you think?
Thanks !
I have a play that search for available storage in vm datastore to find disk space.
- name: Select the datastore which has minimum of 500GB
include_role: find_disk_space_datastore
with_item:
-datastore_001
-datastore_002
-datastore_003
Role: roles/find_disk_space_datastore/tasks/main.yml
- name: search for domain {{ item }}
blah ...blah save the free space on {{ disk_space }} variable
- name: find the datastore
setfact:
datastore_name:
when: {{ disk_space }} >> 500
Assume I have found free space in second item which is datastore_002 instead of going to datastore_003 in the loop how can I exit from there ?????
note - I need to break the loop in between.
thank you inadvanced
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 }}'
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"
]
}
Simple ask: I want to delete some files if partition utilization goes over a certain percentage.
I have access to "size_total" and "size_available" via "ansible_mounts". i.e.:
ansible myhost -m setup -a 'filter=ansible_mounts'
myhost | success >> {
"ansible_facts": {
"ansible_mounts": [
{
"device": "/dev/mapper/RootVolGroup00-lv_root",
"fstype": "ext4",
"mount": "/",
"options": "rw",
"size_available": 5033046016,
"size_total": 8455118848
},
How do I access those values, and how would I perform actions conditionally based on them using Ansible?
Slava's answer definitely was on the right track, here is what I used:
- name: test for available disk space
assert:
that:
- not {{ item.mount == '/' and ( item.size_available < item.size_total - ( item.size_total|float * 0.8 ) ) }}
- not {{ item.mount == '/var' and ( item.size_available < item.size_total - ( item.size_total|float * 0.8 ) ) }}
with_items: ansible_mounts
ignore_errors: yes
register: disk_free
- name: free disk space
command: "/some/command/that/fixes/it"
when: disk_free|failed
The assert task simply tests for a condition, by setting ignore_errors, and registering the result of the test to a new variable we can perform a conditional task later in the play instead of just failing when the result of the assert fails.
The tests themselves could probably be written more efficiently, but at the cost of readability. So I didn't use a multiple-list loop in the example. In this case the task loops over each item in the list of mounted filesystems (an ansible-created fact, called ansible_mounts.)
By negating the test we avoid failing on file system mounts not in our list, then simple math handles the rest. The part that tripped me up was that the size_available and size_total variables were strings, so a jinja filter converts them to a float before calculating the percentage.
In my case, all I care about is the root partition. But I found when using the example from frameloss above, that I needed a negated 'or' condition, because each mount point will get tested against the assertion. If more than one mount point existed, then that meant the assertion would always fail. In my example, I'm testing for if the size_available is less than 50% of size_total directly, rather than calculate it as frameloss did.
Secondly, at least in the version of ansible I used, it was necessary to include the {{ }} around the variable in with_items. A mistake that I made that wasn't in the example above was not aligning the 'when' clause at the same indentation as the 'fail' directive. ( If that mistake is made, then the solution does not work... )
# This works with ansible 2.2.1.0
- hosts: api-endpoints
become: True
tasks:
- name: Test disk space available
assert:
that:
- item.mount != '/' or {{ item.mount == '/' and item.size_available > (item.size_total|float * 0.4) }}
with_items: '{{ ansible_mounts }}'
ignore_errors: yes
register: disk_free
- name: Fail when disk space needs attention
fail:
msg: 'Disk space needs attention.'
when: disk_free|failed
I didn't test it but I suggest to try something like this:
file:
dest: /path/to/big/file
state: absent
when: "{% for point in ansible_mounts %}{% if point.mount == '/' and point.size_available > (point.size_total / 100 * 85) %}true{% endif %}{% endfor %}" == "true"
In this example, we iterate over mount points and find "/", after that we calculate is there utilization goes over 85 percentage and prints "true" if it's true. Next, we compare that string and decide should this file be deleted.
Inspired by examples from the following blog: https://blog.codecentric.de/en/2014/08/jinja2-better-ansible-playbooks-templates/
My solution
- name: cleanup logs, free disk space below 20%
sudo: yes
command: find /var -name "*.log" \( \( -size +50M -mtime +7 \) -o -mtime +30 \) -exec truncate {} --size 0 \;
when: "item.mount == '/var' and ( item.size_available < item.size_total * 0.2 )"
with_items: ansible_mounts
This will truncate any *.log files on the volume /var that are either older than 7 days and greater than 50M or older than 30 days if the free disk space falls below 20%.