#!/usr/bin/env bash # install_systemd_service — Pipeline que registra una app como servicio systemd local. # Compone systemd_local_{install_unit, enable, start, status}. set -euo pipefail # Resolver repo root (asume que este archivo vive en bash/functions/pipelines/) PIPELINE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$PIPELINE_DIR/../../.." && pwd)" FN_DIR="$REPO_ROOT/bash/functions/infra" # shellcheck source=/dev/null source "$FN_DIR/systemd_local_install_unit.sh" # shellcheck source=/dev/null source "$FN_DIR/systemd_local_enable.sh" # shellcheck source=/dev/null source "$FN_DIR/systemd_local_start.sh" # shellcheck source=/dev/null source "$FN_DIR/systemd_local_status.sh" usage() { cat <<'USAGE' >&2 install_systemd_service — registra una app como servicio systemd del sistema. Uso: install_systemd_service --name --exec [opciones] Obligatorios: --name Nombre del servicio (sin .service) --exec Ruta absoluta al binario/script ExecStart Opcionales: --workdir WorkingDirectory (default: dirname de --exec) --user User del servicio (default: usuario actual) --description Description del unit (default: " service") --env KEY=VAL Variable de entorno (repetible) --after After= (default: network.target) --restart Restart= (default: on-failure) --type Type= (default: simple) Salida: JSON consolidado con los resultados de install_unit, enable, start y status. USAGE exit 1 } install_systemd_service() { local name="" exec_path="" workdir="" user="" description="" local after="network.target" restart="on-failure" type="simple" local -a envs=() while [[ $# -gt 0 ]]; do case "$1" in --name) name="$2"; shift 2 ;; --exec) exec_path="$2"; shift 2 ;; --workdir) workdir="$2"; shift 2 ;; --user) user="$2"; shift 2 ;; --description) description="$2"; shift 2 ;; --env) envs+=("$2"); shift 2 ;; --after) after="$2"; shift 2 ;; --restart) restart="$2"; shift 2 ;; --type) type="$2"; shift 2 ;; -h|--help) usage ;; *) echo "opción desconocida: $1" >&2; usage ;; esac done if [[ -z "$name" || -z "$exec_path" ]]; then echo "install_systemd_service: faltan --name y --exec" >&2 usage fi [[ -z "$user" ]] && user="$(id -un)" [[ -z "$workdir" ]] && workdir="$(dirname "$exec_path")" [[ -z "$description" ]] && description="$name service" # Construir bloque Environment= (uno por línea, orden determinista) local env_block="" local e for e in "${envs[@]}"; do env_block+="Environment=\"$e\" " done # Generar unit content (heredoc determinista) local unit_content unit_content="[Unit] Description=$description After=$after [Service] Type=$type User=$user WorkingDirectory=$workdir ${env_block}ExecStart=$exec_path Restart=$restart RestartSec=3 [Install] WantedBy=multi-user.target " echo "[install_systemd_service] instalando unit $name..." >&2 local install_json enable_json start_json status_json install_json=$(systemd_local_install_unit "$name" "$unit_content") echo "[install_systemd_service] enable..." >&2 enable_json=$(systemd_local_enable "$name") echo "[install_systemd_service] start..." >&2 start_json=$(systemd_local_start "$name") # Darle un instante a systemd para estabilizar el estado sleep 1 echo "[install_systemd_service] status..." >&2 status_json=$(systemd_local_status "$name" 15) # JSON consolidado python3 - "$install_json" "$enable_json" "$start_json" "$status_json" <<'PY' import json, sys keys = ["install", "enable", "start", "status"] out = {k: json.loads(v) for k, v in zip(keys, sys.argv[1:])} print(json.dumps(out, indent=2)) PY } # Ejecución directa if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then install_systemd_service "$@" fi