Что такое ALD Pro и зачем его едят можно почитать в других статья на Хабре:
А я расскажу о своем пути в установке данного комплекса, а также какие проблемы были у меня, чтобы их не было у Вас:)
Ну и конечно же, как и любая моя статья, эта также будет связана со скриптами, автоматизацией и удобствами для конечного пользователя.
Глава 1: Зачем нужна автоматизация для установки ALD Pro?

ALD Pro — это мощное решение для управления доменами и аутентификации в инфраструктуре Astra Linux. Однако его установка и настройка — это многоэтапный процесс, требующий выполнения множества команд в терминале, редактирования конфигурационных файлов и перезагрузки системы. Вручную это не только отнимает много времени, но и чревато ошибками, особенно для администраторов, которые не часто сталкиваются с подобными задачами.
Типичные проблемы ручной установки:
-
Сложность: Необходимость точного ввода команд, настройки сети, DNS, репозиториев и других параметров.
-
Время: Процесс может занять несколько часов, особенно если требуется обновление системы или повторение шагов из-за ошибок.
-
Человеческий фактор: Опечатки, пропущенные шаги или неверные параметры могут привести к неработоспособности системы.
-
Документация: Официальные инструкции часто объемны и требуют адаптации под конкретную инфраструктуру.
Почему автоматизация?
Автоматизация установки ALD Pro решает эти проблемы, предоставляя следующие преимущества:
-
Скорость: Скрипт выполняет все шаги за считанные минуты, минимизируя время простоя.
-
Точность: Исключаются ошибки, связанные с ручным вводом. Каждый шаг проверяется, а параметры валидируются.
-
Удобство: Администратору не нужно запоминать последовательность действий — достаточно запустить скрипт и следовать подсказкам.
-
Масштабируемость: Один и тот же скрипт можно использовать для развертывания ALD Pro на множестве серверов, обеспечивая идентичную конфигурацию.
-
Поддержка разных сценариев: Возможность выбора версии ALD Pro, настройки глобального каталога или модуля синхронизации через интерактивный интерфейс.
Эволюция инструментов
Изначально я использовал bash-скрипты с zenity для создания простого графического интерфейса. Это работало, но имело ограничения:
-
Сложность поддержки: добавление новых функций усложняло код.
-
Ограниченный UI: zenity предоставляет базовые диалоговые окна, но не подходит для сложных сценариев.
-
Нет возможности удаленного управления.
Переход на Python и Flask позволил:
-
Создать полноценный веб-интерфейс с интуитивной навигацией.
-
Реализовать прогресс-бар, логирование и обработку ошибок.
-
Обеспечить доступ к установке с любого устройства в сети.
-
Легко расширять функционал (например, добавление поддержки новых версий ALD Pro).
Автоматизация установки ALD Pro — это не просто удобство, а необходимость для современных ИТ-инфраструктур. Она экономит время, снижает риски ошибок и позволяет сосредоточиться на более важных задачах. Дальше я расскажу, как прошел путь от простых bash-скриптов до веб-интерфейса на Flask, и какие подводные камни встретил на этом пути.
Глава 2: Bash + Zenity — Первая версия автоматизации
1. Почему начали с Bash?
-
Простота: Bash — это стандартный инструмент администрирования Linux, не требующий дополнительных зависимостей.
-
Скорость разработки: для простых задач не нужны сложные языки.
-
Доступность: все команды установки ALD Pro уже выполнялись вручную, оставалось лишь объединить их в скрипт.
2. Структура bash-скрипта
Разберём ключевые части скрипта:
2.1. Проверки перед установкой
internet_error="У вас проблемы с доступом к сайту dl.astralinux.ru. Проверьте настройку интернет соединения и правильность dns." if ping -c 1 dl.astralinux.ru &> /dev/null; then echo "Доступ к репозиторию есть" else zenity --info --text="$internet_error" exit 1 fi
-
Проверка Интернет-соединения перед началом установки.
-
Использование
zenityдля вывода ошибок в GUI.
2.2. Работа с администратором системы и правами sudo
if id -nG | grep -qw "astra-admin"; then echo ok else zenity --info --text="Пользователь не принадлежит группе astra-admin. Необходимо зайди под пользователем с правами администратора." exit 1 fi
passwd=$(zenity --forms --title="Пароль для администратора" \ --text="Введите пароль администратора" \ --add-password="Пароль") echo "$passwd" | sudo -Sv >/dev/null 2>&1 if [ $? -ne 0 ]; then #остальной код else zenity --info --text="Неправильный пароль от sudo. Перезапустите скрипт." exit 1 fi
-
Интерактивный ввод пароля через
zenity. -
Проверка корректности перед выполнением привилегированных команд.
2.3. Динамические параметры установки
form_data=$(zenity --forms --title="Введите данные" --text="Введите данные:" \ --add-entry="Введите имя контроллера домена имя типа: dc" \ --add-entry="Введите имя домена типа: domain.test" \ --add-entry="Введите имя полное доменное имя типа: dc.domain.test" \ --add-entry="Введите статический ip-address вашего будущего домена типа: 10.10.10.10" \ --add-entry="Введите маску подсети вашего будущего домена типа: 255.255.255.0" \ --add-entry="Введите gateway сети вашего будущего домена типа: 10.10.10.1" \ --add-entry="Введите ваш dns для доступа в интернет: 10.10.10.9" \ --add-password="Придумайте пароль для администратора домена:" \ --add-combo="Версия ALDPro" \ --combo-values="2.2.1|2.3.0|2.4.0" ) # Разбиение строки с данными на отдельные переменные small_fqdn=$(echo "$form_data" | awk -F '|' '{print $1}') big_fqdn=$(echo "$form_data" | awk -F '|' '{print $2}') fqdn=$(echo "$form_data" | awk -F '|' '{print $3}') ipaddres=$(echo "$form_data" | awk -F '|' '{print $4}') mask=$(echo "$form_data" | awk -F '|' '{print $5}') gateway=$(echo "$form_data" | awk -F '|' '{print $6}') dns=$(echo "$form_data" | awk -F '|' '{print $7}') passwd_dom=$(echo "$form_data" | awk -F '|' '{print $8}') version_aldpro=$(echo "$form_data" | awk -F '|' '{print $9}')
-
Графический ввод параметров (FQDN, IP, пароль и т.д.).
-
Демонстрация примеров заполнения, для удобства пользователя.
2.4. Настройка сети и репозиториев
if [ "$version_aldpro" == 2.3.0 ]; then #репы 2.3.0 и 1.7.5 echo $passwd | sudo -S bash -c "echo -e 'deb https://download.astralinux.ru/aldpro/frozen/01/2.3.0 1.7_x86-64 main base' > /etc/apt/sources.list.d/aldpro.list" echo $passwd | sudo -S bash -c "echo -e 'deb https://dl.astralinux.ru/astra/frozen/1.7_x86-64/1.7.5/uu/1/repository-base/ 1.7_x86-64 main contrib non-free' > /etc/apt/sources.list" echo $passwd | sudo -S bash -c "echo -e 'deb http://download.astralinux.ru/astra/frozen/1.7_x86-64/1.7.5/repository-extended 1.7_x86-64 main contrib non-free' >> /etc/apt/sources.list" elif [ "$version_aldpro" == 2.4.0 ]; then #репы 2.4.0 и 1.7.6 echo $passwd | sudo -S bash -c "echo -e 'deb https://dl.astralinux.ru/aldpro/frozen/01/2.4.0/ 1.7_x86-64 main base' > /etc/apt/sources.list.d/aldpro.list" echo $passwd | sudo -S bash -c "echo -e 'deb https://dl.astralinux.ru/astra/frozen/1.7_x86-64/1.7.6/repository-base 1.7_x86-64 main contrib non-free' > /etc/apt/sources.list" echo $passwd | sudo -S bash -c "echo -e 'deb https://dl.astralinux.ru/astra/frozen/1.7_x86-64/1.7.6/repository-update 1.7_x86-64 main contrib non-free' >> /etc/apt/sources.list" else #репы 2.2.1 и 1.7.4 echo $passwd | sudo -S bash -c "echo -e 'deb https://download.astralinux.ru/aldpro/frozen/01/2.2.1 1.7_x86-64 main base' > /etc/apt/sources.list.d/aldpro.list" echo $passwd | sudo -S bash -c "echo -e 'deb http://dl.astralinux.ru/astra/frozen/1.7_x86-64/1.7.4/repository-extended 1.7_x86-64 main contrib non-free' > /etc/apt/sources.list" echo $passwd | sudo -S bash -c "echo -e 'deb http://dl.astralinux.ru/astra/frozen/1.7_x86-64/1.7.4/repository-base 1.7_x86-64 main non-free contrib' >> /etc/apt/sources.list" fi echo $passwd | sudo -S bash -c "echo -e 'search $big_fqdn' > /etc/resolv.conf" echo $passwd | sudo -S bash -c "echo -e 'nameserver 127.0.0.1' >> /etc/resolv.conf"
-
Замена DNS для работы ALD Pro.
-
Добавление репозитория в зависимости от выбранной версии.
2.5. Запуск установки ALD Pro
echo $passwd | sudo -S aldpro-server-install -d "$big_fqdn" -n "$small_fqdn" -p "$passwd_dom" --ip "$ipaddres" --no-reboot --setup_syncer --setup_gc
-
Автоматический вызов официального инсталлятора с нужными параметрами.
3. Плюсы и минусы решения
✅ Плюсы:
-
Минимальные зависимости (
bash,zenity,sudo). -
Быстрая разработка для базового сценария.
-
Подходит для разовых установок.
❌ Минусы:
-
Сложность поддержки: при добавлении новых функций код становится запутанным.
-
Ограниченный UI: Zenity не поддерживает прогресс-бар в реальном времени или сложные формы.
-
Нет обработки ошибок: если что-то пошло не так, скрипт может «зависнуть» без понятного лога.
Глава 3: Переход на Python + Flask — Современный веб-интерфейс
1. Почему Bash перестал устраивать?
-
Масштабируемость: добавление новых функций (например, выбор версии ALD Pro) усложняло код.
-
Удобство: администраторы хотели удалённо запускать установку, а не подключаться к серверу через SSH.
-
Интерактивность: нужен был прогресс-бар, логирование и возможность перезапуска прерванной установки.
2. Архитектура Flask-приложения
Рассмотрим ключевые компоненты:
2.1. REST API для управления установкой
@app.route('/installation_progress') def get_progress(): if installation_progress.get('is_complete') and installation_progress.get('access_info'): return jsonify({ 'status': 'complete', 'access_info': installation_progress['access_info'], 'progress': installation_progress }) return jsonify(installation_progress) def start_installation(config_data): try: # New Step 0: Configure ALDPro repository ...
-
Запуск установки в отдельном потоке, чтобы не блокировать веб-интерфейс.
2.2. Прогресс в реальном времени
@app.route('/submit', methods=['POST']) # Reset progress and SAVE CONFIG DATA global installation_progress installation_progress = { 'current_step': 0, 'total_steps': 9, 'steps': [ {'name': 'Настройка репозитория ALD Pro и имени хоста', 'status': 'pending', 'start_time': None, 'end_time': None}, {'name': 'Настройка сети и файла hosts', 'status': 'pending', 'start_time': None, 'end_time': None}, {'name': 'Обновление системы', 'status': 'pending', 'start_time': None, 'end_time': None}, {'name': 'Установка компонентов ALD Pro', 'status': 'pending', 'start_time': None, 'end_time': None}, {'name': 'Установка ALD Pro', 'status': 'pending', 'start_time': None, 'end_time': None}, {'name': 'Отключение DNSSEC', 'status': 'pending', 'start_time': None, 'end_time': None}, {'name': 'Перезапуск служб', 'status': 'pending', 'start_time': None, 'end_time': None}, {'name': 'Очистка', 'status': 'pending', 'start_time': None, 'end_time': None}, ], 'start_time': None, 'end_time': None, 'is_complete': False, 'error': None, 'config_data': config_data # Сохраняем конфигурацию для возможного повтора } threading.Thread(target=start_installation, args=(config_data,)).start() return render_template('progress.html', reboot_info=REBOOT_INFO)
-
Frontend (
progress.html) опрашивает этот endpoint и обновляет прогресс.
2.3. Основной процесс установки
@app.route('/installation_progress') def get_progress(): if installation_progress.get('is_complete') and installation_progress.get('access_info'): return jsonify({ 'status': 'complete', 'access_info': installation_progress['access_info'], 'progress': installation_progress }) return jsonify(installation_progress) def start_installation(config_data): try: # New Step 0: Configure ALDPro repository update_progress(0, 'in_progress') time.sleep(1) version = config_data['version_aldpro'] repo_content = "" if version == "2.5.0": repo_content = "deb https://dl.astralinux.ru/aldpro/frozen/01/2.5.0/ 1.7_x86-64 main base" elif version == "2.4.1": repo_content = "deb https://dl.astralinux.ru/aldpro/frozen/01/2.4.1/ 1.7_x86-64 main base" elif version == "2.4.0": repo_content = "deb https://dl.astralinux.ru/aldpro/frozen/01/2.4.0/ 1.7_x86-64 main base" elif version == "2.3.0": repo_content = "deb https://dl.astralinux.ru/aldpro/frozen/01/2.3.0 1.7_x86-64 main base" elif version == "local": repo_content = config_data['local_repo_path'] else: raise Exception(f"Неизвестная версия ALDPro: {version}") # Write repository file with open("/etc/apt/sources.list.d/aldpro.list", "w") as f: f.write(repo_content + "\n") # Меняем имя хоста fqdn = config_data.get('fqdn', '') if fqdn: cmd = f"hostnamectl set-hostname {fqdn}" success, output = run_command(cmd) if not success: raise Exception(f"Ошибка смены имени хоста: {output}") update_progress(0, 'completed') time.sleep(1) # Step 1: Network config update_progress(1, 'in_progress') time.sleep(1) # Определяем активный сетевой интерфейс get_active_iface_cmd = "ip route | grep default | awk '{print $5}' | head -n 1" success, output = run_command(get_active_iface_cmd) if not success or not output.strip(): raise Exception("Не удалось определить активный сетевой интерфейс") active_interface = output.strip() # Проверяем, активен ли NetworkManager nm_active = False check_nm_cmd = "systemctl is-active NetworkManager" success, output = run_command(check_nm_cmd) if success and output.strip() == "active": nm_active = True commands = [] # Если NetworkManager активен, добавляем команды для его отключения if nm_active: commands.extend([ "systemctl stop NetworkManager", "systemctl disable NetworkManager", "systemctl mask NetworkManager", # Ждем немного, чтобы служба точно остановилась "sleep 2" ]) # Настраиваем статический IP в /etc/network/interfaces interfaces_content = f"""# This file describes the network interfaces available on your system source /etc/network/interfaces.d/* # The loopback network interface auto lo iface lo inet loopback auto {active_interface} iface {active_interface} inet static address {config_data['ipaddres']} netmask {config_data['mask']} gateway {config_data['gateway']} source /etc/network/interfaces.d/*.cfg""" # Добавляем остальные команды настройки сети commands.extend([ f"echo '{interfaces_content}' > /etc/network/interfaces", f"sed -i 's/dns-nameservers {config_data.get('dns', '')}/dns-nameservers 127.0.0.1/g' /etc/network/interfaces", f"echo -e 'search {config_data.get('big_fqdn', '')}' > /etc/resolv.conf", f"echo -e 'nameserver {config_data.get('dns', '')}' >> /etc/resolv.conf", # Очистка старых записей localhost "sed -i '/^127\\.0\\.1\\.1/d' /etc/hosts", # Добавление новых записей f"echo '{config_data['ipaddres']} {config_data['fqdn']} {config_data['small_fqdn']}' >> /etc/hosts", # Перезапускаем сеть для применения изменений "systemctl restart networking.service", # Ждем применения настроек сети "sleep 5" ]) for cmd in commands: success, output = run_command(cmd) if not success: # Для systemctl mask ошибка может быть ожидаемой, если служба уже замаскирована if not (nm_active and "mask" in cmd and "is already masked" in output): raise Exception(f"Ошибка настройки сети: {output}") time.sleep(0.5) update_progress(1, 'completed') time.sleep(1) # и остальные шаги
-
Каждый этап фиксируется в объекте
installation_progress. -
При ошибке можно перезапустить конкретный шаг.
2.4. Валидация данных
<div class="form-group"> <label for="passwd_dom">Пароль администратора домена: <span class="help-icon">? <span class="tooltip">Пароль должен содержать: минимум 8 символов, заглавные и строчные буквы, цифры</span> </span> </label> <input type="password" id="passwd_dom" name="passwd_dom" value="{{ config.passwd_dom }}" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}" title="Пароль должен содержать минимум 8 символов, включая заглавные и строчные буквы, и цифры" required oninput="validatePassword()"> <div class="password-requirements"> <div class="requirement"> <span id="length-icon" class="requirement-icon">❌</span> <span>Минимум 8 символов</span> </div> <div class="requirement"> <span id="uppercase-icon" class="requirement-icon">❌</span> <span>Хотя бы одна заглавная буква</span> </div> <div class="requirement"> <span id="lowercase-icon" class="requirement-icon">❌</span> <span>Хотя бы одна строчная буква</span> </div> <div class="requirement"> <span id="number-icon" class="requirement-icon">❌</span> <span>Хотя бы одна цифра</span> </div> </div> </div>
-
Проверка паролей перед запуском.
3. Преимущества перед Bash
✅ Гибкость:
-
Можно добавлять новые функции без переписывания всей логики.
-
Поддержка разных версий ALD Pro через конфигурацию.
✅ Удобство:
-
Веб-интерфейс доступен с любого устройства в сети.
-
Прогресс-бар, логи и возможность повтора неудачного шага.
✅ Надёжность:
-
Обработка ошибок на каждом этапе.
-
Возможность перезапуска прерванной установки.
4. Итог
Переход на Python + Flask превратил простой скрипт в полноценный инструмент администрирования, который:
-
экономит время,
-
уменьшает количество ошибок,
-
даёт больше контроля над процессом.
5. Новый интерфейс
Источники
Если вы дочитали до конца, то исходники можно посмотреть:
GitFlick — исходники кода, и собранные deb-пакеты;
YouTube — видео по работе web-версии установщика;
RuTube — видео на отечественной площадке по работе web-версии установщика;
ссылка на оригинал статьи https://habr.com/ru/articles/930698/
Добавить комментарий