#!/usr/bin/env bash # install-debian.sh — iria-monitor installer for Debian / Ubuntu (apt-based) # # Served per-environment: `curl -fsSL https:///install-debian.sh | bash` # -> installs the published package from PyPI and points the CLI at . # Beta bundle: `bash install-debian.sh` # -> if an iria_monitor-*.whl sits next to this script, installs from it. # # For non-Debian distros, see the pipx instructions on the /toolkit page. set -euo pipefail PACKAGE_NAME="iria-monitor" BINARY_NAME="iria-monitor" TELEMETRY_URL="https://staging.monitor.iria.tech/api/otel/v1/logs" SERVER_URL="https://staging.monitor.iria.tech" # rewritten per-env by the SaaS route case "$SERVER_URL" in http://*|https://*) : ;; *) SERVER_URL="https://plexus-monitor.iria.tech" TELEMETRY_URL="https://plexus-monitor.iria.tech/api/otel/v1/logs" ;; esac green() { printf '\033[0;32m%s\033[0m\n' "$*"; } cyan() { printf '\033[0;36m%s\033[0m\n' "$*"; } red() { printf '\033[0;31m%s\033[0m\n' "$*"; } yellow() { printf '\033[0;33m%s\033[0m\n' "$*"; } step() { cyan "=> $*"; } ok() { green " $*"; } err() { red " $*"; } PYTHON_VER_TEL="none" PYTHON_SOURCE_TEL="unknown" PIPX_PREINSTALLED_TEL="false" INSTALL_KIND_TEL="pipx" send_telemetry() { local exit_code="$1" local message="$2" local failed_step="${3:-}" local severity_text="INFO" local severity_number=9 if [ "$exit_code" -ne 0 ]; then severity_text="ERROR" severity_number=17 fi local os_version os_version="$(cat /etc/os-release 2>/dev/null | grep -m1 '^PRETTY_NAME=' | cut -d= -f2- | tr -d '"' || echo unknown)" local ts ts="$(python3 -c "import time; print(int(time.time()*1e9))" 2>/dev/null || echo 0)" local failed_attr="" if [ -n "$failed_step" ]; then failed_attr=',{"key":"context.failed_step","value":{"stringValue":"'"$failed_step"'"}}' fi curl -s -o /dev/null --max-time 5 -X POST "$TELEMETRY_URL" \ -H "Content-Type: application/json" \ -d '{ "resourceLogs":[{"resource":{"attributes":[ {"key":"service.name","value":{"stringValue":"iria-monitor-cli"}}, {"key":"telemetry.sdk.language","value":{"stringValue":"bash"}}, {"key":"deployment.environment","value":{"stringValue":"cli"}} ]},"scopeLogs":[{"scope":{"name":"iria-monitor-cli.telemetry"},"logRecords":[{ "timeUnixNano":"'"$ts"'", "severityText":"'"$severity_text"'", "severityNumber":'"$severity_number"', "body":{"stringValue":"cli.install"}, "attributes":[ {"key":"event.name","value":{"stringValue":"cli.install"}}, {"key":"platform","value":{"stringValue":"linux"}}, {"key":"python.version","value":{"stringValue":"'"$PYTHON_VER_TEL"'"}}, {"key":"install.kind","value":{"stringValue":"'"$INSTALL_KIND_TEL"'"}}, {"key":"exit.code","value":{"intValue":"'"$exit_code"'"}}, {"key":"event.message","value":{"stringValue":"'"$message"'"}}, {"key":"context.os_version","value":{"stringValue":"'"$os_version"'"}}, {"key":"context.python_source","value":{"stringValue":"'"$PYTHON_SOURCE_TEL"'"}}, {"key":"context.pipx_preinstalled","value":{"boolValue":'"$PIPX_PREINSTALLED_TEL"'}}, {"key":"context.extras","value":{"stringValue":"core"}} '"$failed_attr"' ]}]}]}] }' 2>/dev/null || true } # sudo only when not already root and sudo exists. SUDO="" if [ "$(id -u)" -ne 0 ] && command -v sudo &>/dev/null; then SUDO="sudo" fi # --- Step 0: Decide install source (local wheel vs SaaS wheel vs PyPI) ----- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd 2>/dev/null || echo "")" WHEEL_FILE="" # 1) Check for a wheel bundled next to the script (offline/beta) if [ -n "$SCRIPT_DIR" ]; then WHEEL_FILE=$(find "$SCRIPT_DIR" -maxdepth 1 -name 'iria_monitor-*.whl' -print -quit 2>/dev/null || true) fi # 2) No local wheel? Try downloading from the SaaS environment if [ -z "$WHEEL_FILE" ] && [[ "$SERVER_URL" == http* ]]; then step "Downloading wheel from $SERVER_URL..." TMP_WHL_DIR="$(mktemp -d)" TMP_WHL="$TMP_WHL_DIR/iria_monitor.whl" if curl -fsSL --max-time 30 "$SERVER_URL/dist/iria-monitor.whl" -o "$TMP_WHL" 2>/dev/null; then WHEEL_FILE="$TMP_WHL" INSTALL_KIND_TEL="wheel-served" ok "Downloaded wheel from server" else yellow "Wheel not available from server, falling back to PyPI" fi fi # 3) Final decision if [ -n "$WHEEL_FILE" ]; then INSTALL_SPEC="$WHEEL_FILE" [ "$INSTALL_KIND_TEL" = "wheel-served" ] || INSTALL_KIND_TEL="wheel" ok "Installing from $(basename "$WHEEL_FILE")" else INSTALL_SPEC="$PACKAGE_NAME" fi # --- Step 1: Ensure Python 3.10-3.13 -------------------------------------- step "Looking for Python 3.10-3.13..." find_python() { for candidate in python3.13 python3.12 python3.11 python3.10 python3; do if command -v "$candidate" &>/dev/null; then ver=$("$candidate" -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>/dev/null || true) if [ -n "$ver" ]; then major=$(echo "$ver" | cut -d. -f1) minor=$(echo "$ver" | cut -d. -f2) if [ "$major" -eq 3 ] && [ "$minor" -ge 10 ] && [ "$minor" -le 13 ]; then echo "$candidate" return 0 fi fi fi done return 1 } PYTHON_CMD="$(find_python || true)" if [ -z "$PYTHON_CMD" ] && command -v apt-get &>/dev/null; then step "Installing Python via apt..." $SUDO apt-get update -y $SUDO apt-get install -y python3 python3-venv python3-pip PYTHON_CMD="$(find_python || true)" fi if [ -z "$PYTHON_CMD" ]; then err "No Python 3.10-3.13 found and could not install it." yellow "Install it manually: sudo apt-get install -y python3 python3-venv python3-pip" send_telemetry 1 "no compatible python" "python_detection" exit 1 fi PYTHON_VER=$("$PYTHON_CMD" -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}')") PYTHON_VER_TEL="$PYTHON_VER" PYTHON_SOURCE_TEL="$PYTHON_CMD" ok "Found Python $PYTHON_VER ($PYTHON_CMD)" # --- Step 2: Install pipx if needed --------------------------------------- step "Checking for pipx..." if command -v pipx &>/dev/null; then PIPX_PREINSTALLED_TEL="true" ok "pipx already installed ($(pipx --version))" elif "$PYTHON_CMD" -m pipx --version &>/dev/null; then PIPX_PREINSTALLED_TEL="true" ok "pipx available via $PYTHON_CMD -m pipx" else step "Installing pipx..." # Debian 12+/Ubuntu 23.04+ ship pipx in apt; older releases fall back to pip --user. if command -v apt-get &>/dev/null && $SUDO apt-get install -y pipx 2>/dev/null; then : else "$PYTHON_CMD" -m pip install --user pipx fi "$PYTHON_CMD" -m pipx ensurepath 2>/dev/null || pipx ensurepath 2>/dev/null || true if ! command -v pipx &>/dev/null && ! "$PYTHON_CMD" -m pipx --version &>/dev/null; then err "Failed to install pipx." yellow "Try manually: sudo apt-get install -y pipx OR $PYTHON_CMD -m pip install --user pipx" send_telemetry 2 "pipx install failed" "pipx_install" exit 1 fi ok "pipx installed" fi if command -v pipx &>/dev/null; then PIPX_CMD="pipx" else PIPX_CMD="$PYTHON_CMD -m pipx" fi # --- Step 3: Install iria-monitor ----------------------------------------- if [ -n "$WHEEL_FILE" ]; then step "Installing $BINARY_NAME from $(basename "$WHEEL_FILE")..." else step "Installing $PACKAGE_NAME from PyPI..." fi if ! $PIPX_CMD install "$INSTALL_SPEC" --force --python "$PYTHON_CMD" 2>&1; then err "Failed to install $BINARY_NAME." send_telemetry 3 "package install failed" "package_install" exit 1 fi ok "$BINARY_NAME installed" # --- Step 4: Verify ------------------------------------------------------- step "Verifying installation..." export PATH="$HOME/.local/bin:$PATH" if command -v "$BINARY_NAME" &>/dev/null; then ver=$("$BINARY_NAME" version 2>/dev/null || echo "unknown") ok "$BINARY_NAME $ver is ready" else err "$BINARY_NAME not found in PATH." yellow "Restart your terminal and try: $BINARY_NAME version" fi # --- Step 5: Telemetry (success) ------------------------------------------ send_telemetry 0 "ok" # --- Step 6: Run the setup wizard ----------------------------------------- echo "" green "Installation complete!" echo "" # Continue straight into the setup wizard. We do NOT write any config here: the # wizard itself records the server URL (passed via --server-url) and walks # through account linking, AI tracking, tray and proxy. if ! command -v "$BINARY_NAME" &>/dev/null; then yellow "$BINARY_NAME is not on PATH yet." yellow "Restart your terminal (or run: source ~/.bashrc), then run: $BINARY_NAME install" elif [ -t 0 ]; then step "Launching setup wizard ($BINARY_NAME install)..." "$BINARY_NAME" install --server-url "$SERVER_URL" else yellow "Run the setup wizard when ready: $BINARY_NAME install" fi