#!/usr/bin/env bash # ============================================================================= # PulseGrid Metric Agent Installation Script # ============================================================================= # # This script installs the PulseGrid Metric Agent. # The agent is used for system monitoring and metrics collection. # # ============================================================================= set -o errexit set -o nounset # ============================================================================= # CONFIGURATION SECTION # ============================================================================= # Agent download configuration AGENT_DOWNLOAD_URL="https://download.pulsegrid.uz/pulsegrid-metric-agent/latest/" # Detect architecture and set binary names ARCH=$(uname -m) case $ARCH in x86_64) AGENT_BINARY_NAME="pulsegrid-metric-agent-linux-amd64.tar.gz" AGENT_EXTRACTED_BINARY="pulsegrid-metric-agent-linux-amd64" ;; aarch64|arm64) AGENT_BINARY_NAME="pulsegrid-metric-agent-linux-arm64.tar.gz" AGENT_EXTRACTED_BINARY="pulsegrid-metric-agent-linux-arm64" ;; *) print_error "Unsupported architecture: $ARCH" print_error "Supported architectures: x86_64, aarch64, arm64" exit 1 ;; esac # Installation paths CONFIG_DIR="/etc/pulsegrid-metric-agent" DATA_DIR="/var/lib/pulsegrid-metric-agent/data" BINARY_DIR="/usr/local/bin" # Service configuration SERVICE_NAME="pulsegrid-metric-agent" SERVICE_USER="pulsegrid-metric-agent" SERVICE_GROUP="pulsegrid-metric-agent" # ============================================================================= # COLOR OUTPUT FUNCTIONS # ============================================================================= # Color codes for terminal output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # Shows general information messages in green print_status() { echo -e "${GREEN}[INFO]${NC} $1" } # Shows warning messages in yellow print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } # Shows error messages in red print_error() { echo -e "${RED}[ERROR]${NC} $1" } # Shows section headers in blue print_header() { echo -e "${BLUE}[HEADER]${NC} $1" } # Shows step-by-step progress in blue print_step() { echo -e "${BLUE}[STEP]${NC} $1" } # Shows success messages in green print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } # ============================================================================= # SYSTEM CHECKS # ============================================================================= # Check root privileges print_status "Checking root privileges..." if [ "$EUID" -ne 0 ]; then print_error "This script must be run as root (use sudo)" print_status "Usage: sudo $0" exit 1 fi print_status "Root privileges confirmed" # Check operating system and architecture print_status "Checking system requirements..." # Check if it's Linux if [ "$(uname)" != "Linux" ]; then print_error "This script only supports Linux operating systems" print_error "Detected OS: $(uname)" exit 1 fi # Check if it's supported architecture case $ARCH in x86_64|aarch64|arm64) print_status "Supported architecture detected: $ARCH" ;; *) print_error "This script only supports x86_64, aarch64, and arm64 architectures" print_error "Detected architecture: $ARCH" exit 1 ;; esac # Check if it's supported distribution DISTRO=$(grep PRETTY_NAME /etc/os-release | cut -d'"' -f2 2>/dev/null || echo 'Unknown') if grep -q "Ubuntu\|Debian" /etc/os-release 2>/dev/null; then print_status "Debian/Ubuntu family detected - fully supported" elif grep -q "Fedora\|Red Hat\|CentOS\|Rocky\|Alma" /etc/os-release 2>/dev/null; then print_status "Fedora/RHEL family detected - fully supported" else print_warning "This script is tested on Debian/Ubuntu and Fedora/RHEL families" print_warning "Detected distribution: $DISTRO" print_warning "Other distributions may work but are not guaranteed" # Ask for confirmation to continue read -p "Do you want to continue anyway? (y/N): " -r if [[ ! $REPLY =~ ^[Yy]$ ]]; then print_status "Installation cancelled by user" exit 0 fi fi print_status "System requirements check passed" # Check and install dependencies print_status "Checking system dependencies..." missing_deps=() # List of required dependencies required_deps=("curl" "tar" "gzip" "systemctl") # Check each dependency for dep in "${required_deps[@]}"; do if ! command -v "$dep" >/dev/null 2>&1; then missing_deps+=("$dep") fi done # Install missing dependencies if any if [ ${#missing_deps[@]} -ne 0 ]; then print_warning "Missing dependencies: ${missing_deps[*]}" print_status "Installing missing dependencies..." # Detect package manager if command -v apt-get >/dev/null 2>&1; then print_status "Using apt-get (Debian/Ubuntu family)" sudo apt-get update sudo apt-get install -y "${missing_deps[@]}" elif command -v dnf >/dev/null 2>&1; then print_status "Using dnf (Fedora/RHEL family)" sudo dnf install -y "${missing_deps[@]}" elif command -v yum >/dev/null 2>&1; then print_status "Using yum (RHEL/CentOS family)" sudo yum install -y "${missing_deps[@]}" else print_error "No supported package manager found (apt-get, dnf, or yum)" print_error "Please install the following packages manually: ${missing_deps[*]}" exit 1 fi print_status "Dependencies installed successfully" else print_status "All required dependencies are already installed" fi # ============================================================================= # ENVIRONMENT VARIABLES VALIDATION # ============================================================================= print_step "Validating environment variables..." # Check USER_UUID if [ -z "${USER_UUID:-}" ]; then print_error "USER_UUID environment variable is required" print_status "Please set USER_UUID before running this script:" print_status "export USER_UUID=\"your-uuid\"" exit 1 fi # Check AGENT_TOKEN if [ -z "${AGENT_TOKEN:-}" ]; then print_error "AGENT_TOKEN environment variable is required" print_status "Please set AGENT_TOKEN before running this script:" print_status "export AGENT_TOKEN=\"your-token\"" exit 1 fi print_status "✓ USER_UUID: $USER_UUID" print_status "✓ AGENT_TOKEN: [HIDDEN]" # ============================================================================= # CHECK EXISTING INSTALLATION # ============================================================================= print_step "Checking existing installation..." # Check if binary exists if [ -f "$BINARY_DIR/pulsegrid-metric-agent" ]; then print_status "✓ Agent binary exists: $BINARY_DIR/pulsegrid-metric-agent" else print_status "Agent binary not found - will install" fi # Check if service exists if [ -f "/etc/systemd/system/$SERVICE_NAME.service" ]; then print_status "✓ Systemd service exists: /etc/systemd/system/$SERVICE_NAME.service" else print_status "Systemd service not found - will create" fi # Check if service is active if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then print_status "✓ Service is active and running" print_success "PulseGrid Metric Agent is already installed and running" print_status "Service status: active" print_status "Binary location: $BINARY_DIR/pulsegrid-metric-agent" print_status "Config directory: $CONFIG_DIR" print_success "No action needed - agent is working properly" exit 0 else print_status "Service is not active - will start after installation" fi # ============================================================================= # CREATE SYSTEM USER AND GROUP # ============================================================================= print_step "Creating system user and group..." # Create group if not exists if ! getent group "$SERVICE_GROUP" >/dev/null 2>&1; then print_status "Creating system group: $SERVICE_GROUP" if groupadd --system "$SERVICE_GROUP"; then print_status "✓ Created system group: $SERVICE_GROUP" else print_error "Failed to create group: $SERVICE_GROUP" exit 1 fi else print_status "✓ System group already exists: $SERVICE_GROUP" fi # Create user if not exists if ! getent passwd "$SERVICE_USER" >/dev/null 2>&1; then print_status "Creating system user: $SERVICE_USER" if useradd --system \ --no-create-home \ --gid "$SERVICE_GROUP" \ --shell /bin/false \ --comment "PulseGrid Metric Agent Service User" \ "$SERVICE_USER"; then print_status "✓ Created system user: $SERVICE_USER" else print_error "Failed to create user: $SERVICE_USER" exit 1 fi else print_status "✓ System user already exists: $SERVICE_USER" fi # ============================================================================= # CREATE DIRECTORIES # ============================================================================= print_step "Creating directories..." # Create config directory if [ ! -d "$CONFIG_DIR" ]; then if mkdir -p "$CONFIG_DIR"; then print_status "✓ Created config directory: $CONFIG_DIR" else print_error "Failed to create config directory: $CONFIG_DIR" exit 1 fi else print_status "✓ Config directory already exists: $CONFIG_DIR" fi # Create data directory if [ ! -d "$DATA_DIR" ]; then if mkdir -p "$DATA_DIR"; then print_status "✓ Created data directory: $DATA_DIR" else print_error "Failed to create data directory: $DATA_DIR" exit 1 fi else print_status "✓ Data directory already exists: $DATA_DIR" fi # Set ownership if chown "$SERVICE_USER:$SERVICE_GROUP" "$CONFIG_DIR"; then print_status "✓ Set config directory ownership" else print_error "Failed to set config directory ownership" exit 1 fi if chown "$SERVICE_USER:$SERVICE_GROUP" "$DATA_DIR"; then print_status "✓ Set data directory ownership" else print_error "Failed to set data directory ownership" exit 1 fi # Set permissions chmod 750 "$CONFIG_DIR" chmod 750 "$DATA_DIR" # ============================================================================= # DOWNLOAD AND INSTALL AGENT # ============================================================================= print_step "Downloading and installing agent..." # Create temporary directory temp_dir=$(mktemp -d) cd "$temp_dir" # Download agent download_url="$AGENT_DOWNLOAD_URL/$AGENT_BINARY_NAME" print_status "Downloading agent from: $download_url" print_status "This may take a few moments depending on your internet connection..." if ! curl -fsSL --retry 3 --connect-timeout 30 "$download_url" -o "$AGENT_BINARY_NAME"; then print_error "Failed to download the agent" print_error "Possible reasons:" print_error " - No internet connection" print_error " - Server is temporarily unavailable" print_error " - Firewall is blocking the connection" print_error "Please check your internet connection and try again" cd / rm -rf "$temp_dir" exit 1 fi print_status "✓ Agent downloaded successfully" # Extract archive print_status "Extracting downloaded agent package..." if ! tar -xzf "$AGENT_BINARY_NAME"; then print_error "Failed to extract the agent package" print_error "The downloaded file may be corrupted" cd / rm -rf "$temp_dir" exit 1 fi print_status "✓ Agent package extracted successfully" # Debug: List extracted files print_status "Extracted files:" ls -la # Check if the binary was extracted print_status "Looking for binary: $AGENT_EXTRACTED_BINARY" if [ ! -f "$AGENT_EXTRACTED_BINARY" ]; then print_error "Agent binary not found in the downloaded package" print_error "Expected file: $AGENT_EXTRACTED_BINARY" print_error "Available files:" ls -la cd / rm -rf "$temp_dir" exit 1 fi print_status "✓ Found binary: $AGENT_EXTRACTED_BINARY" # Install binary (only if not exists) if [ ! -f "$BINARY_DIR/pulsegrid-metric-agent" ]; then if cp "$AGENT_EXTRACTED_BINARY" "$BINARY_DIR/pulsegrid-metric-agent"; then chmod +x "$BINARY_DIR/pulsegrid-metric-agent" chown root:root "$BINARY_DIR/pulsegrid-metric-agent" print_status "✓ Agent binary installed to: $BINARY_DIR/pulsegrid-metric-agent" else print_error "Failed to install agent binary" cd / rm -rf "$temp_dir" exit 1 fi else print_status "✓ Agent binary already exists: $BINARY_DIR/pulsegrid-metric-agent" fi # Copy config.yaml from archive (only if not exists) if [ -f "config.yaml" ] && [ ! -f "$CONFIG_DIR/config.yaml" ]; then if cp "config.yaml" "$CONFIG_DIR/config.yaml"; then chmod 644 "$CONFIG_DIR/config.yaml" chown "$SERVICE_USER:$SERVICE_GROUP" "$CONFIG_DIR/config.yaml" print_status "✓ Agent config installed to: $CONFIG_DIR/config.yaml" else print_error "Failed to install config file" cd / rm -rf "$temp_dir" exit 1 fi elif [ -f "config/config.yaml" ] && [ ! -f "$CONFIG_DIR/config.yaml" ]; then # Fallback for archive with config subdirectory if cp "config/config.yaml" "$CONFIG_DIR/config.yaml"; then chmod 644 "$CONFIG_DIR/config.yaml" chown "$SERVICE_USER:$SERVICE_GROUP" "$CONFIG_DIR/config.yaml" print_status "✓ Agent config installed to: $CONFIG_DIR/config.yaml" else print_error "Failed to install config file" cd / rm -rf "$temp_dir" exit 1 fi else print_status "✓ Agent config already exists or not found in archive" fi # Clean up temporary directory cd / rm -rf "$temp_dir" # ============================================================================= # CREATE CONFIGURATION FILES # ============================================================================= print_step "Creating configuration files..." # Create UUID file (only if not exists) if [ ! -f "$CONFIG_DIR/.uuid" ]; then if echo "$USER_UUID" > "$CONFIG_DIR/.uuid"; then chmod 600 "$CONFIG_DIR/.uuid" chown "$SERVICE_USER:$SERVICE_GROUP" "$CONFIG_DIR/.uuid" print_status "✓ Created UUID file" else print_error "Failed to create UUID file" exit 1 fi else print_status "✓ UUID file already exists" fi # Create token file (only if not exists) if [ ! -f "$CONFIG_DIR/.token" ]; then if echo "$AGENT_TOKEN" > "$CONFIG_DIR/.token"; then chmod 600 "$CONFIG_DIR/.token" chown "$SERVICE_USER:$SERVICE_GROUP" "$CONFIG_DIR/.token" print_status "✓ Created token file" else print_error "Failed to create token file" exit 1 fi else print_status "✓ Token file already exists" fi print_status "✓ Configuration files ready" # ============================================================================= # CREATE SYSTEMD SERVICE # ============================================================================= print_step "Creating systemd service..." service_file="/etc/systemd/system/$SERVICE_NAME.service" # Check if service already exists if [ -f "$service_file" ]; then print_status "✓ Systemd service already exists: $service_file" else # Create service content cat > "$service_file" << EOF [Unit] Description=PulseGrid Metric Agent After=network-online.target Wants=network-online.target [Service] Type=simple User=$SERVICE_USER Group=$SERVICE_GROUP ExecStart=$BINARY_DIR/pulsegrid-metric-agent -config $CONFIG_DIR/config.yaml Restart=always RestartSec=300 StandardOutput=journal StandardError=journal SyslogIdentifier=pulsegrid-metric-agent # Security settings NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true ReadWritePaths=$CONFIG_DIR $DATA_DIR ReadOnlyPaths=/proc /sys /run/udev/data # Resource limits LimitNOFILE=65536 LimitNPROC=4096 # Environment variables Environment=HOME=$CONFIG_DIR [Install] WantedBy=multi-user.target EOF if [ $? -eq 0 ]; then print_status "✓ Systemd service created: $service_file" else print_error "Failed to create systemd service file" exit 1 fi fi # Reload systemd if systemctl daemon-reload; then print_status "✓ Systemd daemon reloaded" else print_error "Failed to reload systemd daemon" exit 1 fi # ============================================================================= # START AND ENABLE SERVICE # ============================================================================= print_step "Starting and enabling service..." # Enable service if systemctl enable "$SERVICE_NAME"; then print_status "✓ Service enabled for auto-start" else print_error "Failed to enable service" exit 1 fi # Start service if systemctl start "$SERVICE_NAME"; then print_status "✓ Service started successfully" else print_error "Failed to start service" exit 1 fi # ============================================================================= # SUCCESS MESSAGE # ============================================================================= print_success "PulseGrid Metric Agent installation completed successfully!" # Display ASCII art echo echo " ██████╗ ██╗ ██╗██╗ ███████╗███████╗ ██████╗ ██████╗ ██╗██████╗ " echo " ██╔══██╗██║ ██║██║ ██╔════╝██╔════╝██╔════╝ ██╔══██╗██║██╔══██╗ " echo " ██████╔╝██║ ██║██║ ███████╗█████╗ ██║ ███╗██████╔╝██║██║ ██║ " echo " ██╔═══╝ ██║ ██║██║ ╚════██║██╔══╝ ██║ ██║██╔══██╗██║██║ ██║ " echo " ██║ ╚██████╔╝███████╗███████║███████╗╚██████╔╝██║ ██║██║██████╔╝ " echo " ╚═╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═════╝ " echo " " echo " ███╗ ███╗███████╗████████╗██████╗ ██╗ ██████╗ █████╗ ██████╗ ███████╗███╗ ██╗████████╗" echo " ████╗ ████║██╔════╝╚══██╔══╝██╔══██╗██║██╔════╝ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝" echo " ██╔████╔██║█████╗ ██║ ██████╔╝██║██║ ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║" echo " ██║╚██╔╝██║██╔══╝ ██║ ██╔══██╗██║██║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║" echo " ██║ ╚═╝ ██║███████╗ ██║ ██║ ██║██║╚██████╗ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║" echo " ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝" echo echo " ════════════════════════════════════════════════════════════════════════════════════════════════" echo " 🎉 SUCCESSFULLY INSTALLED! 🎉" echo " ════════════════════════════════════════════════════════════════════════════════════════════════" echo echo " 🛠️ PulseGrid Metric Agent is now installed and running!" echo echo " 📁 Installation Details:" echo " • Binary: $BINARY_DIR/pulsegrid-metric-agent" echo " • Config: $CONFIG_DIR" echo " • Data: $DATA_DIR" echo " • Service: $SERVICE_NAME" echo echo " 🚀 Service Status:" echo " • Status: Active and running" echo " • Auto-start: Enabled" echo echo " ════════════════════════════════════════════════════════════════════════════════════════════════" echo " 🎯 Installation completed successfully! 🎯" echo " ════════════════════════════════════════════════════════════════════════════════════════════════" echo