Ansible: Сбор произвольной информации на хостах с помощью Ansible custom facts. Вывод информации в формате *.json.

На чем было опробовано:

  1. Ansible 2.9.18
  2. Hyper-V на Windows 10 Pro.
  3. Сервер Ansible: CentOS Linux release 7.9.2009 (Core).
  4. Node 1: CentOS Linux release 7.9.2009 (Core).
  5. Node 2: CentOS Linux release 7.9.2009 (Core).
  6. Node 3: CentOS Linux release 7.9.2009 (Core).
  7. Node 4: CentOS Linux release 7.9.2009 (Core).

1. Задача.

К примеру, нам требуется с помощью внедрения custom facts для Ansible организовать сбор версий контейнеров, запущенных на серверах, а так же сбор версий некоторого программного обеспечения на серверах, которое имеет файл с указанием версии в своём каталоге /ecp/po/version.txt.

Собранная информация должна формироваться в json-формат.

Дополнительно требуется рассмотреть средства визуализации информации в удобном виде (opensource web-приложения).

2. Решение задачи.

Решение будет состоять из нескольких этапов:

  • загрузка и выполнение скрипта на узлах с целью получить json файлы;
  • выгрузка файлов json с узлов;
  • склеивание узловых файлов json в один сводный файл;
  • просмотр сводного файла.

В системе Ansible есть возможность собирать системную информацию, которая собирается в виде фактов с помощью встроенного модуля setup.

Со сбором стандартных переменных по умолчанию всё предельно ясно, но что делать, если мы хотим сформировать наши собственные переменные на всех хостах, чтобы в дальнейшем использовать их в нашем коде?

Для этого существует возможность добавления Custom facts, что делается следующим образом:

  • на любом хосте, контролируемом Ansible, создаётся каталог /etc/ansible/facts.d;
  • внутри каталога размещаются один либо несколько файлов с расширением *.fact, например custom.fact;
  • файлы возвращают данные в формате json.

Создаем инвентарь test-servers.inventory на 4 тестовых сервера:

# mcedit /ansible/test-servers.inventory

С таким содержимым:

[test_servers]
server1   ansible_ssh_host=192.168.0.39 ansible_ssh_user=root
server2   ansible_ssh_host=192.168.0.30 ansible_ssh_user=root
server3   ansible_ssh_host=192.168.0.31 ansible_ssh_user=root
emachines ansible_ssh_host=192.168.0.12 ansible_ssh_user=root

Создаем специальный custom.fact файл для загрузки на узлы, который, по сути, является скриптом для выполнения некоторого комплекса действий на удалённом узле.

По замыслу будут собираться некоторые переменные и заворачиваться в разметку json.

#!/bin/bash

file_po="/etc/po/version.txt"
host_name=$(hostname)
ecp_ver=$(awk -F: '/rel_ver/{print $2}' $file_po)
docker_info=$(docker ps --format ' {{json .Names}}: {{json .Image}}, ' | paste -sd'\n' | sed '$ s/.$//')
jp="/$host_name.json"

echo "{" > $jp
echo "\"Информация об узлах\": {" >> $jp
echo "\"$host_name\": {" >> $jp
if test -f "$file_po"; then
    echo "\"Софт\": {" >> $jp
    echo "\"Версия чего-то\": \"$ecp_ver\"" >> $jp
    echo "}" >> $jp
    echo "," >> $jp
fi
echo "\"Докеры на узле\": {" >> $jp
echo "$docker_info" >> $jp
echo "}" >> $jp
echo "}" >> $jp
echo "}" >> $jp
echo "}" >> $jp

Создаём специальный playbook custom-facts-fetch.yml, содержащий сценарий /ansible/files/custom.fact для узла, возвращающий некоторый файл json на Ansible master сервер с каждого узла:

---
- name: "Cбор Ansible custom facts"
  hosts: all

  tasks:
  - name: "Удаление предыдущей версии Ansible custom facts файлов на узле"
    file:
      state: "absent"
      path: "/etc/ansible/facts.d/"

  - name: "Создание Ansible custom fact каталога"
    file:
      path: "/etc/ansible/facts.d"
      state: "directory"
      mode: 0766

  - name: "Загрузка на узлы Ansible custom fact файлов"
    copy:
      src: "/ansible/files/custom.fact"
      dest: "/etc/ansible/facts.d/custom.fact"
      mode: +x

  - name: "Объявление служебной переменной для Ansible custom fact"
    debug: "var=ansible_local"
    notify:
    - reload facts

  - name: "Перезагрузка facts"
    setup: "filter=ansible_local"

  - name: "Подготовка списка файлов *.json для выгрузки с узла"
    find:
      paths: "/"
      recurse: "no"
      patterns: "*.json"
    register: "files_to_copy"

  - name: "Выгрузка файлов *.json с узла на Ansible master сервер"
    fetch:
      src: "{{ item.path }}"
      dest: "/ansible/json"
    with_items: "{{ files_to_copy.files }}"

