LINUX.ORG.RU
решено ФорумAdmin

Как собрать нестандартные факты со всех хостов в одну переменную?

 , накопительная, , факт


0

1

Мне нужно сделать очень необычную вещь.

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

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

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

Результат высчитывается так:

host1 - v.1.25
host2 - v.1.25
host3 - v.1.25
True

host1 - v.1.29
host2 - v.1.29
host3 - v.1.29
True

host1 - v.1.29
host2 - v.1.25
host3 - v.1.29
False

host1 - v.1.25
host2 - v.1.29
host3 - v.1.25
False

Таким образом, надо каким-то макаром собрать нестандартный факт со всех хостов в одну переменную-список, ну а потом ее проверить, чтобы все элементы были одинаковыми.

Я не могу сообразить, как это можно сделать в Ansible?

★★★★★

А если сделать иначе? Вначале собрать список версий с уникальными значениями, а затем уже, если больше одного значения, предпринимать какие-то действия. По сути, если версия везде одна и та же, список уникальных значений будет состоять из одного элемента. Если больше - тогда уже смотрим, что делать дальше.

P.S. В исходном сообщении не было требования выдать список хостов, на которых версии отличаются.

Rizado
()
Ответ на: комментарий от ya-betmen

Я не пойму, как создать переменную, которая будет заполнена в одном блоке задач, и использована в другом блоке задач. Ну, то есть:

---

- hosts: host1
  gather_facts: false
  vars:
    firstVersion: ""

  tasks:

  - name: Заполнение переменной firstVersion
    ...

- hosts: allClusterHosts
  gather_facts: false

  tasks:

  - name: Тут переменная firstVersion от host1 недоступна
    ...

Xintrea ★★★★★
() автор топика
Последнее исправление: Xintrea (всего исправлений: 1)
Ответ на: комментарий от Xintrea

ну в целом можно через register сохранять вывод в переменную для нужных хостов, а потом на локалхосте в цикле собрать значения в один словарь/список

---
# тут для каждого хоста сохраняем вывод в переменную 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

Примерный вывод:

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)"
    }
}

дальше уже приделывать логику для сравнения, можно кастомным фильтром

append_to_dict тоже кастомный, может можно стандартным набором обойтись, но сходу не придумал:

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
        }

CaHbl4
()
Последнее исправление: CaHbl4 (всего исправлений: 1)
Ответ на: комментарий от CaHbl4

Не понимаю, как должен работать фильтр.

Его использование, согласно вашему коду, выглядит так:

append_to_dict(os_versions, item)

где item - перебираемое имя хоста.

А прототип у данного фильтра такой:
def append_to_dict(_val, _dict, _hostname):
    _dict[_hostname] = _val
    return _dict

И вот непонятно, как происходит вызов?

  • _val - это os_versions
  • _hostname - это item


А значение _dict, которое в середине, как попадает в функцию фильтра?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea
  • _val - первый аргумент - это то, что приходит через пайп, т.е. в примере это hostvars[item]['os_version']['stdout']
  • _dict - os_versions - словарь, в который добавляется значение (и ему же присваивается новое значение, типа a = func(a))
  • _hostname - item - хост
CaHbl4
()
Ответ на: комментарий от CaHbl4

Походу, более простым способом будет воспользоваться стандартным фильтром 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'] }}"

И никаких самописных фильтров не надо городить, а результат будет тот же.

Xintrea ★★★★★
() автор топика