
ansible-cmdb — Структуризация и визуализация ansible facts
Приветствую!
ansible-cmdb — программа на Python, которая структуризирует собранные Ansible facts и визуализирует их с помощью HTML с красивым форматированием.
Ansible facts — это данные о серверах (хостах Ansible), которые собираются с помощью модуля setup. Они представляют собой «факты» о системе, например данные об ОС, сетевых интерфейсах, блочных устройствах и других компонентах системы.
С помощью ansible-cmdb
также можно экспортировать структуризированные данные в файлы следующих форматов: json, csv, sql, txt_table. Такие файлы удобно использовать для анализа, хранения или дальнейшей обработки. Но это тема для отдельной статьи😉.
В этой заметке я расскажу📋:
- Как установить и использовать
ansible-cmdb
для генерацииHTML
; - Как добавить кастомные факты;
- Как использовать
HTML
файл в качестве отдельной страницы по сабурлу в Nginx; - Как автоматизировать обновление базы фактов.
Подписывайтесь на наш телеграм @r4ven_me📱, чтобы не пропустить новые публикации на сайте😉. А если есть вопросы или желание пообщаться по тематике — заглядывайте в Вороний чат @r4ven_me_chat🧐. |
Предполагается, что вы знаете, что такое Ansible и умеете им пользоваться🙄. Если нет, то рекомендую к прочтению мои статьи:
- Ansible – система управления конфигурациями: знакомство
- Пишем ansible playbook для начальной настройки Linux сервера
Все примеры из статьи выполнялись в среде дистрибутива Linux Mint Debian Edition 6🍃 (Debian 12). Во всех остальных дистрибутивах процесс выглядит +- аналогично.
Установка ansible-cmdb
Первым делом переходим в рабочую директорию Ansible, где у вас находятся файл инвентаризации и конфигурации (у меня это ~/ansible
):
cd ~/ansible/
Как уже говорил ранее, ansible-cmdb
, как и сам Ansible, написан на языке программирования Python🐍. Поэтому рекомендуется создать виртуальное окружение venv
📦 и уже внутри него выполнять установку ansible-cmdb
:
Способ #1 ‐ venv, если у вас версия Python ниже 3.12
Выполняем в терминале:
mkdir -p ./cmdb/venv
python3 -m venv ./cmdb/venv/ansible-cmdb
./cmdb/venv/ansible-cmdb/bin/pip install ansible-cmdb
Способ #2 — docker, если у вас версия Python 3.12 и выше
К сожалению ansible-cmdb давненько не обновлялся, а в Python 3.12 библиотека imp
стала deprecated. В таком случае для запуска ansible-cmdb
необходимо установить более раннюю версию Python.
Универсальным способом сделать это является Docker:
mkdir -p ./cmdb/venv
docker run -u $(id -u):$(id -g) -v ./cmdb:/cmdb python:3.11-alpine python -m venv /cmdb/venv/ansible-cmdb
docker run -u $(id -u):$(id -g) -v ./cmdb:/cmdb python:3.11-alpine /cmdb/venv/ansible-cmdb/bin/pip install ansible-cmdb
В конце установки должно быть подобное сообщение:
Installing collected packages: ushlex, jsonxs, pyyaml, MarkupSafe, mako, ansible-cmdb
Successfully installed MarkupSafe-3.0.2 ansible-cmdb-1.31 jsonxs-0.6 mako-1.3.10 pyyaml-6.0.2 ushlex-0.99.1
Чтобы в будущем каждый раз не активировать venv
(или не заходить в docker) для работы с ansible-cmdb
создадим небольшой скрипт.
Если устанавливали через venv
(Способ #1):
cat << EOF > "${PWD}"/cmdb/ansible_cmdb.sh
#!/bin/bash
"${PWD}/cmdb/venv/ansible-cmdb/bin/python" "${PWD}/cmdb/venv/ansible-cmdb/lib/ansiblecmdb/ansible-cmdb.py" "\$@"
EOF
Если устанавливали в Docker (Способ #2):
cat << EOF > "${PWD}"/cmdb/ansible_cmdb.sh
#!/bin/bash
docker run -v "${PWD}/cmdb":"/cmdb" python:3.11-alpine /cmdb/venv/ansible-cmdb/bin/python /cmdb/venv/ansible-cmdb/lib/ansiblecmdb/ansible-cmdb.py "\$@"
EOF
Сделаем его исполняемым и добавим символьную ссылку на него в директории ~/.local/bin
для удобства:
chmod +x ./cmdb/ansible_cmdb.sh
ln -s "${PWD}"/cmdb/ansible_cmdb.sh ~/.local/bin/ansible-cmdb
☝️Для корректной работы директория
~/.local/bin
должна быть в списке переменной окружения$PATH
.
Проверяем:
ansible-cmdb --help
Usage: ansible-cmdb.py [option] <dir> > output.html
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-t TEMPLATE, --template=TEMPLATE
Template to use. Default is 'html_fancy'
-i INVENTORY, --inventory=INVENTORY
Inventory to read extra info from
-f, --fact-cache <dir> contains fact-cache files
-p PARAMS, --params=PARAMS
Params to send to template
-d, --debug Show debug output
-q, --quiet Don't report warnings
-c COLUMNS, --columns=COLUMNS
Show only given columns
-C CUST_COLS, --cust-cols=CUST_COLS
Path to a custom columns definition file
-l LIMIT, --limit=LIMIT
Limit hosts to pattern
--exclude-cols=EXCLUDE_COLUMNS
Exclude cols from output
Пример работы ansible-cmdb
Создаем директорию для базовых фактов и запускаем их сбор с помощью ansible
и модуля setup
:
mkdir -p ./cmdb/facts/basic
ansible -m setup --tree ./cmdb/facts/basic all &> /dev/null
Теперь с помощью ansible-cmdb
генерируем HTML
файл на основе собранных данных:
ansible-cmdb -p collapsed=1 ./cmdb/facts/basic > ./cmdb/cmdb.html
💡Параметр (
-p
)collapsed=1
будет отображать данные о хостах в свернутом виде.
Теперь просто открываем полученный файл в браузере:


Аккуратно и удобно. На странице есть интерактивные элементы: поиск, фильтрация и пр. Очень удобно😏.
Для генерации json | csv | sql | txt_table | markdown
команда будет примерно такой:
ansible-cmdb -t csv ./cmdb/facts/basic > ./cmdb/cmdb.csv
"Name","OS","IP","Arch","Mem","MemFree","MemUsed","CPUs","Virt","Disk avail"
"host1","Debian 12.7","10.1.1.10","x86_64/x86_64","8g","0g","1g","4","kvm/guest","8.3g, 0.2g"
"host2","Debian 12.10","0.1.1.11","x86_64/x86_64","8g","2g","2g",6","kvm/guest","7.8g, 0.3g"
"host3","Debian 12.8","0.1.1.12","x86_64/x86_64","8g","0g","3g","4","kvm/guest","1.9g"
"host4","Debian 12.6","0.1.1.13","x86_64/x86_64","8g","0g","1g","8","kvm/guest","8.7g, 0.2g"
"host5","Debian 12.7","0.1.1.14","x86_64/x86_64","8g","0g","1g","2","kvm/guest","9.0g, 0.2g"
"host6","Debian 12.6","0.1.1.15","x86_64/x86_64","8g","0g","1g","2","kvm/guest","0.8g, 3.7g, 3.7g, 0.4g"
Стоит предупредить, что полный список фактов доступен только в шаблоне JSON. Остальные форматы имеют ограниченное количество полей, опеределенных в шаблонах, которые расположены по пути: ./cmdb/venv/ansible-cmdb/lib/ansiblecmdb/data/tpl
. При необходимости их можно кастомизировать под себя.
Добавление кастомных фактов
ansible-cmdb
предоставляет гибкие возможности по кастомизации итогового файла👨🎨.
Покажу на примере добавления своего факта в виде списка маршрутов хоста, который Ansible по умолчанию не собирает🤷♂️.
⚠️Факты Ansible должны быть представлены в формате JSON.
Моя реализация выполнена с помощью скрипта на Bash, который в выводе дает список маршрутов хоста в JSON
формате📃.
Приступим👨🏭. Создаем файл скрипта:
nvim ./cmdb/routes_to_json.sh
Наполняем его таким содержимым:
#!/bin/bash
# Получаем маршруты в массив
mapfile -t routes < <(ip r)
# Начало JSON
RESULT='{"custom_facts": {"IP Routes": ['
# Добавляем маршруты
for i in "${!routes[@]}"; do
# Экранируем спецсимволы
line="${routes[$i]//\\/\\\\}"
line="${line//\"/\\\"}"
# Добавляем маршрут как отдельный объект
RESULT+="{\"#$((i+1))\": \"$line\"}"
# Добавляем запятую между элементами (кроме последнего)
[ $i -lt $((${#routes[@]} - 1)) ] && RESULT+=","
done
# Завершаем JSON
RESULT+=']}}'
# Выводим результат
echo "$RESULT"
Делаем исполняемым:
chmod +x ./cmdb/routes_to_json.sh
Проверяем:
./cmdb/routes_to_json.sh | python3 -m json.tool
Вывод должен быть примерно таким:
{
"custom_facts": {
"IP Routes": [
{
"#1": "default dev vpn0 proto static scope link metric 50 "
},
{
"#2": "default via 10.10.10.1 dev eth0 proto dhcp src 10.10.10.30 metric 600 "
},
{
"#3": "10.11.11.0/24 dev vpn0 proto kernel scope link src 10.11.11.15 metric 50 "
}
]
}
}
Теперь создаем новый плейбук, который будет собирать наш кастомный факт (запуск скрипта выше на удалённых хостах и сбор вывода в локальные файлы):
nvim ./cmdb/get_custom_facts.yml
Наполняем:
---
- name: Get custom facts
hosts: all
gather_facts: false
tasks:
- name: Run script to get info about ip routes
script: "~/ansible/cmdb/routes_to_json.sh"
register: script_output
- name: Create local output files with ip routes info
local_action: copy content="{{ script_output.stdout }}" dest="~/ansible/cmdb/facts/custom/{{ inventory_hostname }}"
☝️Не забудьте скорректировать пути до вашей рабочей директории Ansible.
Теперь создаем отдельную директорию под кастомные факты, собираем их с помощью ansible-playbook
и генерируем обновленный HTML
с помощью ansible-cmdb
:
mkdir -p ./cmdb/facts/custom
ansible-playbook ./cmdb/get_custom_facts.yml
ansible-cmdb -p collapsed=1 ./cmdb/facts/{basic,custom} > ./cmdb/cmdb.html
В итоговом HTML
появится новый раздел «Custom facts». Как по мне выглядит неплохо😌:

ansible-cmdb
позволяет настраивать свои столбцы в HTML
и много чего еще. Рекомендую подробнее изучить документацию📚 (ссылки в конце статьи).
Доступ к cmdb.html по урлу в Nginx
Если вам необходимо предоставлять данную информацию кому-то еще, то можно добавить итоговый HTML в виде отдельной страницы на вашем веб сервере, например Nginx🌐.
Если веб сервер работает от ограниченного в правах пользователя, проще всего будет создать хардлинк на ваш файл в корне сайта Nginx (условно корень /var/www/html
:
sudo ln "${PWD}"/cmdb/cmdb.html /var/www/html/
А в конфиге Nginx, добавьте, например, такой location
:
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.html index.htm;
location / {
try_files $uri $uri.html $uri/ =404;
}
}
Как то так:

Автоматизация сбора/обновления фактов
Без автоматизации в мире администрирования никуда🙂↔️. Напишем скрипт сбора/обновления фактов и настроим его ежедневный запуск в 01:00
по таймеру systemd в пространстве нашего пользователя (--user
).
Создаем файл скрипта:
nvim ./cmdb/update_cmdb.sh
Наполняем:
#!/usr/bin/env bash
set -Eeuo pipefail
export PATH="$PATH:$HOME/.local/bin"
WORK_DIR="$HOME/ansible/"
echo "Script started"
cd "$WORK_DIR"
echo "Get basic facts"
ansible -m setup --tree ./cmdb/facts/basic all &> /dev/null || true
echo "Get custom facts"
ansible-playbook ./cmdb/get_custom_facts.yml &> /dev/null || true
echo "Generate cmdb html file"
ansible-cmdb -p collapsed=1 ./cmdb/facts/{basic,custom} > ./cmdb/cmdb.html
echo "Script done"
echo "--------------------------------------"
☝️Не забудьте указать свой
WORK_DIR
.
Сохраняем, делаем файл исполняемым, создаем линк в директорию ~/.local/bin
для удобства и проверяем:
chmod +x ./cmdb/update_cmdb.sh
ln -s "${PWD}"/cmdb/update_cmdb.sh ~/.local/bin/update-cmdb
update-cmdb
# время изменения
stat -c '%y' ./cmdb/cmdb.html
Далее создаем systemd юнит сервиса:
systemctl --user edit --full --force update-cmdb.service
Наполняем:
[Unit]
Description=Update ansible cmdb
[Service]
WorkingDirectory=%h/ansible
ExecStart=%h/.local/bin/update-cmdb
☝️Также не забывает указать свой
WorkingDirectory
.
Теперь создаем юнит таймера:
systemctl --user edit --full --force update-cmdb.timer
Наполняем:
[Unit]
Description=Update ansible cmdb daily at 01:00
[Timer]
OnCalendar=*-*-* 01:00:00
Persistent=true
[Install]
WantedBy=timers.target
Активируем таймер:
systemctl --user enable --now update-cmdb.timer
Проверяем:
systemctl --user status update-cmdb.timer
systemctl --user status update-cmdb.service
journalctl --user -fu update-cmdb
💡Для принудительно запуска задания выполните:
systemctl --user start update-cmdb.service
Теперь наш HTML
файл будет всегда содержать актуальные данные по хостам Ansible👍.