
Дорогие читатели!
Добро пожаловать в увлекательное путешествие по миру автоматизации в Linux! Хочу предупредить вас, что формат этой статьи будет необычен — я решил представить материал в виде захватывающего рассказа.
Немного об авторе и его прошлом
В землях Linux, где каждый день приносит новые задачи и вызовы, я — ваш проводник в мире автоматизации. Меня зовут Александр Габидуллин, и я рад приветствовать вас в своём повествовании о приключениях трёх мушкетёров: Ansible, Bash и меня.
Про ansible и bash поговорим чуть дальше, а сейчас обо мне!
Я занимаю должность инженера в отделе архитектуры и интеграции в одном из больших вендоров отечественного ПО. До этого я начинал как обычный рыцарь в мире linux, и помогал windows администраторам сделать первые шаги на встречу к linux системам и автоматизировать их рутинный труд.
Я надеюсь, что мой опыт и знания будут полезны для вас и помогут в решении сложных задач.
Присоединяйтесь ко мне в этом путешествии, и давайте вместе отправимся навстречу новым открытиям и достижениям!
«На пути к переменам: проблема, которая стала отправной точкой»
Когда-то в далеком 2022 году, работая в государственном учреждении на должности инженер информационной безопасности, я получил письмо счастья, а точнее копию письма с указом президента РФ №250.
Так как я был безопасником, меня касалась малая часть работ по переводу защищенных систем на отечественное ПО и большей проблемой были закупки и финансирование. Однако коллеги из отдела эксплуатации техники и информационных систем попросили помощи, так как все администраторы были windows пользователями, и с отечественным Linux, им было очень тяжело, а потом к ним присоединились еще и администраторы отвечающие на студенческие рабочие места.
P.S. да-да, я начинал свои первые шаги с большого государственного университета.
После отрицания и гнева, как всем известно наступает этап принятия и я начал планировать импортозамещение во всей организации с технической стороны.

Необходимо было в кратчайшие сроки перевести более 1000 рабочих мест сотрудников и студентов на отечественное ПО и без ручного труда.
В поисках пути к автоматизации: первые шаги и вызовы

Изначально я не любил программирование, но любил скрипты на bash. И учитывая инфраструктуру с которой приходилось работать, когда АРМ может включаться и выключаться несколько раз за день, а переустановку с *Окон* на Linux производят в ручную администраторы, то было принято решение подготовить небольшой набор скриптов, которые запускались после накатывания ОС.
И казалось бы все встало на рельсы и должно работать?
Но увы, как всегда бывает в интерпрайзе, появились различные проблемы: отваливалась сеть, появились различные отделы с дополнительными требованиями, ну и не стоит забывать про железо и драйвера необходимы для его работы, а самое важно нужна была идемпотентность и разграничение прав.
Также появляются проблемы с запуском самих скриптов, администраторы не понимают как отладить ошибки при запуске, как его поправить на месте и постоянно дергают меня. Я в свою очередь каждый раз расширяю код и добавляю все больше проверок и условий. И тут мы переходим к моему первому проекту, который я реализовывал для локального использования.
От хаоса к порядку: первый проект «Помогатор»
Я понимая, что не могу постоянно бегать и помогать в запуске скриптов, начинаю создавать проект под название Помогатор. Он получает базовый графический интерфейс на zenity, я собираю его в удобный deb пакет и кладу его на внутренний сервер. Таким образов администратор в любой момент может установить мой пакет двойным кликом и введя свой пароль. А далее его встретит графический интерфейс и подскажет ему возможности и требования.
Под капотом пока остаются bash скрипты, но все переменные необходимые для выполнения уже запрашиваются в интерактивном режиме, и бывшие администраторы windows понимают, что он них хотят и в какой поле необходимо ввести.
Функционал начинает набирать обороты, и начинают добавляться различные кастомные сборки пакетов и их установка.

