diff --git a/configure-host.sh b/configure-host.sh new file mode 100755 index 0000000..a06b0e2 --- /dev/null +++ b/configure-host.sh @@ -0,0 +1,360 @@ +#!/bin/bash + +# ============================================================== +# πŸ› οΈ Configure Host +# Configura a mΓ‘quina host: serviΓ§o Docker, limite de log +# e arquivo de observabilidade. Pode ser executado em +# ambientes novos ou jΓ‘ instalados. +# Uso: +# bash configure-host.sh +# ============================================================== + +if [ -t 0 ]; then + : +else + exec < /dev/tty +fi + +set -e + +# ─── Cores ──────────────────────────────────────────────────── +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +BOLD='\033[1m' +DIM='\033[2m' +NC='\033[0m' + +# ─── Sudo ───────────────────────────────────────────────────── +SUDO="" +[ "$EUID" -ne 0 ] && SUDO="sudo" + +_SUDO_REQUESTED=false +request_sudo() { + [ "$_SUDO_REQUESTED" = "true" ] && return 0 + [ -z "$SUDO" ] && return 0 + echo "" + print_warn "Esta etapa requer permissΓ΅es de superusuΓ‘rio." + if ! sudo -v; then + print_error "NΓ£o foi possΓ­vel obter permissΓ΅es de superusuΓ‘rio." + exit 1 + fi + _SUDO_REQUESTED=true +} + +# ─── UtilitΓ‘rios ────────────────────────────────────────────── + +print_banner() { + clear + echo -e "${CYAN}" + echo " ╔══════════════════════════════════════════════╗" + echo " β•‘ 🐳 Docker Service Installer β•‘" + echo " β•‘ Registra o Docker como serviΓ§o systemd β•‘" + echo " β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•" + echo -e "${NC}" +} + +print_step() { echo -e "\n${BLUE}${BOLD}β–Ά $1${NC}"; } +print_ok() { echo -e " ${GREEN}βœ” $1${NC}"; } +print_warn() { echo -e " ${YELLOW}⚠ $1${NC}"; } +print_error() { echo -e " ${RED}βœ– $1${NC}"; } + +confirm() { + echo -ne " ${BOLD}$1${NC} ${CYAN}[s/N]${NC}: " + read -r resp + [[ "$resp" =~ ^[sS]$ ]] +} + +# ══════════════════════════════════════════════════════════════ +# Validar systemctl +# ══════════════════════════════════════════════════════════════ + +check_systemctl() { + print_step "Verificando systemctl..." + + if ! command -v systemctl &>/dev/null; then + print_error "systemctl nΓ£o encontrado. Este script requer systemd." + exit 1 + fi + + print_ok "systemctl encontrado ($(systemctl --version | head -1))" +} + +# ══════════════════════════════════════════════════════════════ +# Validar Docker instalado +# ══════════════════════════════════════════════════════════════ + +check_docker_installed() { + print_step "Verificando instalaΓ§Γ£o do Docker..." + + if ! command -v docker &>/dev/null; then + print_error "Docker nΓ£o encontrado. Instale o Docker antes de continuar." + echo -e " ${DIM}ReferΓͺncia: https://docs.docker.com/engine/install/${NC}" + exit 1 + fi + + print_ok "Docker encontrado ($(docker --version))" +} + +# ─── DiretΓ³rio de instalaΓ§Γ£o ────────────────────────────────── +INSTALL_DIR="attendancesystem" + +# ══════════════════════════════════════════════════════════════ +# Carregar / inicializar .env.observability +# ══════════════════════════════════════════════════════════════ + +_observability_defaults() { + local env_file="$1" + cat > "$env_file" <<'EOF' +SeventhLogs__CustomLevel__Warning__0=Microsoft.AspNetCore +SeventhLogs__CustomLevel__Warning__1=Microsoft.AspNetCore.Hosting.Diagnostics +SeventhLogs__CustomLevel__Warning__2=System.Net.Http.HttpClient.OtlpTraceExporter.ClientHandler +SeventhLogs__CustomLevel__Warning__3=System.Net.Http.HttpClient.OtlpTraceExporter.LogicalHandler +EOF +} + +load_observability_env() { + local env_file="${INSTALL_DIR}/.env.observability" + + if [ ! -f "$env_file" ]; then + _observability_defaults "$env_file" + print_ok ".env.observability criado com configuraΓ§Γ΅es padrΓ£o" + return + fi + + print_warn "ConfiguraΓ§Γ£o de observabilidade encontrada em ${env_file}" + + if confirm "Deseja manter as configuraΓ§Γ΅es atuais?"; then + print_ok ".env.observability mantido sem alteraΓ§Γ΅es" + return + fi + + if confirm "NΓ£o manter as configuraΓ§Γ΅es atuais do arquivo .env.observability vai redefinir para as configuraΓ§Γ΅es padrΓ΅es, vocΓͺ realmente deseja fazer isso?"; then + print_ok ".env.observability mantido sem alteraΓ§Γ΅es" + return + fi + + _observability_defaults "$env_file" + print_ok ".env.observability redefinido para as configuraΓ§Γ΅es padrΓ£o" +} +# ══════════════════════════════════════════════════════════════ +# Flags de controle +# ══════════════════════════════════════════════════════════════ + +NEEDS_SERVICE_CONFIG=false +NEEDS_LOG_CONFIG=false + +# ══════════════════════════════════════════════════════════════ +# Verificar status atual do serviΓ§o e configuraΓ§Γ£o de log +# ══════════════════════════════════════════════════════════════ + +check_docker_service_status() { + print_step "Verificando status do serviΓ§o Docker..." + + local enabled active + enabled=$(systemctl is-enabled docker 2>/dev/null || echo "disabled") + active=$(systemctl is-active docker 2>/dev/null || echo "inactive") + + echo -e " ${DIM}Habilitado no boot : ${NC}${BOLD}${enabled}${NC}" + echo -e " ${DIM}Status atual : ${NC}${BOLD}${active}${NC}" + + if [[ "$enabled" != "enabled" || "$active" != "active" ]]; then + NEEDS_SERVICE_CONFIG=true + fi + + local daemon_json="/etc/docker/daemon.json" + if [ -f "$daemon_json" ] && grep -q '"max-size"' "$daemon_json"; then + echo -e " ${DIM}Limite de log : ${NC}${GREEN}${BOLD}configurado${NC}" + else + echo -e " ${DIM}Limite de log : ${NC}${YELLOW}${BOLD}nΓ£o configurado${NC}" + NEEDS_LOG_CONFIG=true + fi + + if [[ "$NEEDS_SERVICE_CONFIG" == "false" && "$NEEDS_LOG_CONFIG" == "false" ]]; then + echo "" + print_ok "Docker jΓ‘ estΓ‘ registrado, rodando e com limite de log configurado." + print_ok "Nenhuma aΓ§Γ£o necessΓ‘ria." + echo "" + exit 0 + fi +} + +# ══════════════════════════════════════════════════════════════ +# Mostrar resumo antes de aplicar +# ══════════════════════════════════════════════════════════════ + +show_summary() { + echo "" + echo -e "${CYAN}${BOLD} β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”" + echo -e " β”‚ AΓ§Γ΅es que serΓ£o executadas β”‚" + echo -e " β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜${NC}" + echo "" + + local step=1 + + if [[ "$NEEDS_SERVICE_CONFIG" == "true" ]]; then + echo -e " ${BOLD}${step}.${NC} Criar drop-in de polΓ­tica de restart:" + echo -e " ${DIM}/etc/systemd/system/docker.service.d/restart-policy.conf${NC}" + echo -e " ${DIM}β†’ Restart=always | RestartSec=5${NC}" + echo "" + step=$((step + 1)) + + echo -e " ${BOLD}${step}.${NC} Recarregar o daemon do systemd" + echo -e " ${DIM}β†’ systemctl daemon-reload${NC}" + echo "" + step=$((step + 1)) + + echo -e " ${BOLD}${step}.${NC} Habilitar o Docker para iniciar com o SO" + echo -e " ${DIM}β†’ systemctl enable docker${NC}" + echo "" + step=$((step + 1)) + + echo -e " ${BOLD}${step}.${NC} Iniciar o serviΓ§o Docker imediatamente" + echo -e " ${DIM}β†’ systemctl start docker${NC}" + echo "" + step=$((step + 1)) + fi + + if [[ "$NEEDS_LOG_CONFIG" == "true" ]]; then + echo -e " ${BOLD}${step}.${NC} Configurar limite de log em /etc/docker/daemon.json" + echo -e " ${DIM}β†’ log-driver: json-file | max-size: 100m | max-file: 5${NC}" + echo "" + step=$((step + 1)) + + echo -e " ${BOLD}${step}.${NC} Reiniciar o Docker para aplicar a configuraΓ§Γ£o de log" + echo -e " ${DIM}β†’ systemctl restart docker${NC}" + echo "" + fi + + echo -e " ──────────────────────────────────────────────────────────────" + echo "" + + if ! confirm "Deseja aplicar as configuraΓ§Γ΅es acima?"; then + echo "" + print_warn "OperaΓ§Γ£o cancelada. Nenhuma alteraΓ§Γ£o foi feita." + echo "" + exit 0 + fi +} + +# ══════════════════════════════════════════════════════════════ +# Aplicar configuraΓ§Γ£o do serviΓ§o systemd +# ══════════════════════════════════════════════════════════════ + +configure_docker_service() { + [[ "$NEEDS_SERVICE_CONFIG" == "false" ]] && return 0 + + print_step "Configurando serviΓ§o Docker no systemd..." + + request_sudo + + local override_dir="/etc/systemd/system/docker.service.d" + $SUDO mkdir -p "$override_dir" + + $SUDO tee "$override_dir/restart-policy.conf" > /dev/null <<'EOF' +[Service] +Restart=always +RestartSec=5 +EOF + print_ok "Drop-in de restart criado em ${override_dir}/restart-policy.conf" + + $SUDO systemctl daemon-reload + print_ok "systemctl daemon-reload executado" + + $SUDO systemctl enable docker + print_ok "Docker habilitado para iniciar com o SO" + + $SUDO systemctl start docker + print_ok "Docker iniciado" +} + +# ══════════════════════════════════════════════════════════════ +# Configurar limite de log do Docker +# ══════════════════════════════════════════════════════════════ + +configure_docker_log_limit() { + [[ "$NEEDS_LOG_CONFIG" == "false" ]] && return 0 + + print_step "Configurando limite de log do Docker..." + + request_sudo + + local daemon_json="/etc/docker/daemon.json" + + if [ -f "$daemon_json" ]; then + $SUDO cp "$daemon_json" "${daemon_json}.bak" + print_warn "Backup do daemon.json criado em ${daemon_json}.bak" + fi + + $SUDO mkdir -p "$(dirname "$daemon_json")" + + $SUDO tee "$daemon_json" > /dev/null <<'EOF' +{ + "log-driver": "json-file", + "log-opts": { + "max-size": "100m", + "max-file": "5" + } +} +EOF + print_ok "Limite de log configurado em ${daemon_json} (max-size: 100m, max-file: 5)" + + $SUDO systemctl restart docker + print_ok "Docker reiniciado para aplicar a configuraΓ§Γ£o de log" +} + +# ══════════════════════════════════════════════════════════════ +# Validar resultado final +# ══════════════════════════════════════════════════════════════ + +verify_result() { + print_step "Validando configuraΓ§Γ£o..." + + if ! systemctl is-active --quiet docker; then + print_error "O serviΓ§o Docker nΓ£o estΓ‘ ativo apΓ³s a configuraΓ§Γ£o." + echo -e " ${DIM}Verifique os logs com: journalctl -u docker --no-pager -n 20${NC}" + exit 1 + fi + + local daemon_json="/etc/docker/daemon.json" + if [ ! -f "$daemon_json" ] || ! grep -q '"max-size"' "$daemon_json"; then + print_error "Limite de log nΓ£o encontrado em ${daemon_json} apΓ³s a configuraΓ§Γ£o." + exit 1 + fi + + echo "" + echo -e "${GREEN}${BOLD} ╔══════════════════════════════════════════════╗" + echo -e " β•‘ βœ… Docker configurado com sucesso! β•‘" + echo -e " β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" + echo "" + echo -e " ${BOLD}Status final:${NC}" + echo -e " Habilitado no boot : ${GREEN}$(systemctl is-enabled docker)${NC}" + echo -e " Rodando agora : ${GREEN}$(systemctl is-active docker)${NC}" + echo -e " PolΓ­tica de restart: ${GREEN}always (RestartSec=5s)${NC}" + echo -e " Limite de log : ${GREEN}max-size=100m, max-file=5${NC}" + echo "" + echo -e " ${DIM}Comandos ΓΊteis:" + echo -e " systemctl status docker" + echo -e " journalctl -u docker -f${NC}" + echo "" +} + +# ══════════════════════════════════════════════════════════════ +# MAIN +# ══════════════════════════════════════════════════════════════ + +main() { + print_banner + check_systemctl + check_docker_installed + check_docker_service_status + show_summary + configure_docker_service + configure_docker_log_limit + verify_result + load_observability_env +} + +main "$@" diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 8be3562..43da261 --- a/install.sh +++ b/install.sh @@ -26,6 +26,23 @@ BOLD='\033[1m' DIM='\033[2m' NC='\033[0m' +# ─── Sudo ───────────────────────────────────────────────────── +SUDO="" +[ "$EUID" -ne 0 ] && SUDO="sudo" + +_SUDO_REQUESTED=false +request_sudo() { + [ "$_SUDO_REQUESTED" = "true" ] && return 0 + [ -z "$SUDO" ] && return 0 + echo "" + print_warn "Esta etapa requer permissΓ΅es de superusuΓ‘rio." + if ! sudo -v; then + print_error "NΓ£o foi possΓ­vel obter permissΓ΅es de superusuΓ‘rio." + exit 1 + fi + _SUDO_REQUESTED=true +} + # ─── RepositΓ³rio Git ────────────────────────────────────────── INSTALL_DIR="attendancesystem" BRANCH="${BRANCH:-release/V1.4}" @@ -139,6 +156,89 @@ check_deps() { print_ok "Todas as dependΓͺncias OK" } +# ══════════════════════════════════════════════════════════════ +# Configurar limite de log do Docker +# ══════════════════════════════════════════════════════════════ + +configure_docker_log_limit() { + print_step "Configurando limite de log do Docker..." + + local daemon_json="/etc/docker/daemon.json" + + if [ -f "$daemon_json" ] && grep -q '"max-size"' "$daemon_json"; then + print_ok "Limite de log jΓ‘ configurado em ${daemon_json}" + return 0 + fi + + request_sudo + + if [ -f "$daemon_json" ]; then + $SUDO cp "$daemon_json" "${daemon_json}.bak" + print_warn "Backup do daemon.json criado em ${daemon_json}.bak" + fi + + $SUDO mkdir -p "$(dirname "$daemon_json")" + + $SUDO tee "$daemon_json" > /dev/null <<'EOF' +{ + "log-driver": "json-file", + "log-opts": { + "max-size": "100m", + "max-file": "5" + } +} +EOF + print_ok "Limite de log configurado em ${daemon_json} (max-size: 100m, max-file: 5)" + + if systemctl is-active --quiet docker; then + $SUDO systemctl restart docker + print_ok "Docker reiniciado para aplicar a configuraΓ§Γ£o de log" + fi +} + +# ══════════════════════════════════════════════════════════════ +# Garantir Docker como serviΓ§o systemd +# ══════════════════════════════════════════════════════════════ + +ensure_docker_service() { + print_step "Verificando serviΓ§o do Docker no systemd..." + + if ! command -v systemctl &>/dev/null; then + print_error "systemctl nΓ£o encontrado. Este instalador requer systemd." + exit 1 + fi + print_ok "systemctl encontrado" + + if systemctl is-active --quiet docker; then + print_ok "Docker jΓ‘ estΓ‘ rodando como serviΓ§o systemd" + return 0 + fi + + print_warn "Docker nΓ£o estΓ‘ ativo como serviΓ§o. Configurando..." + + request_sudo + + local override_dir="/etc/systemd/system/docker.service.d" + $SUDO mkdir -p "$override_dir" + $SUDO tee "$override_dir/restart-policy.conf" > /dev/null <<'EOF' +[Service] +Restart=always +RestartSec=5 +EOF + + $SUDO systemctl daemon-reload + $SUDO systemctl enable docker + $SUDO systemctl start docker + + if systemctl is-active --quiet docker; then + print_ok "Docker habilitado e iniciado como serviΓ§o systemd" + print_ok "Docker iniciarΓ‘ automaticamente com o SO e serΓ‘ reiniciado se cair" + else + print_error "Falha ao iniciar o serviΓ§o docker. Verifique com: journalctl -u docker" + exit 1 + fi +} + # ══════════════════════════════════════════════════════════════ # Clonar / atualizar repositΓ³rio # ══════════════════════════════════════════════════════════════ @@ -159,6 +259,12 @@ clone_repo() { print_ok "Arquivos baixados em: $(pwd)/${INSTALL_DIR}" fi + if [ -f "$INSTALL_DIR/configure-host.sh" ]; then + cp "$INSTALL_DIR/configure-host.sh" ./configure-host.sh + chmod +x ./configure-host.sh + print_ok "configure-host.sh disponΓ­vel neste diretΓ³rio" + fi + ENV_FILE="$INSTALL_DIR/.env.prod" } @@ -365,6 +471,45 @@ EOF print_ok ".env.prod gerado" } +# ══════════════════════════════════════════════════════════════ +# Carregar / inicializar .env.observability +# ══════════════════════════════════════════════════════════════ + +_observability_defaults() { + local env_file="$1" + cat > "$env_file" <<'EOF' +SeventhLogs__CustomLevel__Warning__0=Microsoft.AspNetCore +SeventhLogs__CustomLevel__Warning__1=Microsoft.AspNetCore.Hosting.Diagnostics +SeventhLogs__CustomLevel__Warning__2=System.Net.Http.HttpClient.OtlpTraceExporter.ClientHandler +SeventhLogs__CustomLevel__Warning__3=System.Net.Http.HttpClient.OtlpTraceExporter.LogicalHandler +EOF +} + +load_observability_env() { + local env_file="${INSTALL_DIR}/.env.observability" + + if [ ! -f "$env_file" ]; then + _observability_defaults "$env_file" + print_ok ".env.observability criado com configuraΓ§Γ΅es padrΓ£o" + return + fi + + print_warn "ConfiguraΓ§Γ£o de observabilidade encontrada em ${env_file}" + + if confirm "Deseja manter as configuraΓ§Γ΅es atuais?"; then + print_ok ".env.observability mantido sem alteraΓ§Γ΅es" + return + fi + + if confirm "NΓ£o manter as configuraΓ§Γ΅es atuais do arquivo .env.observability vai redefinir para as configuraΓ§Γ΅es padrΓ΅es, vocΓͺ realmente deseja fazer isso?"; then + print_ok ".env.observability mantido sem alteraΓ§Γ΅es" + return + fi + + _observability_defaults "$env_file" + print_ok ".env.observability redefinido para as configuraΓ§Γ΅es padrΓ£o" +} + # ══════════════════════════════════════════════════════════════ # Subir ambiente # ══════════════════════════════════════════════════════════════ @@ -398,12 +543,15 @@ start_environment() { main() { print_banner check_deps + ensure_docker_service + configure_docker_log_limit clone_repo load_existing_env # detecta .env.prod existente + load_observability_env collect_config # wizard com navegaΓ§Γ£o show_summary # resumo com menu de ediΓ§Γ£o - generate_envs + if confirm "Deseja subir o ambiente agora?"; then start_environment