#!/bin/bash set -e update_notes() { local vmid="$1" local type="$2" echo "[INFO] Procesando $type $vmid..." # Detectar OS os=$(pct exec "$vmid" -- cat /etc/os-release 2>/dev/null | grep '^ID=' | cut -d= -f2 | tr -d '"') [ -z "$os" ] && echo "[WARN] No se pudo detectar OS para $type $vmid. Saltando." && return echo "[INFO] Sistema operativo detectado: $os" # Comandos por OS case "$os" in alpine) update_cmd="tries=5; for i in \$(seq 1 \$tries); do if apk update; then ok=1; break; else echo \"[WARN] apk update failed (\$i/\$tries). Retrying in \$((i*2))s...\"; sleep \$((i*2)); fi; done; [ \"\${ok:-0}\" = \"1\" ] || echo \"[WARN] Proceeding with stale indexes\"; apk upgrade --no-cache || echo \"[WARN] apk upgrade failed; continuing\"" install_base_pkgs="apk add --no-cache docker openssh jq" # Comprobar si tailscale está instalado check_tailscale_installed=$(pct exec "$vmid" -- sh -c "which tailscale 2>/dev/null || echo notfound") if [[ "$check_tailscale_installed" == "notfound" ]]; then install_tailscale="apk add --no-cache tailscale" else install_tailscale="echo '[INFO] tailscale ya está instalado'" fi enable_docker="rc-update add docker && rc-service docker start" enable_ssh="rc-update add sshd && rc-service sshd start" enable_tailscale_check='if [ -e /etc/init.d/tailscaled ]; then rc-update add tailscaled; rc-service tailscaled start; fi' check_tailscale_status='if [ -e /etc/init.d/tailscaled ]; then rc-service tailscaled status; else echo notinstalled; fi' ;; ubuntu) update_cmd="apt-get update && DEBIAN_FRONTEND=noninteractive apt-get upgrade -y" install_base_pkgs="apt-get install -y docker.io openssh-server jq" check_tailscale_installed=$(pct exec "$vmid" -- sh -c "which tailscale 2>/dev/null || echo notfound") if [[ "$check_tailscale_installed" == "notfound" ]]; then install_tailscale="apt-get install -y tailscale" else install_tailscale="echo '[INFO] tailscale ya está instalado'" fi enable_docker="systemctl enable docker && systemctl start docker" enable_ssh="systemctl enable ssh && systemctl start ssh" enable_tailscale_check="systemctl enable tailscaled && systemctl start tailscaled" check_tailscale_status="systemctl is-active tailscaled" ;; *) echo "[WARN] OS no soportado: $os. Saltando $vmid." return ;; esac # Ejecutar comandos pct exec "$vmid" -- sh -c "$update_cmd" pct exec "$vmid" -- sh -c "$install_base_pkgs || true" pct exec "$vmid" -- sh -c "$install_tailscale || true" pct exec "$vmid" -- sh -c "$enable_docker" pct exec "$vmid" -- sh -c "$enable_ssh" pct exec "$vmid" -- sh -c "$enable_tailscale_check" echo "[INFO] Verificando configuración del Docker API y métricas en $type $vmid..." pct exec "$vmid" -- sh -c ' set -e mkdir -p /etc/docker DAEMON_JSON="/etc/docker/daemon.json" TMP_JSON="/etc/docker/daemon.json.tmp" ensure_json() { if [ -f "$DAEMON_JSON" ]; then echo "[INFO] daemon.json existente encontrado. Verificando llaves requeridas..." if ! command -v jq >/dev/null 2>&1; then echo "[ERROR] jq no está instalado; no se puede actualizar JSON de Docker." >&2 exit 1 fi JQF="/tmp/daemon_filter.jq" cat > "$JQF" <<\JQ (.hosts = ((.hosts // []) + ["unix:///var/run/docker.sock","tcp://0.0.0.0:2375"]) | .hosts |= unique) | .["metrics-addr"] = "0.0.0.0:9023" | .experimental = true JQ jq -f "$JQF" "$DAEMON_JSON" > "$TMP_JSON" rm -f "$JQF" else echo "[INFO] Creando daemon.json con configuración por defecto (API TCP + métricas)." cat > "$TMP_JSON" <<\JSON { "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"], "metrics-addr": "0.0.0.0:9023", "experimental": true } JSON fi if [ ! -f "$DAEMON_JSON" ] || ! cmp -s "$DAEMON_JSON" "$TMP_JSON"; then echo "[INFO] Aplicando cambios a daemon.json" cp "$TMP_JSON" "$DAEMON_JSON" JSON_CHANGED=1 else echo "[INFO] daemon.json ya contiene la configuración requerida." JSON_CHANGED=0 fi rm -f "$TMP_JSON" } apply_systemd_override_if_needed() { # Sólo para sistemas con systemd (Ubuntu) if command -v systemctl >/dev/null 2>&1; then echo "[INFO] Detectado systemd. Verificando override de servicio Docker..." mkdir -p /etc/systemd/system/docker.service.d OVERRIDE="/etc/systemd/system/docker.service.d/override.conf" NEED_OVERRIDE=0 if systemctl cat docker 2>/dev/null | grep -qE "ExecStart=.*-H fd://"; then NEED_OVERRIDE=1 fi if [ $NEED_OVERRIDE -eq 1 ]; then echo "[INFO] Creando override de systemd para remover -H fd:// y permitir hosts desde daemon.json" cat > "$OVERRIDE" <<\OVR [Service] ExecStart= ExecStart=/usr/bin/dockerd OVR systemctl daemon-reload OVERRIDE_APPLIED=1 else echo "[INFO] No se requiere override de systemd." OVERRIDE_APPLIED=0 fi else OVERRIDE_APPLIED=0 fi } restart_docker() { if command -v systemctl >/dev/null 2>&1; then systemctl restart docker || true if systemctl is-active --quiet docker; then echo "[INFO] Docker reiniciado (systemd)." else echo "[WARN] Docker no está activo tras reinicio (systemd)." fi elif command -v rc-service >/dev/null 2>&1; then rc-service docker restart || true rc-service docker status || true echo "[INFO] Docker reiniciado (OpenRC)." else echo "[WARN] No se pudo detectar gestor de servicios para reiniciar Docker." fi } check_listeners() { echo "[INFO] Comprobando puertos en escucha para Docker..." if command -v ss >/dev/null 2>&1; then ss -lnt | awk "{print}" elif command -v netstat >/dev/null 2>&1; then netstat -lnt || true fi if ss -lnt 2>/dev/null | grep -q ":2375 "; then echo "[INFO] API Docker TCP escuchando en 0.0.0.0:2375" else echo "[WARN] API Docker TCP NO detectada en 0.0.0.0:2375" fi if ss -lnt 2>/dev/null | grep -q ":9023 "; then echo "[INFO] Métricas Docker escuchando en 0.0.0.0:9023" else echo "[WARN] Métricas Docker NO detectadas en 0.0.0.0:9023" fi } ensure_json apply_systemd_override_if_needed if [ ${JSON_CHANGED:-0} -eq 1 ] || [ ${OVERRIDE_APPLIED:-0} -eq 1 ]; then restart_docker else echo "[INFO] Configuración de Docker ya presente; no se requiere reinicio." fi check_listeners ' # Estado tailscale tailscale_status=$(pct exec "$vmid" -- sh -c "$check_tailscale_status" 2>&1) if echo "$tailscale_status" | grep -q "running"; then tailscale_note="tailscale UP" elif echo "$tailscale_status" | grep -q "notinstalled"; then tailscale_note="tailscale NOT INSTALLED" else tailscale_note="tailscale DOWN" fi # Obtener contenedores Docker docker_info=$(pct exec "$vmid" -- sh -c "docker ps --format '{{.Names}} : {{.Image}}'" 2>/dev/null || echo "Sin contenedores") if [[ -z "$docker_info" ]]; then docker_info="Sin contenedores" fi # Formar nota full_note=$(printf "# Notes:\n%s\n%s\n" "$tailscale_note" "$docker_info") # Añadir al archivo de configuración del contenedor conf_path="/etc/pve/lxc/${vmid}.conf" # Eliminar notas anteriores si existen sed -i '/^# Notes:/,$d' "$conf_path" echo -e "$full_note" >> "$conf_path" echo "[INFO] Notas actualizadas en $conf_path:" echo "$full_note" } echo "[INFO] Iniciando gestión automática de LXC..." # Iterar sobre LXC activos for vmid in $(pct list | awk 'NR>1 {print $1}'); do update_notes "$vmid" "LXC" done # VMs (sin integración por ahora) for vmid in $(qm list | awk 'NR>1 && $2 == "running" {print $1}'); do echo "[INFO] Saltando VM $vmid (se requiere integración SSH para gestionar desde el host)" done echo "[INFO] Script completado."