Скрытый текст
Исходники лежат в общем доступе, кто хочет изучить или возможно взять за основу милости прошу https://gitflic.ru/project/gabidullin-aleks/pomogator
Что я хотел решить данным проектом?
-
Автоматизация рутинных задач на месте;
Теперь я не хожу к каждому АРМ, а любой админ нажав пару кнопок в приложение способен настроить его под нужды конечного сотрудника.
-
Удобства установки кастомных сборок deb пакетов без флешки и подключения сетевых папок;
Мною был поднят сервер и туда выложены все deb пакеты, которые могли понадобиться сотруднику, и которых не было в репозитории или они были собраны в ручную. А моя утилита просто переходила по ссылке, скачивала нужный пакет и устанавливала автоматически и если требовался какой-либо pre/post инстальный сценарий, то он уже был прописан в скрипте под капотом.
Я могу постоянно дописывать функционал и обновлять пакет Помогатора, но тут скрывалась и проблема: а как мне обновить пакет, на уже установленных АРМ?
И я решая дописать в Помогатор проверку версии установленной уже в системе, и последнюю версию выложенную на сервере.
Делаю отдельную вкладку на nginx и по данному пути обновляю версию сборки, а локально установленный пакет перед каждым запуском обращаются по url и сверяет версию свою и на сервере. Если версия отличается, то появляется кнопка с требованием обновить пакет и запросом пароля администратора. И вроде все, проблемы решены, но остается одно НО и очень существенное: администратору все ровно необходимо идти и вводить пароль для установки обновленного пакета. И тут без систем автоматизации уже не обойтись.
«На пути к совершенству: развитие проекта и внедрение новых решений».
Начался поиск систем автоматизации, которые работают из коробки и не требуют большого погружения в стилистику написания. Получился всем известный список: Puppet, Chef, Salt и Ansible. Не хотелось использовать агентские службы, так как пришлось бы все ровно настраивать агента на всех АРМ.
Как видно из названия статьи, выбор пал на ansible.
Почему я выбрал именно его:
Понятный для меня формат yaml;
Нет агентских служб;
Можно запускать с использованием пароля от локальной УЗ с необходимыми права;
Идемпотентен ( при прямых руках и как оказалось не всегда они прямые);
Нет необходимости настройки отдельный мастер-нод.
Теперь имея выбранную систему необходимо было улучшить проект, но понимая, что я буду использовать другой подход и технологии, я решаю приступить к новому проекту, который будет уже open-source и будет направлен на помощь всем администраторам, занимающимся импортозамещением. Проект получает свое название AstraWizard и как можно понять из название связан он с ОС Astra Linux, но сейчас не об этом.
Скрытый текст
Код проекта можно посмотреть https://gitflic.ru/project/gabidullin-aleks/astrawizard

