#ansible #jinja2 #json-query
Вопрос:
Ansible уже провел «сбор фактов», и у каждого хоста hostvars
уже есть ansible_memory_mb.real.total
набор.
Как мне выбрать хост(ы), чтобы это число было выше среднего для всех из них? Должна быть однострочная фильтрация Джинджа, которую я не могу понять…
Ответ №1:
Например, извлеките переменные, которые вы хотите
mems: "{{ ansible_play_hosts| map('extract', hostvars, 'ansible_memfree_mb')| list }}"
mems: - 99 - 84 - 86
Примечание: Для извлечения ansible_memory_mb.real.total
попробуйте
mems: "{{ ansible_play_hosts| map('extract', hostvars, ['ansible_memmory_mb','real','total'])| list }}"
и создайте словарь
hosts_mems: "{{ dict(ansible_play_hosts|zip(mems)) }}"
hosts_mems: host01: 99 host02: 84 host03: 86
Рассчитайте среднее значение
mems_average: "{{ hosts_mems.values()|sum / hosts_mems.values()|length }}"
mems_average: '89.66666666666667'
и выберите хосты с большим объемом памяти, чем в среднем
hosts_mems_high: "{{ hosts_mems|dict2items| selectattr('value', 'gt', mems_average|int)|items2dict }}"
hosts_mems_high: host01: 99
Если вы хотите «однострочную фильтрацию Джинджи», т. Е. Если вы хотите уменьшить количество переменных, делайте замены по своему усмотрению.
Комментарии:
1. Спасибо, @Vladimir. Но этот метод работает, но превращает словарь в список-а затем снова в словарь-несколько раз. Неужели нет ничего короче-и быстрее? Скажи, с
hostvars | json_query(......)
кем ?2. Если вы что-нибудь найдете, скажите мне.
Ответ №2:
Вот как я в итоге это сделал. Не совсем однострочный-сначала мне нужно рассчитать среднюю оперативную память, что мне очень нравится, как @Vladimir-Ботка предлагает в своем ответе.
Однако мой метод избегает dict2items
и того zip
, и другого, что, на мой взгляд, делает его более совершенным:
- name: Figure out, if there is a business server with spare RAM set_fact: spareserver: gt;- {{ (groups.business | map('extract', hostvars) | selectattr('ansible_memory_mb.real.total', 'gt', avgram | float) | first).ansible_hostname }} vars: ramsizes: gt;- {{ groups.business | map('extract', hostvars, [ 'ansible_memory_mb', 'real', 'total' ]) | list }} avgram: '{{ (ramsizes | sum) / (ramsizes | length) }}'
Наблюдения:
- Необходимость явного преобразования в
float
является либо ошибкой, либо очень раздражающей «функцией». Значениеavgram
было результатом арифметического выражения-почему переменная переходной задачи записывается в виде строки, которую необходимо снова перевести в плавающее значение? С возможной потерей точности тоже? - Я обращаюсь
map('extract')
hostvars
дважды-мне это не нравится, но я не знаю, как этого избежать-предложения приветствуются. - Я до сих пор не понимаю, почему
json_query
не получалось. Приведенное ниже не приводило к каким-либо ошибкам, ноspareserver
оно было пустым.
- set_fact: spareserver: gt;- {{ hostvars | json_query('[?ansible_memory_mb.real.total gt; `{{ avgram }}`]') }}
- Тот, кто понизил мой вопрос из-за того, что я попросил Владимира найти лучшее решение, должен прекратить использовать StackOverflow.