Как составить список хостов с объемом оперативной памяти больше среднего?

#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) }}'  

Наблюдения:

  1. Необходимость явного преобразования в float является либо ошибкой, либо очень раздражающей «функцией». Значение avgram было результатом арифметического выражения-почему переменная переходной задачи записывается в виде строки, которую необходимо снова перевести в плавающее значение? С возможной потерей точности тоже?
  2. Я обращаюсь map('extract') hostvars дважды-мне это не нравится, но я не знаю, как этого избежать-предложения приветствуются.
  3. Я до сих пор не понимаю, почему json_query не получалось. Приведенное ниже не приводило к каким-либо ошибкам, но spareserver оно было пустым.
 - set_fact:  spareserver: gt;-  {{ hostvars | json_query('[?ansible_memory_mb.real.total gt; `{{ avgram }}`]') }}  
  1. Тот, кто понизил мой вопрос из-за того, что я попросил Владимира найти лучшее решение, должен прекратить использовать StackOverflow.