Я понимая, что проект будет помогать в различных задачах и на разных уровнях, начинаю использовать все best-practice, которые получил на первом проекте.
Для меня важно было сделать так, чтобы каждая кнопка была универсальная, и я не привязывался бы к ней.
Так я формирую базу для приложения:
#-------------------------------------Основные функции------------------------------------#
run_event() {
local command_to_run="$1"
eval "$command_to_run"
}
rend_menu() {
local choices=("$@")
selected_item_menu=$(zenity --list --title="Меню выбора" --column="Выберите" "${choices[@]}" --height=400 --width=500)
}
run_menu(){
local menu_items=("$@")
while true; do
rend_menu "${menu_items[@]}"
if [ $? -eq 0 ]; then
if [ -n "${event_menu["$selected_item_menu"]}" ]; then
run_event "${event_menu["$selected_item_menu"]}"
elif [ "$selected_item_menu" == "$exit_menu" ]; then
selected_item_menu=""
return
fi
else
exit 1
fi
done
}
run_app() {
pre-install
disclamer
wizard_info
wizard_version
make_inventory
run_menu "${items_menu_all[@]}"
}
#--------------------Запуск программы---------------------------
run_app
Таким образом я могу делать множество вложенных меню и просто придумывать имена для кнопок, которые будут отрисованы в zenity.
Теперь необходимо решить, а как я буду запускать написанные мною playbook'и по нажатию кнопки? Не самое лучшее, но точно удобное для меня решение получись таким:
#выполнить playbook ansible с доп. параметрами
playbook(){
(
ansible-playbook "$dir_playbook/preparation.yml" --user=$user_name --private-key=$dir_wizard/id_rsa --extra-vars "ansible_become_pass=$password_hosts" -i $choose_inventory_type --limit="$group_hosts"
#выполнить плейбук
ansible-playbook "$dir_playbook/$selected_item_menu.yml" --user=$user_name --private-key=$dir_wizard/id_rsa --extra-vars "ansible_become_pass=$password_hosts restart_system='$restart_system' path_shell_script='$path_shell_script' path_file_src='$path_file_src' path_file_dst='$path_file_dst' path_from='$path_from' path_to='$path_to' remove_packet='$remove_packet' install_packet='$install_packet' deb_packet_url='$deb_packet_url' deb_packet_localhost='$deb_packet_localhost' text='$text' check_packet='$check_packet' old='$old' new='$new' file_to_path='$file_to_path' command_shell='$command_shell' stop_system='$stop_system' start_system='$start_system' enable_system='$enable_system' disable_system='$disable_system' local_repo='$local_repo' list_packets_freeipa='$list_packets_freeipa' status_system='$status_system' choose_system='$choose_system' path_to_iso='$path_to_iso' install_freeipa_replica_cmd='$install_freeipa_replica_cmd' list_packets_freeipa_replica='$list_packets_freeipa_replica' name_dir_repo='$name_dir_repo' install_freeipa_server_cmd='$install_freeipa_server_cmd' install_freeipa_client_cmd='$install_freeipa_client_cmd' domain_msad='$domain_msad' ip_msad='$ip_msad' admin_msad='$admin_msad' password_for_msad='$password_for_msad' ip_dc_ipa='$ip_dc_ipa' search_name='$search_name' wallpaper='$wallpaper' usb_cmd='$usb_cmd' install_zabbix_agent='$install_zabbix_agent'" -i $choose_inventory_type --limit="$group_hosts" > "$dir_log"
exit_code=$?
# Проверка кода завершения и отображение соответствующего сообщения
if [ $exit_code -eq 0 ]; then
zenity --info --title="Успех" --text="Групповая политика успешно применилась.Журнал хранится в $dir_log" --height=100 --width=400
else
zenity --error --title="Ошибка" --text="Ошибка при применении политики.Журнал хранится в $dir_log" --height=100 --width=400
fi
) | zenity --progress --pulsate --auto-close --title="Применение политики" --text="Выполняется $selected_item_menu" --height=100 --width=300 --auto-kill
}
Объясняю: моя кнопка имеет русское название, допустим - Ввести клиента в домен Freeipa.
Так как я не хочу описывать каждую кнопку, то я использую тот же принцип, что и при создании меню. То есть у меня описано, что при выборе данной кнопки, запускается функция для сбора информации о будущем клиенте, а далее через --extra-vars передает данные значения в Playbook, который называется тоже на русском как и кнопка.
#Работа с freeipa
event_menu["$item_menu_gpo_freeipa_server"]="freeipa_server; check_vars_for_playbook; playbook &"
event_menu["$item_menu_gpo_freeipa_client"]="freeipa_client; check_vars_for_playbook; playbook &"
event_menu["$item_menu_gpo_freeipa_replica"]="freeipa_replica; check_vars_for_playbook; playbook &"
#ввод в домен freeipa
freeipa_client(){
#заполняем необходимые формы"
form_data=$(zenity --forms --title="Введите данные" --text="Введите данные:" \
--add-entry="Введите имя домена. Пример: domain.test" \
--add-entry="Введите ip адрес контроллера домена. Пример: 10.10.10.23" \
--add-password="Введите пароль администратора домена" --height=300 --width=400)
search_name=$(echo "$form_data" | awk -F '|' '{print $1}')
ip_dc_ipa=$(echo "$form_data" | awk -F '|' '{print $2}')
pass_ipa_admin=$(echo "$form_data" | awk -F '|' '{print $3}')
install_freeipa_client_cmd="astra-freeipa-client -d $search_name -p $pass_ipa_admin -y --par \"--hostname \"{{ inventory_hostname }}\".$search_name --force --enable-dns-updates\" "
}
Если выполнения playbook'а происходит без необходимости передачи значения для переменных, то можно выполнять его на прямую. Таким образом я могу добавлять либо сбор переменных и далее запуск одноименного с кнопкой playbook'а, либо запуск playbook'а сразу.
#установка удаленного помощника
event_menu["$item_menu_gpo_remote_desktop"]="check_vars_for_playbook; playbook &"
#Сменить репозитории#
event_menu["$item_menu_gpo_repo_stable"]="check_vars_for_playbook; playbook &"
event_menu["$item_menu_gpo_repo_1_7_6frozen"]="check_vars_for_playbook; playbook &"
event_menu["$item_menu_gpo_repo_1_7_7frozen"]="check_vars_for_playbook; playbook &"
event_menu["$item_menu_gpo_repo_1_8_1frozen"]="check_vars_for_playbook; playbook &"
event_menu["$item_menu_gpo_repo_1_8_2frozen"]="check_vars_for_playbook; playbook &"
Важной проблемой, которую я решаю до сих пор, является безопасность подключения с использованием пароля. Я использую при подключение ssh-ключи, однако если на АРМ еще не выполнялся ни один Play, и ключа ssh нет у нас и у конечного хоста в доверенных, то необходимо ими обменяться, а тут уже нужен пароль для подключения.
Возможно не красиво и не правильно, но это мой проект и я рад любым советам.
#парсил файл с хостами и передают туда открытый ключ
ssh_key_send(){
form_data=$(zenity --forms --title="Введите данные" --text="Введите данные:" \
--add-entry="Введите имя администратора для управляемого хоста" \
--add-password="Введите пароль администратора" \
--add-combo="Выберете список для работы с компьютерами" \
--combo-values="Статический|LDAP|Сетевой Сканер" )
# Разбиение строки с данными на отдельные переменные
user_name=$(echo "$form_data" | awk -F '|' '{print $1}')
password_hosts=$(echo "$form_data" | awk -F '|' '{print $2}')
type_inventory=$(echo "$form_data" | awk -F '|' '{print $3}')
if [ "$type_inventory" = "LDAP" ]; then
choose_inventory_type="$freeipa_inventory_host"
fi
if [ "$type_inventory" = "Сетевой Сканер" ]; then
choose_inventory_type="$network_inventory_host"
fi
if [ "$type_inventory" = "Статический" ]; then
choose_inventory_type="$inventory_host"
fi
##--new version---##
# Чтение строк из файла в массив lines
mapfile -t lines < "$choose_inventory_type"
# Создание пустого списка для хранения хостов
hosts=()
(
# Цикл по каждой строке
for line in "${lines[@]}"; do
# Проверка, если строка начинается с #
if [[ $line =~ ^\#.*$ ]]; then
continue # Пропускаем текущую итерацию цикла, если строка начинается с #
fi
if [[ $line =~ ^\[.*$ ]]; then
continue # Пропускаем текущую итерацию цикла, если строка начинается с [
fi
# Проверка, содержит ли строка "ansible_ssh_host="
if [[ $line == *ansible_ssh_host=* ]]; then
# Взять IP-адрес из строки
ip=$(echo "$line" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}')
else
# Использовать всю строку как имя хоста
ip=$line
fi
# Проверка, найден ли IP-адрес
if [[ -n $ip ]]; then
# Добавление хоста в список
hosts+=("$ip")
fi
done
# Вывод переменной hosts для проверки
# printf '%s\n' "${hosts[@]}"
# Проход по каждому хосту и выполнение необходимых операций
#ssh-keygen -R "$pc" если необходимо удалить хост
for pc in "${hosts[@]}"; do
if ! ssh-keygen -F "$pc" >/dev/null; then
sshpass -p "$password_hosts" ssh-copy-id -f -o "StrictHostKeyChecking no" -i $dir_wizard/id_rsa.pub $user_name@$pc
fi
done
# Проверка кода завершения и отображение соответствующего сообщения
) | zenity --progress --pulsate --auto-close --title="Подготовка управляемых ПК" --text="Передача ключей для управления компьютером" --height=100 --width=400 --auto-kill
set_hosts
}
Сейчас проект развивается только моими силами, и в свободное от моей основной работы время.
Есть много интересных задач, который я смог решить с помощью данного проекта, например:
Возможность формировать inventory файл на основе: Freeipa/ALDPro, динамически на основе сканирования включенных хостов, ну и статический заполненный в ручную;
Можно используя GUI выбирать группы, на которые необходимо применить ту или иную политику;
Есть возможность выводить всем активным пользователям сообщение на их экран, не зависимо заблокирован он или нет;
Ведение журналов по использованию каждой политики
и другие.
Завершение рассказа, но не нашего пути...

Подробнее о возможностях расскажу в следующих статьях, и возможно кто-то из Вас захочет поучаствовать в проекте или предложит свои идеи для добавления.
Комментарии (11)
MEGA_Nexus
28.06.2025 11:55Не совсем понимаю, какую задачу вы хотите решить с помощью AstraWizard.
- Всю автоматизацию на Linux делает Python.
- Чтобы не разбираться в Python был придуман высокоуровневый инструмент автоматизации Ansible.
- Чтобы не запоминать с какими параметрами запускать плейбуки Ansible был придуман Web интерфейс ansible awx и ansible semaphore.
Конкретно мы в компании используем Jenkins в качестве Web-интерфейса к Ansible. Админ, разработчик или тестировщик могут просто зайти в Jenkins и запустить нужный ранбук. Они просто жмут кнопку и далее происходит вся магия Ansible. Все креды и extra vars вшиты и о них думать не нужно. Если какие-то extra vars нужно заполнить, то jenkins предоставляет для этого красивую форму. В общем, очень удобная связка. По факту Ansible + Jenkins у нас делают то, что вы хотите сделать с помощью AstraWizard.
Настойчиво рекомендую вам познакомиться с ansible semaphore. Он скорее всего закроет все ваши потребности. Если нет, то смотрите тогда в сторону Ansible AWX или связки Ansible + Jenkins.
MikeyTide Автор
28.06.2025 11:55Добрый день, да все это известно и давно работает, но как давал ответ выше. Вы говорите о проде, вы говорите о людях с базовыми компетенциями ( написание своих плейбуков хотя бы, знание модулей и т.д.).
Я же даю уже готовый вариант собранный в деб пакет людям, кто не имеет возможности использовать более сложные инструменты.( Например: админ вузов, где я и работал и писал данный проект, админы школ и других гос. учреждений).
Чаще всего сотрудники там либо молодые и без опыта работы, либо работали всю жизнь с windows и боятся работать с Linux.И перед ними стоит выбор:
1. развернуть продукты, изучать их связки и работу;2. базово использовать мой продукт, у которого есть и видео уроки, и код открыт, также как я писал выше я могу оформить любую хотелку также в плейбук и добавить его в AstraWizard.(если данный функционал мне будет интересен и большинству пользователей продукта)
Из последнего, коллеги просили настроить удаленный помощник по паролю, чтобы администратор, мог попадать в сессию пользователя, но и чтобы это было безопасно, чтобы администратор не мог этого делать по своему желанию, так появилась последняя версия и доработка в виде установки удаленного помощника.
Я не говорю о конкуренции с гигантами, а лишь о проекте, который родился как локальный в 1 месте, а уже помогает в разных местах решать простые задачи начинающим администраторам.
cordarryl_juormer
28.06.2025 11:55Ansible, bash и я: три мушкетёра в мире автоматизации управления компьютерами на Linux
а торвальдс за дартаньяна
THEOILMAN
28.06.2025 11:55Изобрели maas и foreman, но для более приземленных целей получается... Неплохо, без сарказма) Сам часто о таком задумывался, но слишком тупой чтобы реализовать даже с помощью llm :D
MikeyTide Автор
28.06.2025 11:55Да, спасибо за понимание.
Все верно, просто помогал людям с которыми работал, а далее с добавлением ansible под капот, решил сделать публичным ПО.
Есть еще множество разработок, о которых собираюсь рассказать в ближайших статьях.
Возможно комьюнити поможет советами, или в комментариях напишут свои *хотелки*, а я реализую.
Мне опыт, людям польза
THEOILMAN
28.06.2025 11:55По опыту работы с астрой вот что заметил - люди которые всю жизнь (20+лет) админили Винду почему-то совсем не могут в x11vnc. Сто раз приходится объяснять как подключиться к текущей сессии пользователя удаленно и прочие гадости творить. Так же без графики не в состоянии по ssh с помощью smbclient забирать файлы с ФС на клиентский пк, например. Уж больно много там всяких ключей, кавычек и экранов для них...
Хотя вижу, что всё впринципе охвачено в этом велосипеде. Даже не знаю... Автоматизация это конечно здорово, главное чтобы со скоростью работы не увеличивалось количество задач =D
MikeyTide Автор
28.06.2025 11:55Приветствую, как раз про x11vnc я и рассказал в комментариях выше.
Я в последней версии добавил его автоматическую установку на клиентские машины с помощью ansible.
Далее у пользователя появляется на рабочем столе ярлык - удаленный помощник.
Когда пользователь его запускает, то у него поднимается сервер vnc, а на экране появляется пароль из 6 цифр и имя пк + ip адрес, чтобы он смог их продиктовать администратору при запросе.Далее пользователь говорит админу данные цифры, и админ с помощью любой утилиты, которая поддерживает протокол vnc подключается используя имя пк или ip и пароль, который диктует пользователь с экрана.
По поводу копирования файлов, в моем AstraWizard также есть возможность как положить так и стянуть с удаленного хоста файл, или несколько файлов.
То есть вы выбираете данную функцию, и если хотите передать, то вас попросит выбрать 1 или несколько файлов. А при получение с удаленного хоста, попросит указать путь до файла и куда его положить на вашем пк.Все уже есть! Исходный код, а также все мои ролики можно найти на гите в проекте.
P.S.
Ссылки на плейлисты, где я рассказываю что умеет AstraWizard, и конечно же показываю
pnmv
В своё время, ещё на заре двухтысячных, не осилив написание чего-то там на bash, ибо громоздко выходило и было не понятно, как всё это поддерживать, взялся за серьезное изучение perl. На нём вышло более презентабельно, и, кажется, более компактно.
MikeyTide Автор
Согласен, bash был в начале проекта, далее хотелось перевести на python в силу его простоты (для меня), и использовать pyqt5 вместо графики через zenity.
Но это займет время, а хотелось бы развивать проект в плане функционала, что я и делаю последнее время на заказ. То есть пишут пользователи с просьбой помочь с той или иной функцией, и далее она появляется в приложении.
Благодаря Habr'у, если пойму что спрос больше чем мне казалось, то может займусь наведением красоты и правильности в коде!
pnmv
Bash - неплохая отправная точка, в плане понимания, чего же мы всё-таки хотим от нашего проекта.
Смещение в сторону питона тоже понятно - всё-таки, не язык для однострочников, да еще и всякие юпитеры при нём, что тоже удобно. Зоопарк из библиотек, правда, может слегка дезориентировать.
MikeyTide Автор
Питон проще поддерживать, тем более если когда-то появятся помощники.
С библиотеками все в рамках разумного думаю. Ну и красивая графика поможет пользователям использовать все это в школах, вузах и т.д.
Где системные администраторы либо начинающие, или уже заканчивающие свой путь ( без обид, скорее всего это реальная статистика).
И весь этот софт писался именно как помощник им, а не в прод для больших компаний, где используется уже terraform/opentofu, ansible, salt и т.д.
В продолжение данной статьи расскажу именно о своих плейбуках и исследованиях в ОС. Возможно мои костыли, помогут решить кому-то свои собственные задачи