From d2ec1242f0f5e553e1162ce2bde5eba99d6a52a2 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 3 Dec 2025 03:04:03 +0000 Subject: [PATCH] fix: --disable-host flag now correctly disables host monitoring The install script was not passing the --enable-host=false flag to the agent when --disable-host was specified. Since the agent defaults to enabling host monitoring, it was ignored. Also adds TrueNAS SCALE support to the unified agent installer: - Detects TrueNAS SCALE via /etc/truenas-version and other markers - Installs to /data/pulse-agent (persists across TrueNAS upgrades) - Creates Init/Shutdown task to restore service after TrueNAS updates - Adds uninstall support for TrueNAS SCALE Related to #800, #801 --- scripts/install.sh | 187 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 3 deletions(-) diff --git a/scripts/install.sh b/scripts/install.sh index 9fbe5df..0c88849 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -41,6 +41,13 @@ BINARY_NAME="pulse-agent" INSTALL_DIR="/usr/local/bin" LOG_FILE="/var/log/${AGENT_NAME}.log" +# TrueNAS SCALE configuration (immutable root filesystem) +TRUENAS=false +TRUENAS_STATE_DIR="/data/pulse-agent" +TRUENAS_LOG_DIR="$TRUENAS_STATE_DIR/logs" +TRUENAS_BOOTSTRAP_SCRIPT="$TRUENAS_STATE_DIR/bootstrap-pulse-agent.sh" +TRUENAS_ENV_FILE="$TRUENAS_STATE_DIR/pulse-agent.env" + # Defaults PULSE_URL="" PULSE_TOKEN="" @@ -69,7 +76,12 @@ fail() { # Returns via EXEC_ARGS variable build_exec_args() { EXEC_ARGS="--url ${PULSE_URL} --token ${PULSE_TOKEN} --interval ${INTERVAL}" - if [[ "$ENABLE_HOST" == "true" ]]; then EXEC_ARGS="$EXEC_ARGS --enable-host"; fi + # Always pass enable-host flag since agent defaults to true + if [[ "$ENABLE_HOST" == "true" ]]; then + EXEC_ARGS="$EXEC_ARGS --enable-host" + else + EXEC_ARGS="$EXEC_ARGS --enable-host=false" + fi if [[ "$ENABLE_DOCKER" == "true" ]]; then EXEC_ARGS="$EXEC_ARGS --enable-docker"; fi if [[ "$INSECURE" == "true" ]]; then EXEC_ARGS="$EXEC_ARGS --insecure"; fi if [[ -n "$AGENT_ID" ]]; then EXEC_ARGS="$EXEC_ARGS --agent-id ${AGENT_ID}"; fi @@ -79,7 +91,12 @@ build_exec_args() { # Returns via EXEC_ARGS_ARRAY variable build_exec_args_array() { EXEC_ARGS_ARRAY=(--url "$PULSE_URL" --token "$PULSE_TOKEN" --interval "$INTERVAL") - if [[ "$ENABLE_HOST" == "true" ]]; then EXEC_ARGS_ARRAY+=(--enable-host); fi + # Always pass enable-host flag since agent defaults to true + if [[ "$ENABLE_HOST" == "true" ]]; then + EXEC_ARGS_ARRAY+=(--enable-host) + else + EXEC_ARGS_ARRAY+=(--enable-host=false) + fi if [[ "$ENABLE_DOCKER" == "true" ]]; then EXEC_ARGS_ARRAY+=(--enable-docker); fi if [[ "$INSECURE" == "true" ]]; then EXEC_ARGS_ARRAY+=(--insecure); fi if [[ -n "$AGENT_ID" ]]; then EXEC_ARGS_ARRAY+=(--agent-id "$AGENT_ID"); fi @@ -154,6 +171,26 @@ if [[ "$UNINSTALL" == "true" ]]; then rm -f "${INSTALL_DIR}/${BINARY_NAME}" fi + # TrueNAS SCALE + if [[ -d "$TRUENAS_STATE_DIR" ]] || [[ -f /etc/truenas-version ]]; then + log_info "Removing TrueNAS SCALE installation..." + # Stop and disable service + systemctl stop "${AGENT_NAME}" 2>/dev/null || true + systemctl disable "${AGENT_NAME}" 2>/dev/null || true + # Remove systemd symlink + rm -f "/etc/systemd/system/${AGENT_NAME}.service" + systemctl daemon-reload 2>/dev/null || true + # Remove Init/Shutdown task + if command -v midclt >/dev/null 2>&1 && command -v python3 >/dev/null 2>&1; then + TASK_ID=$(midclt call initshutdownscript.query '[["script","=","'"$TRUENAS_BOOTSTRAP_SCRIPT"'"]]' 2>/dev/null | python3 -c "import json,sys; d=json.load(sys.stdin); print(d[0]['id'] if d else '')" 2>/dev/null || echo "") + if [[ -n "$TASK_ID" ]]; then + midclt call initshutdownscript.delete "$TASK_ID" >/dev/null 2>&1 || log_warn "Failed to remove Init/Shutdown task (id $TASK_ID)" + fi + fi + # Remove state directory + rm -rf "$TRUENAS_STATE_DIR" + fi + # OpenRC (Alpine, Gentoo, Artix, etc.) if command -v rc-service >/dev/null 2>&1; then rc-service "${AGENT_NAME}" stop 2>/dev/null || true @@ -186,6 +223,29 @@ if [[ ! "$INTERVAL" =~ ^[0-9]+[smh]?$ ]]; then fail "Invalid interval format. Use format like '30s', '5m', or '1h'." fi +# --- TrueNAS SCALE Detection --- +# TrueNAS SCALE has an immutable root filesystem; /usr/local/bin is read-only. +# We store everything in /data which persists across reboots and upgrades. +is_truenas_scale() { + if [[ -f /etc/truenas-version ]]; then + return 0 + fi + if [[ -f /etc/version ]] && grep -qi "truenas" /etc/version 2>/dev/null; then + return 0 + fi + if [[ -d /data/ix-applications ]] || [[ -d /etc/ix-apps.d ]]; then + return 0 + fi + return 1 +} + +if [[ "$(uname -s)" == "Linux" ]] && is_truenas_scale; then + TRUENAS=true + INSTALL_DIR="$TRUENAS_STATE_DIR" + LOG_FILE="$TRUENAS_LOG_DIR/${AGENT_NAME}.log" + log_info "TrueNAS SCALE detected (immutable root). Using $TRUENAS_STATE_DIR for installation." +fi + # --- Download --- OS=$(uname -s | tr '[:upper:]' '[:lower:]') ARCH=$(uname -m) @@ -298,9 +358,13 @@ if [[ "$OS" == "darwin" ]]; then --interval ${INTERVAL}" + # Always pass enable-host flag since agent defaults to true if [[ "$ENABLE_HOST" == "true" ]]; then PLIST_ARGS="${PLIST_ARGS} --enable-host" + else + PLIST_ARGS="${PLIST_ARGS} + --enable-host=false" fi if [[ "$ENABLE_DOCKER" == "true" ]]; then PLIST_ARGS="${PLIST_ARGS} @@ -495,7 +559,124 @@ EOF exit 0 fi -# 4. OpenRC (Alpine, Gentoo, Artix, etc.) +# 4. TrueNAS SCALE (immutable root, uses systemd but needs special persistence) +# TrueNAS SCALE wipes /etc/systemd/system on upgrades, so we store the service +# in /data and create an Init/Shutdown task to recreate the symlink on boot. +if [[ "$TRUENAS" == true ]]; then + log_info "Configuring TrueNAS SCALE installation..." + + # Create directories + mkdir -p "$TRUENAS_STATE_DIR" + mkdir -p "$TRUENAS_LOG_DIR" + + # Build command line args + build_exec_args + + # Store service file in /data (persists across upgrades) + TRUENAS_SERVICE_STORAGE="$TRUENAS_STATE_DIR/${AGENT_NAME}.service" + cat > "$TRUENAS_SERVICE_STORAGE" < "$TRUENAS_ENV_FILE" < "$TRUENAS_BOOTSTRAP_SCRIPT" <<'BOOTSTRAP' +#!/bin/bash +# Pulse Agent Bootstrap for TrueNAS SCALE +# This script is called by TrueNAS Init/Shutdown task on boot. +# It recreates the systemd symlink (which is wiped on TrueNAS upgrades). + +set -e + +SERVICE_NAME="pulse-agent" +SERVICE_STORAGE="STATE_DIR_PLACEHOLDER/pulse-agent.service" +SYSTEMD_LINK="/etc/systemd/system/${SERVICE_NAME}.service" + +if [[ ! -f "$SERVICE_STORAGE" ]]; then + echo "ERROR: Service file not found at $SERVICE_STORAGE" + exit 1 +fi + +# Create symlink (or update if exists) +ln -sf "$SERVICE_STORAGE" "$SYSTEMD_LINK" + +# Reload and start +systemctl daemon-reload +systemctl enable "$SERVICE_NAME" 2>/dev/null || true +systemctl restart "$SERVICE_NAME" + +echo "Pulse agent started successfully" +BOOTSTRAP + + # Replace placeholder + sed -i "s|STATE_DIR_PLACEHOLDER|${TRUENAS_STATE_DIR}|g" "$TRUENAS_BOOTSTRAP_SCRIPT" + chmod +x "$TRUENAS_BOOTSTRAP_SCRIPT" + + # Create systemd symlink now + SYSTEMD_LINK="/etc/systemd/system/${AGENT_NAME}.service" + ln -sf "$TRUENAS_SERVICE_STORAGE" "$SYSTEMD_LINK" + + # Register Init/Shutdown task using midclt + if command -v midclt >/dev/null 2>&1; then + log_info "Registering TrueNAS Init/Shutdown task..." + + # Check if task already exists + EXISTING_TASK=$(midclt call initshutdownscript.query '[["script","=","'"$TRUENAS_BOOTSTRAP_SCRIPT"'"]]' 2>/dev/null | python3 -c "import json,sys; d=json.load(sys.stdin); print(d[0]['id'] if d else '')" 2>/dev/null || echo "") + + if [[ -n "$EXISTING_TASK" ]]; then + log_info "Init/Shutdown task already exists (id $EXISTING_TASK), updating..." + midclt call initshutdownscript.update "$EXISTING_TASK" '{"type":"SCRIPT","script":"'"$TRUENAS_BOOTSTRAP_SCRIPT"'","when":"POSTINIT","enabled":true,"timeout":30,"comment":"Pulse Agent Bootstrap"}' >/dev/null 2>&1 || true + else + midclt call initshutdownscript.create '{"type":"SCRIPT","script":"'"$TRUENAS_BOOTSTRAP_SCRIPT"'","when":"POSTINIT","enabled":true,"timeout":30,"comment":"Pulse Agent Bootstrap"}' >/dev/null 2>&1 || log_warn "Failed to create Init/Shutdown task. Please add it manually in TrueNAS UI." + fi + else + log_warn "midclt not available. Please create an Init/Shutdown task manually in TrueNAS UI:" + log_warn " Type: Script" + log_warn " Script: $TRUENAS_BOOTSTRAP_SCRIPT" + log_warn " When: Post Init" + fi + + # Enable and start service + systemctl daemon-reload + systemctl enable "${AGENT_NAME}" 2>/dev/null || true + systemctl restart "${AGENT_NAME}" + + log_info "Installation complete!" + log_info "Binary: ${INSTALL_DIR}/${BINARY_NAME}" + log_info "Service: $TRUENAS_SERVICE_STORAGE (symlinked to systemd)" + log_info "Logs: tail -f ${LOG_FILE}" + log_info "" + log_info "The Init/Shutdown task ensures the agent survives TrueNAS upgrades." + exit 0 +fi + +# 5. OpenRC (Alpine, Gentoo, Artix, etc.) # Check for rc-service but make sure we're not on a systemd system that happens to have it if command -v rc-service >/dev/null 2>&1 && [[ -d /etc/init.d ]] && ! command -v systemctl >/dev/null 2>&1; then INITSCRIPT="/etc/init.d/${AGENT_NAME}"