Add mass agent deployment script with SSH key/password auth and apt fallback
This commit is contained in:
@@ -0,0 +1,117 @@
|
|||||||
|
# Массовый деплой InfoUser Agent
|
||||||
|
|
||||||
|
Скрипт `deploy-agent.sh` устанавливает или обновляет агент `info-user-agent` на списке Linux-хостов по SSH.
|
||||||
|
|
||||||
|
## Принцип работы
|
||||||
|
|
||||||
|
1. Пытается подключиться по ключу `id_rsa`.
|
||||||
|
2. Если ключ не подходит — подключается по паролю и копирует публичный ключ в `~/.ssh/authorized_keys` (последующие запуски будут по ключу).
|
||||||
|
3. Устанавливает/обновляет агент:
|
||||||
|
- Сначала `apt-get install info-user-agent` из подключённого apt-репозитория.
|
||||||
|
- Если apt не сработал — fallback через `dpkg -i` из `.deb` в корне проекта.
|
||||||
|
4. Пишет `config.json` с адресом сервера и токеном.
|
||||||
|
5. Запускает systemd-таймер и триггерит первый heartbeat.
|
||||||
|
6. Раскладывает результат в `deploy-ok.txt` / `deploy-deferred.txt` и логи в `logs/`.
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
На машине, с которой запускается скрипт:
|
||||||
|
|
||||||
|
- `bash`
|
||||||
|
- `ssh`, `scp`
|
||||||
|
- `sshpass`
|
||||||
|
- `ping`
|
||||||
|
|
||||||
|
На целевых хостах:
|
||||||
|
|
||||||
|
- Доступен SSH-сервер.
|
||||||
|
- Пользователь входит в `sudo` (без пароля на сам sudo запросы идут с паролем).
|
||||||
|
- Подключён apt-репозиторий с пакетом `info-user-agent` (для основного пути установки).
|
||||||
|
|
||||||
|
## Подготовка
|
||||||
|
|
||||||
|
### 1. SSH-ключ
|
||||||
|
|
||||||
|
Положите приватный ключ рядом со скриптом:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp /path/to/id_rsa ./id_rsa
|
||||||
|
chmod 600 ./id_rsa
|
||||||
|
```
|
||||||
|
|
||||||
|
Публичный ключ `./id_rsa.pub` будет сгенерирован автоматически при первом запуске.
|
||||||
|
|
||||||
|
### 2. Список хостов
|
||||||
|
|
||||||
|
Создайте `ip.txt` (один хост на строку):
|
||||||
|
|
||||||
|
```text
|
||||||
|
user@192.168.255.50
|
||||||
|
user@192.168.255.16
|
||||||
|
192.168.255.71
|
||||||
|
# это комментарий
|
||||||
|
```
|
||||||
|
|
||||||
|
Если пользователь не указан, используется `user`.
|
||||||
|
|
||||||
|
### 3. Параметры подключения
|
||||||
|
|
||||||
|
По умолчанию:
|
||||||
|
|
||||||
|
- SSH-порт: `22`
|
||||||
|
- SSH/Sudo-пароль: `1q2w3e$R`
|
||||||
|
- Пользователь по умолчанию: `user`
|
||||||
|
- Адрес сервера: `http://192.168.255.180:3000`
|
||||||
|
- Токен агента: `a916c8cd656b3f40acc2920820abf88e`
|
||||||
|
|
||||||
|
Переопределить можно через переменные окружения:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export SSH_PASS='MyS3cr3t$'
|
||||||
|
export SERVER_URL='http://monitor.example.com:3000'
|
||||||
|
export AGENT_TOKEN='my-token'
|
||||||
|
export SSH_PORT=2222
|
||||||
|
export DEFAULT_USER='admin'
|
||||||
|
./deploy-agent.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/user/moder/info-user/deploy
|
||||||
|
./deploy-agent.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Результат
|
||||||
|
|
||||||
|
После завершения рядом со скриптом появятся:
|
||||||
|
|
||||||
|
- `deploy-ok.txt` — хосты, на которых всё прошло успешно.
|
||||||
|
- `deploy-deferred.txt` — хосты, которые надо доразворачивать (нет пинга, нет SSH, ошибка установки).
|
||||||
|
- `logs/` — подробные логи по каждому хосту.
|
||||||
|
- `ip.txt.bak.YYYYMMDD_HHMMSS` — бэкап списка хостов.
|
||||||
|
|
||||||
|
Если в `deploy-deferred.txt` что-то есть, исправьте проблему и запустите скрипт снова — он переберёт весь список заново.
|
||||||
|
|
||||||
|
## Установка отдельного хоста вручную
|
||||||
|
|
||||||
|
Если хост не попадает под массовый деплой:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# На хосте
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y info-user-agent
|
||||||
|
sudo info-user-agent-setup
|
||||||
|
# или отредактируйте /opt/info-user-agent/config.json вручную
|
||||||
|
sudo systemctl start info-user-agent.timer
|
||||||
|
sudo systemctl start info-user-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- **"SSH недоступен (ключ и пароль)"** — хост пингуется, но не принимает ни ключ, ни пароль. Проверьте пользователя/пароль, настройки SSH (`PermitRootLogin` / `PasswordAuthentication`).
|
||||||
|
- **"Ошибка установки"** — apt-репозиторий недоступен и fallback `.deb` не найден. Положите актуальный `.deb` в корень проекта (`info-user-agent_*.deb`).
|
||||||
|
- **sshpass не найден** — установите:
|
||||||
|
```bash
|
||||||
|
sudo apt-get install -y sshpass
|
||||||
|
```
|
||||||
Executable
+389
@@ -0,0 +1,389 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# deploy-agent.sh — массовая установка/обновление InfoUser Agent.
|
||||||
|
#
|
||||||
|
# Использование:
|
||||||
|
# cd /home/user/moder/info-user/deploy
|
||||||
|
# ./deploy-agent.sh
|
||||||
|
#
|
||||||
|
# Перед запуском:
|
||||||
|
# 1. Положить id_rsa в ./id_rsa
|
||||||
|
# 2. Создать ./ip.txt со списком хостов (user@IP или просто IP)
|
||||||
|
# 3. При необходимости изменить SERVER_URL/AGENT_TOKEN ниже или через env
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
|
||||||
|
HOSTS_FILE="${SCRIPT_DIR}/ip.txt"
|
||||||
|
KEY_FILE="${SCRIPT_DIR}/id_rsa"
|
||||||
|
PUB_FILE="${SCRIPT_DIR}/id_rsa.pub"
|
||||||
|
|
||||||
|
OK_FILE="${SCRIPT_DIR}/deploy-ok.txt"
|
||||||
|
DEFER_FILE="${SCRIPT_DIR}/deploy-deferred.txt"
|
||||||
|
LOG_DIR="${SCRIPT_DIR}/logs"
|
||||||
|
|
||||||
|
PKG_NAME="info-user-agent"
|
||||||
|
AGENT_CONFIG_DIR="/opt/info-user-agent"
|
||||||
|
AGENT_CONFIG_FILE="${AGENT_CONFIG_DIR}/config.json"
|
||||||
|
|
||||||
|
SERVER_URL="${SERVER_URL:-http://192.168.255.180:3000}"
|
||||||
|
AGENT_TOKEN="${AGENT_TOKEN:-a916c8cd656b3f40acc2920820abf88e}"
|
||||||
|
SSH_PASS="${SSH_PASS:-1q2w3e\$R}"
|
||||||
|
SSH_PORT="${SSH_PORT:-22}"
|
||||||
|
DEFAULT_USER="${DEFAULT_USER:-user}"
|
||||||
|
MAX_RETRIES="${MAX_RETRIES:-3}"
|
||||||
|
RETRY_SLEEP="${RETRY_SLEEP:-3}"
|
||||||
|
|
||||||
|
# Цвета
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
SSH_KEY_OPTS=(
|
||||||
|
-o BatchMode=yes
|
||||||
|
-o StrictHostKeyChecking=accept-new
|
||||||
|
-o ConnectTimeout=6
|
||||||
|
-o ConnectionAttempts=1
|
||||||
|
-o ServerAliveInterval=5
|
||||||
|
-o ServerAliveCountMax=1
|
||||||
|
-o PasswordAuthentication=no
|
||||||
|
-p "$SSH_PORT"
|
||||||
|
)
|
||||||
|
|
||||||
|
SSH_PASS_OPTS=(
|
||||||
|
-o StrictHostKeyChecking=accept-new
|
||||||
|
-o ConnectTimeout=6
|
||||||
|
-o ConnectionAttempts=1
|
||||||
|
-o ServerAliveInterval=5
|
||||||
|
-o ServerAliveCountMax=1
|
||||||
|
-p "$SSH_PORT"
|
||||||
|
)
|
||||||
|
|
||||||
|
SCP_KEY_OPTS=(
|
||||||
|
-i "$KEY_FILE"
|
||||||
|
-o BatchMode=yes
|
||||||
|
-o StrictHostKeyChecking=accept-new
|
||||||
|
-o ConnectTimeout=6
|
||||||
|
-o ConnectionAttempts=1
|
||||||
|
-p "$SSH_PORT"
|
||||||
|
)
|
||||||
|
|
||||||
|
SCP_PASS_OPTS=(
|
||||||
|
-o StrictHostKeyChecking=accept-new
|
||||||
|
-o ConnectTimeout=6
|
||||||
|
-o ConnectionAttempts=1
|
||||||
|
-p "$SSH_PORT"
|
||||||
|
)
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}=== InfoUser Agent deploy ===${NC}"
|
||||||
|
echo "SERVER_URL: $SERVER_URL"
|
||||||
|
echo "AGENT_TOKEN: ${AGENT_TOKEN:0:8}..."
|
||||||
|
echo "HOSTS_FILE: $HOSTS_FILE"
|
||||||
|
echo "KEY_FILE: $KEY_FILE"
|
||||||
|
echo "LOG_DIR: $LOG_DIR"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
check_prerequisites() {
|
||||||
|
local missing=()
|
||||||
|
command -v ssh >/dev/null 2>&1 || missing+=("ssh")
|
||||||
|
command -v scp >/dev/null 2>&1 || missing+=("scp")
|
||||||
|
command -v sshpass >/dev/null 2>&1 || missing+=("sshpass")
|
||||||
|
command -v ping >/dev/null 2>&1 || missing+=("ping")
|
||||||
|
|
||||||
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
|
echo -e "${RED}Ошибка: не найдены утилиты: ${missing[*]}${NC}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$HOSTS_FILE" ]]; then
|
||||||
|
echo -e "${RED}Ошибка: файл со списком хостов не найден: $HOSTS_FILE${NC}" >&2
|
||||||
|
echo "Создайте его по примеру ip.txt.example" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$KEY_FILE" ]]; then
|
||||||
|
echo -e "${RED}Ошибка: SSH-ключ не найден: $KEY_FILE${NC}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Генерируем .pub если нет
|
||||||
|
if [[ ! -f "$PUB_FILE" ]]; then
|
||||||
|
echo "Генерирую публичный ключ: $PUB_FILE"
|
||||||
|
ssh-keygen -y -f "$KEY_FILE" > "$PUB_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ищем fallback .deb в корне проекта
|
||||||
|
DEB_FILE=""
|
||||||
|
for f in "${PROJECT_DIR}"/${PKG_NAME}_*_all.deb; do
|
||||||
|
[[ -f "$f" ]] && DEB_FILE="$f"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "$DEB_FILE" ]]; then
|
||||||
|
echo -e "${YELLOW}Предупреждение: fallback .deb не найден в $PROJECT_DIR. Будет использован только apt.${NC}"
|
||||||
|
else
|
||||||
|
echo "Fallback .deb: $DEB_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_target() {
|
||||||
|
local line="$1"
|
||||||
|
if [[ "$line" == *"@"* ]]; then
|
||||||
|
echo "$line"
|
||||||
|
else
|
||||||
|
echo "${DEFAULT_USER}@${line}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_host() {
|
||||||
|
local target="$1"
|
||||||
|
echo "${target#*@}"
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_name() {
|
||||||
|
local target="$1"
|
||||||
|
echo "${target//[@.:\/]/_}"
|
||||||
|
}
|
||||||
|
|
||||||
|
with_retries() {
|
||||||
|
local desc="$1"
|
||||||
|
shift
|
||||||
|
local attempt=1
|
||||||
|
while true; do
|
||||||
|
if "$@"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if (( attempt >= MAX_RETRIES )); then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo " ${desc}: повтор ${attempt}/${MAX_RETRIES}..."
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
sleep "$RETRY_SLEEP"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
ping_check() {
|
||||||
|
local host="$1"
|
||||||
|
ping -c 1 -W 1 "$host" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_key_check() {
|
||||||
|
local target="$1"
|
||||||
|
ssh -i "$KEY_FILE" -n "${SSH_KEY_OPTS[@]}" "$target" "echo ok" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_pass_check() {
|
||||||
|
local target="$1"
|
||||||
|
sshpass -p "$SSH_PASS" ssh -n "${SSH_PASS_OPTS[@]}" "$target" "echo ok" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_auth_method() {
|
||||||
|
local target="$1"
|
||||||
|
if ssh_key_check "$target"; then
|
||||||
|
echo "key"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ssh_pass_check "$target"; then
|
||||||
|
echo "pass"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "fail"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_key_on_host() {
|
||||||
|
local target="$1"
|
||||||
|
local log_file="$2"
|
||||||
|
{
|
||||||
|
echo "==> SSH по паролю успешен, добавляю ключ в authorized_keys"
|
||||||
|
sshpass -p "$SSH_PASS" ssh -n "${SSH_PASS_OPTS[@]}" "$target" "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
|
||||||
|
sshpass -p "$SSH_PASS" scp "${SCP_PASS_OPTS[@]}" "$PUB_FILE" "$target:/tmp/info_user_key.pub"
|
||||||
|
sshpass -p "$SSH_PASS" ssh -n "${SSH_PASS_OPTS[@]}" "$target" "cat /tmp/info_user_key.pub >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && rm -f /tmp/info_user_key.pub"
|
||||||
|
} >>"$log_file" 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_exec() {
|
||||||
|
local method="$1"
|
||||||
|
local target="$2"
|
||||||
|
local cmd="$3"
|
||||||
|
if [[ "$method" == "key" ]]; then
|
||||||
|
ssh -i "$KEY_FILE" -n "${SSH_KEY_OPTS[@]}" "$target" "$cmd"
|
||||||
|
else
|
||||||
|
sshpass -p "$SSH_PASS" ssh -n "${SSH_PASS_OPTS[@]}" "$target" "$cmd"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
scp_to_host() {
|
||||||
|
local method="$1"
|
||||||
|
local target="$2"
|
||||||
|
local local_path="$3"
|
||||||
|
local remote_path="$4"
|
||||||
|
if [[ "$method" == "key" ]]; then
|
||||||
|
scp "${SCP_KEY_OPTS[@]}" "$local_path" "$target:$remote_path"
|
||||||
|
else
|
||||||
|
sshpass -p "$SSH_PASS" scp "${SCP_PASS_OPTS[@]}" "$local_path" "$target:$remote_path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_agent() {
|
||||||
|
local method="$1"
|
||||||
|
local target="$2"
|
||||||
|
local log_file="$3"
|
||||||
|
|
||||||
|
local config_json
|
||||||
|
config_json=$(printf '{"server_url":"%s","agent_token":"%s","interval_minutes":60,"send_public_ip":false}' "$SERVER_URL" "$AGENT_TOKEN")
|
||||||
|
|
||||||
|
local remote_cmd
|
||||||
|
remote_cmd=$(printf 'echo "%s" | sudo -S tee %s >/dev/null' "$config_json" "$AGENT_CONFIG_FILE")
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "==> Настраиваю $AGENT_CONFIG_FILE"
|
||||||
|
ssh_exec "$method" "$target" "echo '$SSH_PASS' | sudo -S mkdir -p '$AGENT_CONFIG_DIR'"
|
||||||
|
ssh_exec "$method" "$target" "$remote_cmd"
|
||||||
|
|
||||||
|
echo "==> Запускаю таймер и первый heartbeat"
|
||||||
|
ssh_exec "$method" "$target" "echo '$SSH_PASS' | sudo -S systemctl daemon-reload"
|
||||||
|
ssh_exec "$method" "$target" "echo '$SSH_PASS' | sudo -S systemctl enable info-user-agent.timer"
|
||||||
|
ssh_exec "$method" "$target" "echo '$SSH_PASS' | sudo -S systemctl start info-user-agent.timer"
|
||||||
|
ssh_exec "$method" "$target" "echo '$SSH_PASS' | sudo -S systemctl start info-user-agent"
|
||||||
|
} >>"$log_file" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
install_agent() {
|
||||||
|
local method="$1"
|
||||||
|
local target="$2"
|
||||||
|
local log_file="$3"
|
||||||
|
|
||||||
|
# Сначала пробуем apt
|
||||||
|
{
|
||||||
|
echo "==> Пробую установить через apt"
|
||||||
|
ssh_exec "$method" "$target" "echo '$SSH_PASS' | sudo -S apt-get update -qq"
|
||||||
|
ssh_exec "$method" "$target" "echo '$SSH_PASS' | sudo -S apt-get install -y '$PKG_NAME'"
|
||||||
|
} >>"$log_file" 2>&1 && return 0
|
||||||
|
|
||||||
|
# Fallback на dpkg если apt не сработал и есть .deb
|
||||||
|
if [[ -z "$DEB_FILE" ]]; then
|
||||||
|
echo " apt не сработал, fallback .deb отсутствует" >>"$log_file" 2>&1
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local deb_name
|
||||||
|
deb_name="$(basename "$DEB_FILE")"
|
||||||
|
local remote_deb="/tmp/${deb_name}"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "==> apt не сработал, пробую dpkg -i $deb_name"
|
||||||
|
scp_to_host "$method" "$target" "$DEB_FILE" "$remote_deb"
|
||||||
|
ssh_exec "$method" "$target" "echo '$SSH_PASS' | sudo -S dpkg -i '$remote_deb'"
|
||||||
|
ssh_exec "$method" "$target" "rm -f '$remote_deb'"
|
||||||
|
} >>"$log_file" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
process_host() {
|
||||||
|
local raw_line="$1"
|
||||||
|
local target
|
||||||
|
local host_only
|
||||||
|
local safe_host
|
||||||
|
local log_file
|
||||||
|
local auth_method
|
||||||
|
|
||||||
|
target="$(normalize_target "$raw_line")"
|
||||||
|
host_only="$(extract_host "$target")"
|
||||||
|
safe_host="$(safe_name "$target")"
|
||||||
|
log_file="${LOG_DIR}/${safe_host}.log"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}===== $target =====${NC}"
|
||||||
|
|
||||||
|
# Пинг
|
||||||
|
if ! with_retries "ping" ping_check "$host_only"; then
|
||||||
|
echo -e "${RED}❌ Пинг не проходит: $target -> отложен${NC}"
|
||||||
|
echo "$target" >> "$DEFER_FILE"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Определяем метод авторизации
|
||||||
|
auth_method="$(detect_auth_method "$target")"
|
||||||
|
if [[ "$auth_method" == "fail" ]]; then
|
||||||
|
echo -e "${RED}❌ SSH недоступен (ключ и пароль): $target -> отложен${NC}"
|
||||||
|
echo "$target" >> "$DEFER_FILE"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$auth_method" == "key" ]]; then
|
||||||
|
echo -e "${GREEN}✅ SSH по ключу: $target${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✅ SSH по паролю: $target (добавляю ключ)${NC}"
|
||||||
|
install_key_on_host "$target" "$log_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Установка/обновление
|
||||||
|
if install_agent "$auth_method" "$target" "$log_file"; then
|
||||||
|
echo -e "${GREEN}✅ Агент установлен/обновлён: $target${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ Ошибка установки: $target -> отложен (см. $log_file)${NC}"
|
||||||
|
echo "$target" >> "$DEFER_FILE"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Настройка и запуск
|
||||||
|
if configure_agent "$auth_method" "$target" "$log_file"; then
|
||||||
|
echo -e "${GREEN}✅ Настроен и запущен: $target${NC}"
|
||||||
|
echo "$target" >> "$OK_FILE"
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ Установлен, но не удалось настроить/запустить: $target -> отложен (см. $log_file)${NC}"
|
||||||
|
echo "$target" >> "$DEFER_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
print_summary() {
|
||||||
|
local ok_count
|
||||||
|
local defer_count
|
||||||
|
ok_count="$(wc -l < "$OK_FILE" 2>/dev/null || echo 0)"
|
||||||
|
defer_count="$(wc -l < "$DEFER_FILE" 2>/dev/null || echo 0)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}=== Итог ===${NC}"
|
||||||
|
echo -e "${GREEN}Успешно: $ok_count${NC}"
|
||||||
|
echo -e "${RED}Отложено: $defer_count${NC}"
|
||||||
|
echo "Логи: $LOG_DIR/"
|
||||||
|
if [[ -s "$DEFER_FILE" ]]; then
|
||||||
|
echo "Повторить для отложенных: ./deploy-agent.sh"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
print_header
|
||||||
|
check_prerequisites
|
||||||
|
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
: > "$OK_FILE"
|
||||||
|
: > "$DEFER_FILE"
|
||||||
|
|
||||||
|
# Бэкап ip.txt
|
||||||
|
cp -f "$HOSTS_FILE" "${HOSTS_FILE}.bak.$(date +%Y%m%d_%H%M%S)" 2>/dev/null || true
|
||||||
|
|
||||||
|
local total=0
|
||||||
|
total="$(grep -vE '^\s*$|^\s*#' "$HOSTS_FILE" | wc -l)"
|
||||||
|
echo -e "${BLUE}Хостов в списке: $total${NC}"
|
||||||
|
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
# Убираем CR (Windows-концы строк)
|
||||||
|
line="${line//$'\r'/}"
|
||||||
|
|
||||||
|
# trim
|
||||||
|
line="${line#"${line%%[![:space:]]*}"}"
|
||||||
|
line="${line%"${line##*[![:space:]]}"}"
|
||||||
|
|
||||||
|
[[ -z "$line" || "$line" =~ ^# ]] && continue
|
||||||
|
process_host "$line"
|
||||||
|
done < "$HOSTS_FILE"
|
||||||
|
|
||||||
|
print_summary
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Список хостов для массового деплоя InfoUser Agent.
|
||||||
|
# Формат: user@IP или просто IP (будет использован DEFAULT_USER).
|
||||||
|
# Пустые строки и строки, начинающиеся с #, игнорируются.
|
||||||
|
|
||||||
|
user@192.168.255.50
|
||||||
|
user@192.168.255.16
|
||||||
|
192.168.255.71
|
||||||
Reference in New Issue
Block a user