MyTetra Share
Делитесь знаниями!
Как собрать нестандартный факт с нескольких хостов в одну переменную?
Время создания: 29.05.2023 08:39
Текстовые метки: ansible, факт, fact, set_fact, нестандартный, одна, переменная, собрать, накопить, хост, несколько, фильтр
Раздел: Компьютер - Linux - Оркестрация - Ansible
Запись: xintrea/mytetra_syncro/master/base/1685338765ntf19n6lnz/text.html на raw.github.com

Имеется следующая задача:



Необходимо создать такой плейбук, который получит версию нестандартного Linux-дистрибутива из специализированного файла на каждом хосте. Чтобы узнать версию дистрибутива, в bash можно давать команду cat /etc/dist_version.

Плейбук должен проверить, совпадают ли версии на всех хостах. Если на всех хостах версии одинаковые, плейбук должен успешно завершиться. Если хоть одна версия не совпадает, плейбук должен завершиться ошибкой (через модуль fail).



Другими словами, заранее проверяемая версия на хостах неизвестна. То есть, нельзя просто написать сравнение с заранее заданным значением. Надо собрать все значения со всех хостов, и потом проверить, чтобы все версии на хостах совпадали. Как это сделать?


В качестве решения можно предложить следующий код:



# Здесь для каждого хоста сохраняется вывод в переменную os_version

- hosts: test_hosts

tasks:

- name: "get OS version"

command: "cat /etc/redhat-release"

register: os_version


- debug:

var: os_version


# Здесь заводится пустой словарь и в цикле в него добавляются значения

- hosts: localhost

vars:

os_versions: {}

tasks:

- name: "OS version in one dict"

set_fact:

os_versions: "{{ hostvars[item]['os_version']['stdout'] | append_to_dict(os_versions, item) }}"

with_items: "{{ groups['test_hosts'] }}"


- debug:

var: os_versions



В этом коде надо обратить внимание, что есть переменная os_version (без "s" на конце), в которую попадает версия ОС. Значения этой переменной для каждого хоста хранится в hostvars[item]['os_version'] после выполнения первого блока.


А так же во втором блоке есть переменная os_versions (с "s" на конце), которая является словарем ИмяХоста -> Версия ОС. Эта переменная заполняется в цикле, организованным через with_items.


Вывод будет выглядеть примерно так:



ok: [localhost] => {

"os_versions": {

"test01": "Red Hat Enterprise Linux release 8.2 (Ootpa)",

"test02": "Red Hat Enterprise Linux release 8.2 (Ootpa)",

"test03": "Red Hat Enterprise Linux release 8.2 (Ootpa)"

}

}



Для работы вышеуказанного кода потребуется самописный фильтр. Для это в каталоге с плейбуками необходимо создать подкаталог /filter_plugins, в котором разместить файл core.py следующего содержания:



def append_to_dict(_val, _dict, _hostname):

_dict[_hostname] = _val

return _dict


class FilterModule(object):

def filters(self):

return {

'append_to_dict': append_to_dict

}



Вызов функции фильтра происходит следующим образом. В качестве первого аргумента _val устанавливается значение, стоящее слева от вертикальной черты "|" в Jinja-выражении. То есть, в обычной трактовке, первый аргумент - это фильтруемый объект. В данном случае передается hostvars[item]['os_version']['stdout']. Однако это значение передается как фильтруемый объект только для того, чтобы передать в функцию фильтра в качестве первого аргумента значение версии операционной системы для перебираемого хоста.


В качестве последующих аргументов передаются значения, указанные в скобках после имени фильтра в Jinja-выражении. То есть, в качестве _dict буден передан словарь os_versions, в качестве _hostname будет передан item (то есть, имя перебираемого хоста).



Примечение: те же самые действия можно сделать даже не создавая самописный фильтр. Достаточно воспользоваться стандартным фильтром combine:



- name: "OS version in one dict"

set_fact:

os_versions: "{{ os_versions | combine( { item: hostvars[item]['os_version']['stdout']} ) }}"

with_items: "{{ groups['test_hosts'] }}"



Фильр combine складывает два словаря, возвращая один общий словарь.



Далее уже несложно сделать еще один фильтр is_equal_value_in_dict, который обработает os_versions и если обнаружит, что в этом словаре все значения версии ОС совпадают, вернет True, или в противном случае False. Это значение можно использовать в модуле fail, вот так:



- name: Проверка соответствия версий ОС

fail:

msg: Некоторые версии ОС не совпадают с другими

when: "{{ os_versions|is_equal_value_in_dict }}"



Кстати, проверить что словарь содержит только одинаковые значения, можно стандартными методами и фильтрами, без написания самодельных.


Так же в этом разделе:
 
MyTetra Share v.0.65
Яндекс индекс цитирования