#!/bin/bash set -euo pipefail ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" source "${ZARYA_DIR}/lib/common.sh" COMMAND="${1:-help}" parse_run_targets() { local raw_input="$*" local normalized normalized=$(echo "${raw_input}" | tr ',' ' ') local targets=() for item in ${normalized}; do if [[ "${item}" =~ ^([0-9]+)-([0-9]+)$ ]]; then local start="${BASH_REMATCH[1]}" local end="${BASH_REMATCH[2]}" for ((i=10#$start; i<=10#$end; i++)); do targets+=($(printf "%02d" "${i}")) done elif [[ "${item}" =~ ^[0-9]+$ ]]; then targets+=($(printf "%02d" "$((10#$item))")) else log_err "Некорректный идентификатор плейбука: '${item}'" exit 1 fi done printf "%s\n" "${targets[@]}" | sort -u -n } resolve_playbook() { local id="$1" local found found=$(find "${REPO_ROOT}/ansible/playbooks" -maxdepth 1 -name "${id}_*.yml" | head -n1) if [[ -z "${found}" ]]; then log_err "Плейбук с префиксом [${id}] не найден в ansible/playbooks/" exit 1 fi echo "${found}" } print_playbooks_catalog() { echo -e "${BLUE}=== Каталог доступных плейбуков (ansible/playbooks/) ===${NC}" printf "%-4s %-28s %-12s %s\n" "ID" "PLAYBOOK" "HOSTS" "DESCRIPTION" echo "----------------------------------------------------------------------------------" for pb in $(ls -1 "${REPO_ROOT}/ansible/playbooks"/[0-9][0-9]_*.yml 2>/dev/null | sort); do local file_name file_name=$(basename "${pb}") local id="${file_name:0:2}" local hosts hosts=$(awk '/hosts:/ {print $2; exit}' "${pb}" | tr -d '"'"'") local desc desc=$(awk '/- name:/ {print substr($0, index($0,$3)); exit}' "${pb}") printf "%-4s %-28s %-12s %s\n" "${id}" "${file_name%.yml}" "${hosts}" "${desc}" done } case "${COMMAND}" in git-credential) if [[ -f "${RAM_CACHE}" ]]; then token=$(grep '^export ATLAS_PUSH_TOKEN=' "${RAM_CACHE}" 2>/dev/null | cut -d= -f2- | tr -d '"'\'' ' || true) if [[ -n "${token}" ]]; then echo "username=atlas" echo "password=${token}" fi fi exit 0 ;; start|login) shift || true hours="${1:-1}" if ! [[ "${hours}" =~ ^[0-9]+$ ]] || (( hours < 0 || hours > 24 )); then log_err "Недопустимый TTL сессии: '${hours}'. Допустимо: 0 (бессрочно) или 1-24 (часы)." exit 1 fi ensure_prerequisites load_secrets_to_ram "${hours}" unseal_vault if [[ "${hours}" -eq 0 ]]; then log_ok "Рабочая сессия Sovereign C2 открыта (Бессрочно)." else log_ok "Рабочая сессия Sovereign C2 открыта (TTL: ${hours} ч)." fi ;; clean|logout) rm -f "${RAM_CACHE}" /dev/shm/.atlas_core log_ok "Секреты и SSH-ключи безопасно удалены из RAM." ;; unseal) ensure_prerequisites unseal_vault ;; up) shift || true target="${1:-all}" case "${target}" in host) run_isolated "${ZARYA_DIR}/layers/00_host.sh" ;; net) run_isolated "${ZARYA_DIR}/layers/01_net.sh" ;; tier0) run_isolated "${ZARYA_DIR}/layers/02_tier0.sh" ;; talos) run_isolated "${ZARYA_DIR}/layers/03_talos.sh" ;; apps) "${ZARYA_DIR}/layers/04_apps.sh" ;; all) run_isolated "${ZARYA_DIR}/layers/00_host.sh" run_isolated "${ZARYA_DIR}/layers/01_net.sh" run_isolated "${ZARYA_DIR}/layers/02_tier0.sh" run_isolated "${ZARYA_DIR}/layers/03_talos.sh" "${ZARYA_DIR}/layers/04_apps.sh" log_ok "Вся инфраструктура полностью развернута." ;; *) log_err "Неизвестный слой: ${target}. Доступны: host, net, tier0, talos, apps, all" exit 1 ;; esac ;; run) shift || true if [[ $# -eq 0 ]] || [[ "${1:-}" == "list" ]]; then print_playbooks_catalog exit 0 fi targets=$(parse_run_targets "$*") log_info "Очередь выполнения плейбуков: $(echo ${targets} | tr '\n' ' ')" for id in ${targets}; do pb_path=$(resolve_playbook "${id}") log_info "==> [RUN ${id}] Исполнение: $(basename "${pb_path}")..." run_isolated ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${pb_path}" done log_ok "Все выбранные плейбуки успешно выполнены." ;; exec) shift || true if [[ $# -eq 0 ]]; then log_err "Использование: dep exec <команда> [аргументы...]" exit 1 fi run_isolated "$@" ;; a|apply) unseal_vault shift || true run_isolated bash -c "cd '${REPO_ROOT}/tofu' && tofu apply $*" ;; plan) shift || true run_isolated bash -c "cd '${REPO_ROOT}/tofu' && tofu plan $*" ;; tf) shift || true run_isolated bash -c "cd '${REPO_ROOT}/tofu' && tofu $*" ;; pods) shift || true kpods "$@" ;; sync) log_info "Принудительная конвергенция FluxCD..." flux reconcile source git atlas-repo flux reconcile kustomization infra-sync flux reconcile kustomization apps-sync log_ok "Синхронизация завершена." ;; gc) "${ZARYA_DIR}/layers/gc.sh" ;; state) shift || true target="${1:-all}" if [[ "${target}" == "--snapshot" ]]; then shift || true "${ZARYA_DIR}/state/collect_state.sh" "$@" else case "${target}" in host|pve) bash "${ZARYA_DIR}/state/01_pve.sh" ;; net|vyos) bash "${ZARYA_DIR}/state/03_vyos.sh" ;; vps|edge) bash "${ZARYA_DIR}/state/02_vps.sh" ;; tier0) bash "${ZARYA_DIR}/state/04_tier0.sh" ;; k8s|talos) bash "${ZARYA_DIR}/state/05_k8s.sh" ;; workstation) bash "${ZARYA_DIR}/state/00_workstation.sh" ;; all) for mod in 00_workstation 01_pve 02_vps 03_vyos 04_tier0 05_k8s; do bash "${ZARYA_DIR}/state/${mod}.sh" done ;; *) log_err "Неизвестный таргет: ${target}. Доступны: host, net, vps, tier0, k8s, workstation, all" exit 1 ;; esac fi ;; reset|nuke) "${ZARYA_DIR}/layers/reset.sh" ;; help|--help|-h) cat < Точечный запуск плейбуков: 06 | 01-03 | 01,03,06 dep run list Каталог всех плейбуков с описанием dep exec <команда...> Вызов любого бинарника строго внутри RAM-изоляции run_isolated Инфраструктура (IaC): dep a [-auto-approve] OpenTofu apply с авто-ансилом Vault dep plan OpenTofu plan dep tf Прямой вызов OpenTofu в изолированном контексте Кластер и состояние: dep pods [args...] Просмотр подов через kpods (включая kpods -w) dep sync Принудительный синк FluxCD dep gc Сборка мусора и сброс бэкоффа подов dep state [target] Живой вывод статуса в терминал (host, net, vps, tier0, k8s, all) dep reset Полное уничтожение инфраструктуры (MFA через YubiKey) EOF ;; *) log_err "Неизвестная команда: ${COMMAND}. Используйте 'dep help' для справки." exit 1 ;; esac