Напишем скрипт custom-facts-fetch-PLAY.sh для запуска playbook на целевом inventory:

#!/bin/bash.

ansible-playbook /ansible/custom-facts-fetch.yml -i /ansible/test-servers.inventory

Сделаем файл скрипта исполняемым:

# chmod +x custom-facts-fetch-PLAY.sh

И запустим его.

Ответ:

После успешной отработки playbook на сервере Ansible master появится каталог /ansible/json с подкаталогами ‘имя_узла‘:

В каждом из которых будет находиться json файл вида имя_узла.json:

Содержимое json файла первого узла emachines:

Содержимое json файла второго узла server1:

Содержимое json файла третьего узла server2:

Содержимое json файла четвертого узла server3:

Получилось несколько файлов json, по файлу с каждого целевого узла.

Сколько узлов мы задействовали для Ansible custom facts, столько и json файлов и будет.

В первом файле emachines.hamsterden.loc.json не имеется фрагмент с названием «Версия чего-то‘, по втором файле cos7client1.hamsterden.loc.json такой фрагмент имеется, а так как в custom.fact реализована проверка на фактическое наличия файла /ecp/po/version.txt.

К примеру, наличие файла /ecp/po/version.txt бывает только у серверов типа «web-server». Так как скрипт «сам учитывает» тип сервера, то можно смело применять custom.fact на все целевые серверы и файл json всегда будет генерироваться корректно для каждого типа серверов.

Для создание сводного json файла по всем файлам со всех узлам, воспользуемся утилитой jq.

Ссылка на официальный сайт утилиты: https://stedolan.github.io/jq/.

Установка утилиты:

# yum install jq -y

План работ с файлами:

file1.json + file3.json + file3.json + file4.json = final_result_po.json

Создадим make-final-json-file.sh скрипт:

# mcedit /ansible/make-final-json-file.sh
#!/bin/bash

#создание каталогов для обработки файлов
mkdir -p /ansible/json/temp
mkdir -p /ansible/json-ready

#каталог куда Ansible кладет скачанные json файлы с узлов
ja="/ansible/json"

#временный каталог куда Ansible складывает все json файлы из всех каталогов узлов перед сведением информации в единый файл json
jrt="/ansible/json/temp"

#каталог куда Ansible помещает сводный json файл со всей добытой информацией по узлам
jr="/ansible/json-ready"

#обработка файлов и удаление временных промежуточных результатов
cp -i $(find /$ja -iname "*.json") $jrt
cd $jrt
jq -s '.[0] * .[1] * .[2] * .[3]' *.json > "$jrt"/temp.json
cat "$jrt"/temp.json | sed 's/{}/\"нет докеров\"/' > "$jr"/final_result_po.json

#удаление временных каталогов и файлов
rm -rf $jrt
rm -rf $ja

Сделаем файл скрипта исполняемым:

# chmod +x /ansible/make-final-json-file.sh

Результатом работы скрипта будет сводный json файл всех четырёх final_result_po.json в каталоге /ansible/json_ready на Ansible master сервере:

Текстовый файл:

{
  "Информация об узлах": {
    "cos7client1.hamsterden.loc": {
      "Софт": {
        "Версия чего-то": "9.11.2"
      },
      "Докеры на узле": {
        "wordpress-compose_nginx_1": "nginx:latest",
        "wordpress-compose_wordpress_1": "wordpress:php7.4-fpm-alpine",
        "wordpress-compose_pma_1": "phpmyadmin/phpmyadmin",
        "wordpress-compose_mysql_1": "mariadb"
      }
    },
    "cos7client2.hamsterden.loc": {
      "Софт": {
        "Версия чего-то": "10.2.1"
      },
      "Докеры на узле": "нет докеров"
    },
    "cos7client3.hamsterden.loc": {
      "Софт": {
        "Версия чего-то": "9.3.4"
      },
      "Докеры на узле": "нет докеров"
    },
    "emachines.hamsterden.loc": {
      "Докеры на узле": {
        "onlyoffice": "onlyoffice/documentserver",
        "funny_heisenberg": "onlyoffice/documentserver"
      }
    }
  }
}

Если открыть final_result_po.json файл в браузере Mozilla Firefox, то информация будет корректно визуализирована в удобно читаемом виде:

Задача выполнена!

X. Оригиналы источников информации.

  1. golinuxcloud.com «Working with Ansible facts | Create custom facts with examples».
  2. github.com «Ansible local fact example».
  3. medium.com «Custom facts for Ansible».
  4. otus.ru «Ansible: формируем переменные на всех хостах с Custom facts».
  5. mydailytutorials.com «Working with Ansible facts – retrieving facts».
  6. adyxax.org «Ansible custom factsAnsible custom facts».
  7. Источник: https://hamsterden.ru/ansible-collecting-arbitrary-information-on-all-hosts-with-custom-facts/

Was this helpful?

1 / 0