new binary for alpie apk support

This commit is contained in:
Muhammad Ibrahim
2025-11-11 12:42:00 +00:00
parent 9857d7cdfc
commit ab700a3bc8
10 changed files with 124 additions and 396 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,31 +1,6 @@
#!/bin/sh #!/bin/sh
# PatchMon Agent Installation Script # PatchMon Agent Installation Script
# This script requires bash for full functionality # POSIX-compliant shell script (works with dash, ash, bash, etc.)
# Usage: curl -s {PATCHMON_URL}/api/v1/hosts/install -H "X-API-ID: {API_ID}" -H "X-API-KEY: {API_KEY}" | sh
# Check if bash is available, if not try to install it (for Alpine Linux)
if ! command -v bash >/dev/null 2>&1; then
if command -v apk >/dev/null 2>&1; then
echo "Installing bash for script compatibility..."
apk add --no-cache bash >/dev/null 2>&1 || true
fi
fi
# If bash is available and we're not already running in bash, switch to bash
# When piped, we can't re-execute easily, so we'll continue with sh
# but ensure bash is available for bash-specific features
if command -v bash >/dev/null 2>&1 && [ -z "${BASH_VERSION:-}" ]; then
# Check if we're being piped (stdin is not a terminal)
if [ -t 0 ]; then
# Direct execution, re-execute with bash
exec bash "$0" "$@"
exit $?
fi
# When piped, we continue with sh but bash is now available
# The script will use bash-specific features which should work if bash is installed
fi
# PatchMon Agent Installation Script
# Usage: curl -s {PATCHMON_URL}/api/v1/hosts/install -H "X-API-ID: {API_ID}" -H "X-API-KEY: {API_KEY}" | sh # Usage: curl -s {PATCHMON_URL}/api/v1/hosts/install -H "X-API-ID: {API_ID}" -H "X-API-KEY: {API_KEY}" | sh
set -e set -e
@@ -44,20 +19,20 @@ NC='\033[0m' # No Color
# Functions # Functions
error() { error() {
echo -e "${RED}❌ ERROR: $1${NC}" >&2 printf "%b\n" "${RED}❌ ERROR: $1${NC}" >&2
exit 1 exit 1
} }
info() { info() {
echo -e "${BLUE} $1${NC}" printf "%b\n" "${BLUE} $1${NC}"
} }
success() { success() {
echo -e "${GREEN}$1${NC}" printf "%b\n" "${GREEN}$1${NC}"
} }
warning() { warning() {
echo -e "${YELLOW}⚠️ $1${NC}" printf "%b\n" "${YELLOW}⚠️ $1${NC}"
} }
# Check if running as root # Check if running as root
@@ -75,7 +50,7 @@ verify_datetime() {
# Display current datetime info # Display current datetime info
echo "" echo ""
echo -e "${BLUE}📅 Current System Date/Time:${NC}" printf "%b\n" "${BLUE}📅 Current System Date/Time:${NC}"
echo " • Date/Time: $system_time" echo " • Date/Time: $system_time"
echo " • Timezone: $timezone" echo " • Timezone: $timezone"
echo "" echo ""
@@ -93,20 +68,20 @@ verify_datetime() {
;; ;;
*) *)
echo "" echo ""
echo -e "${RED}❌ Date/time verification failed${NC}" printf "%b\n" "${RED}❌ Date/time verification failed${NC}"
echo "" echo ""
echo -e "${YELLOW}💡 Please fix the date/time and re-run the installation script:${NC}" printf "%b\n" "${YELLOW}💡 Please fix the date/time and re-run the installation script:${NC}"
echo " sudo timedatectl set-time 'YYYY-MM-DD HH:MM:SS'" echo " sudo timedatectl set-time 'YYYY-MM-DD HH:MM:SS'"
echo " sudo timedatectl set-timezone 'America/New_York' # or your timezone" echo " sudo timedatectl set-timezone 'America/New_York' # or your timezone"
echo " sudo timedatectl list-timezones # to see available timezones" echo " sudo timedatectl list-timezones # to see available timezones"
echo "" echo ""
echo -e "${BLUE} After fixing the date/time, re-run this installation script.${NC}" printf "%b\n" "${BLUE} After fixing the date/time, re-run this installation script.${NC}"
error "Installation cancelled - please fix date/time and re-run" error "Installation cancelled - please fix date/time and re-run"
;; ;;
esac esac
else else
# Non-interactive (piped from curl) - show warning and continue # Non-interactive (piped from curl) - show warning and continue
echo -e "${YELLOW}⚠️ Non-interactive installation detected${NC}" printf "%b\n" "${YELLOW}⚠️ Non-interactive installation detected${NC}"
echo "" echo ""
echo "Please verify the date/time shown above is correct." echo "Please verify the date/time shown above is correct."
echo "If the date/time is incorrect, it may cause issues with:" echo "If the date/time is incorrect, it may cause issues with:"
@@ -114,7 +89,7 @@ verify_datetime() {
echo " • Scheduled updates" echo " • Scheduled updates"
echo " • Data synchronization" echo " • Data synchronization"
echo "" echo ""
echo -e "${GREEN}✅ Continuing with installation...${NC}" printf "%b\n" "${GREEN}✅ Continuing with installation...${NC}"
success "✅ Date/time verification completed (assumed correct)" success "✅ Date/time verification completed (assumed correct)"
echo "" echo ""
fi fi
@@ -211,17 +186,17 @@ export MACHINE_ID
info "🚀 Starting PatchMon Agent Installation..." info "🚀 Starting PatchMon Agent Installation..."
info "📋 Server: $PATCHMON_URL" info "📋 Server: $PATCHMON_URL"
info "🔑 API ID: ${API_ID:0:16}..." info "🔑 API ID: $(echo "$API_ID" | cut -c1-16)..."
info "🆔 Machine ID: ${MACHINE_ID:0:16}..." info "🆔 Machine ID: $(echo "$MACHINE_ID" | cut -c1-16)..."
info "🏗️ Architecture: $ARCHITECTURE" info "🏗️ Architecture: $ARCHITECTURE"
# Display diagnostic information # Display diagnostic information
echo "" echo ""
echo -e "${BLUE}🔧 Installation Diagnostics:${NC}" printf "%b\n" "${BLUE}🔧 Installation Diagnostics:${NC}"
echo " • URL: $PATCHMON_URL" echo " • URL: $PATCHMON_URL"
echo " • CURL FLAGS: $CURL_FLAGS" echo " • CURL FLAGS: $CURL_FLAGS"
echo " • API ID: ${API_ID:0:16}..." echo " • API ID: $(echo "$API_ID" | cut -c1-16)..."
echo " • API Key: ${API_KEY:0:16}..." echo " • API Key: $(echo "$API_KEY" | cut -c1-16)..."
echo " • Architecture: $ARCHITECTURE" echo " • Architecture: $ARCHITECTURE"
echo "" echo ""
@@ -236,52 +211,56 @@ command_exists() {
# Function to install packages with error handling # Function to install packages with error handling
install_apt_packages() { install_apt_packages() {
local packages=("$@") # Space-separated list of packages
local missing_packages=() _packages="$*"
_missing_packages=""
# Check which packages are missing # Check which packages are missing
for pkg in "${packages[@]}"; do for pkg in $_packages; do
if ! command_exists "$pkg"; then if ! command_exists "$pkg"; then
missing_packages+=("$pkg") _missing_packages="$_missing_packages $pkg"
fi fi
done done
if [ ${#missing_packages[@]} -eq 0 ]; then # Trim leading space
_missing_packages=$(echo "$_missing_packages" | sed 's/^ //')
if [ -z "$_missing_packages" ]; then
success "All required packages are already installed" success "All required packages are already installed"
return 0 return 0
fi fi
info "Need to install: ${missing_packages[*]}" info "Need to install: $_missing_packages"
# Build apt-get command based on force mode # Build apt-get command based on force mode
local apt_cmd="apt-get install ${missing_packages[*]} -y" _apt_cmd="apt-get install $_missing_packages -y"
if [ "$FORCE_INSTALL" = "true" ]; then if [ "$FORCE_INSTALL" = "true" ]; then
info "Using force mode - bypassing broken packages..." info "Using force mode - bypassing broken packages..."
apt_cmd="$apt_cmd -o APT::Get::Fix-Broken=false -o DPkg::Options::=\"--force-confold\" -o DPkg::Options::=\"--force-confdef\"" _apt_cmd="$_apt_cmd -o APT::Get::Fix-Broken=false -o DPkg::Options::=\"--force-confold\" -o DPkg::Options::=\"--force-confdef\""
fi fi
# Try to install packages # Try to install packages
if eval "$apt_cmd" 2>&1 | tee /tmp/patchmon_apt_install.log; then if eval "$_apt_cmd" 2>&1 | tee /tmp/patchmon_apt_install.log; then
success "Packages installed successfully" success "Packages installed successfully"
return 0 return 0
else else
warning "Package installation encountered issues, checking if required tools are available..." warning "Package installation encountered issues, checking if required tools are available..."
# Verify critical dependencies are actually available # Verify critical dependencies are actually available
local all_ok=true _all_ok=true
for pkg in "${packages[@]}"; do for pkg in $_packages; do
if ! command_exists "$pkg"; then if ! command_exists "$pkg"; then
if [ "$FORCE_INSTALL" = "true" ]; then if [ "$FORCE_INSTALL" = "true" ]; then
error "Critical dependency '$pkg' is not available even with --force. Please install manually." error "Critical dependency '$pkg' is not available even with --force. Please install manually."
else else
error "Critical dependency '$pkg' is not available. Try again with --force flag or install manually: apt-get install $pkg" error "Critical dependency '$pkg' is not available. Try again with --force flag or install manually: apt-get install $pkg"
fi fi
all_ok=false _all_ok=false
fi fi
done done
if $all_ok; then if $_all_ok; then
success "All required tools are available despite installation warnings" success "All required tools are available despite installation warnings"
return 0 return 0
else else
@@ -292,121 +271,133 @@ install_apt_packages() {
# Function to check and install packages for yum/dnf # Function to check and install packages for yum/dnf
install_yum_dnf_packages() { install_yum_dnf_packages() {
local pkg_manager="$1" _pkg_manager="$1"
shift shift
local packages=("$@") _packages="$*"
local missing_packages=() _missing_packages=""
# Check which packages are missing # Check which packages are missing
for pkg in "${packages[@]}"; do for pkg in $_packages; do
if ! command_exists "$pkg"; then if ! command_exists "$pkg"; then
missing_packages+=("$pkg") _missing_packages="$_missing_packages $pkg"
fi fi
done done
if [ ${#missing_packages[@]} -eq 0 ]; then # Trim leading space
_missing_packages=$(echo "$_missing_packages" | sed 's/^ //')
if [ -z "$_missing_packages" ]; then
success "All required packages are already installed" success "All required packages are already installed"
return 0 return 0
fi fi
info "Need to install: ${missing_packages[*]}" info "Need to install: $_missing_packages"
if [ "$pkg_manager" = "yum" ]; then if [ "$_pkg_manager" = "yum" ]; then
yum install -y "${missing_packages[@]}" yum install -y $_missing_packages
else else
dnf install -y "${missing_packages[@]}" dnf install -y $_missing_packages
fi fi
} }
# Function to check and install packages for zypper # Function to check and install packages for zypper
install_zypper_packages() { install_zypper_packages() {
local packages=("$@") _packages="$*"
local missing_packages=() _missing_packages=""
# Check which packages are missing # Check which packages are missing
for pkg in "${packages[@]}"; do for pkg in $_packages; do
if ! command_exists "$pkg"; then if ! command_exists "$pkg"; then
missing_packages+=("$pkg") _missing_packages="$_missing_packages $pkg"
fi fi
done done
if [ ${#missing_packages[@]} -eq 0 ]; then # Trim leading space
_missing_packages=$(echo "$_missing_packages" | sed 's/^ //')
if [ -z "$_missing_packages" ]; then
success "All required packages are already installed" success "All required packages are already installed"
return 0 return 0
fi fi
info "Need to install: ${missing_packages[*]}" info "Need to install: $_missing_packages"
zypper install -y "${missing_packages[@]}" zypper install -y $_missing_packages
} }
# Function to check and install packages for pacman # Function to check and install packages for pacman
install_pacman_packages() { install_pacman_packages() {
local packages=("$@") _packages="$*"
local missing_packages=() _missing_packages=""
# Check which packages are missing # Check which packages are missing
for pkg in "${packages[@]}"; do for pkg in $_packages; do
if ! command_exists "$pkg"; then if ! command_exists "$pkg"; then
missing_packages+=("$pkg") _missing_packages="$_missing_packages $pkg"
fi fi
done done
if [ ${#missing_packages[@]} -eq 0 ]; then # Trim leading space
_missing_packages=$(echo "$_missing_packages" | sed 's/^ //')
if [ -z "$_missing_packages" ]; then
success "All required packages are already installed" success "All required packages are already installed"
return 0 return 0
fi fi
info "Need to install: ${missing_packages[*]}" info "Need to install: $_missing_packages"
pacman -S --noconfirm "${missing_packages[@]}" pacman -S --noconfirm $_missing_packages
} }
# Function to check and install packages for apk # Function to check and install packages for apk
install_apk_packages() { install_apk_packages() {
local packages=("$@") _packages="$*"
local missing_packages=() _missing_packages=""
# Check which packages are missing # Check which packages are missing
for pkg in "${packages[@]}"; do for pkg in $_packages; do
if ! command_exists "$pkg"; then if ! command_exists "$pkg"; then
missing_packages+=("$pkg") _missing_packages="$_missing_packages $pkg"
fi fi
done done
if [ ${#missing_packages[@]} -eq 0 ]; then # Trim leading space
_missing_packages=$(echo "$_missing_packages" | sed 's/^ //')
if [ -z "$_missing_packages" ]; then
success "All required packages are already installed" success "All required packages are already installed"
return 0 return 0
fi fi
info "Need to install: ${missing_packages[*]}" info "Need to install: $_missing_packages"
# Update package index before installation # Update package index before installation
info "Updating package index..." info "Updating package index..."
apk update -q || true apk update -q || true
# Build apk command # Build apk command
local apk_cmd="apk add --no-cache ${missing_packages[*]}" _apk_cmd="apk add --no-cache $_missing_packages"
# Try to install packages # Try to install packages
if eval "$apk_cmd" 2>&1 | tee /tmp/patchmon_apk_install.log; then if eval "$_apk_cmd" 2>&1 | tee /tmp/patchmon_apk_install.log; then
success "Packages installed successfully" success "Packages installed successfully"
return 0 return 0
else else
warning "Package installation encountered issues, checking if required tools are available..." warning "Package installation encountered issues, checking if required tools are available..."
# Verify critical dependencies are actually available # Verify critical dependencies are actually available
local all_ok=true _all_ok=true
for pkg in "${packages[@]}"; do for pkg in $_packages; do
if ! command_exists "$pkg"; then if ! command_exists "$pkg"; then
if [ "$FORCE_INSTALL" = "true" ]; then if [ "$FORCE_INSTALL" = "true" ]; then
error "Critical dependency '$pkg' is not available even with --force. Please install manually." error "Critical dependency '$pkg' is not available even with --force. Please install manually."
else else
error "Critical dependency '$pkg' is not available. Try again with --force flag or install manually: apk add $pkg" error "Critical dependency '$pkg' is not available. Try again with --force flag or install manually: apk add $pkg"
fi fi
all_ok=false _all_ok=false
fi fi
done done
if $all_ok; then if $_all_ok; then
success "All required tools are available despite installation warnings" success "All required tools are available despite installation warnings"
return 0 return 0
else else
@@ -790,7 +781,7 @@ fi
# Installation complete # Installation complete
success "🎉 PatchMon Agent installation completed successfully!" success "🎉 PatchMon Agent installation completed successfully!"
echo "" echo ""
echo -e "${GREEN}📋 Installation Summary:${NC}" printf "%b\n" "${GREEN}📋 Installation Summary:${NC}"
echo " • Configuration directory: /etc/patchmon" echo " • Configuration directory: /etc/patchmon"
echo " • Agent binary installed: /usr/local/bin/patchmon-agent" echo " • Agent binary installed: /usr/local/bin/patchmon-agent"
echo " • Architecture: $ARCHITECTURE" echo " • Architecture: $ARCHITECTURE"
@@ -810,16 +801,16 @@ echo " • Logs directory: /etc/patchmon/logs"
MOVED_FILES=$(ls /etc/patchmon/credentials.yml.backup.* /etc/patchmon/config.yml.backup.* /usr/local/bin/patchmon-agent.backup.* /etc/patchmon/logs/patchmon-agent.log.old.* /usr/local/bin/patchmon-agent.sh.backup.* /etc/patchmon/credentials.backup.* 2>/dev/null || true) MOVED_FILES=$(ls /etc/patchmon/credentials.yml.backup.* /etc/patchmon/config.yml.backup.* /usr/local/bin/patchmon-agent.backup.* /etc/patchmon/logs/patchmon-agent.log.old.* /usr/local/bin/patchmon-agent.sh.backup.* /etc/patchmon/credentials.backup.* 2>/dev/null || true)
if [ -n "$MOVED_FILES" ]; then if [ -n "$MOVED_FILES" ]; then
echo "" echo ""
echo -e "${YELLOW}📋 Files Moved for Fresh Installation:${NC}" printf "%b\n" "${YELLOW}📋 Files Moved for Fresh Installation:${NC}"
echo "$MOVED_FILES" | while read -r moved_file; do echo "$MOVED_FILES" | while read -r moved_file; do
echo "$moved_file" echo "$moved_file"
done done
echo "" echo ""
echo -e "${BLUE}💡 Note: Old files are automatically cleaned up (keeping last 3)${NC}" printf "%b\n" "${BLUE}💡 Note: Old files are automatically cleaned up (keeping last 3)${NC}"
fi fi
echo "" echo ""
echo -e "${BLUE}🔧 Management Commands:${NC}" printf "%b\n" "${BLUE}🔧 Management Commands:${NC}"
echo " • Test connection: /usr/local/bin/patchmon-agent ping" echo " • Test connection: /usr/local/bin/patchmon-agent ping"
echo " • Manual report: /usr/local/bin/patchmon-agent report" echo " • Manual report: /usr/local/bin/patchmon-agent report"
echo " • Check status: /usr/local/bin/patchmon-agent diagnostics" echo " • Check status: /usr/local/bin/patchmon-agent diagnostics"

View File

@@ -1,7 +1,8 @@
#!/bin/bash #!/bin/sh
# PatchMon Agent Removal Script # PatchMon Agent Removal Script
# Usage: curl -s {PATCHMON_URL}/api/v1/hosts/remove | bash # POSIX-compliant shell script (works with dash, ash, bash, etc.)
# Usage: curl -s {PATCHMON_URL}/api/v1/hosts/remove | sh
# This script completely removes PatchMon from the system # This script completely removes PatchMon from the system
set -e set -e
@@ -20,24 +21,24 @@ NC='\033[0m' # No Color
# Functions # Functions
error() { error() {
echo -e "${RED}❌ ERROR: $1${NC}" >&2 printf "%b\n" "${RED}❌ ERROR: $1${NC}" >&2
exit 1 exit 1
} }
info() { info() {
echo -e "${BLUE} $1${NC}" printf "%b\n" "${BLUE} $1${NC}"
} }
success() { success() {
echo -e "${GREEN}$1${NC}" printf "%b\n" "${GREEN}$1${NC}"
} }
warning() { warning() {
echo -e "${YELLOW}⚠️ $1${NC}" printf "%b\n" "${YELLOW}⚠️ $1${NC}"
} }
# Check if running as root # Check if running as root
if [[ $EUID -ne 0 ]]; then if [ "$(id -u)" -ne 0 ]; then
error "This script must be run as root (use sudo)" error "This script must be run as root (use sudo)"
fi fi
@@ -67,7 +68,7 @@ fi
# Step 3: Remove agent script # Step 3: Remove agent script
info "📄 Removing agent script..." info "📄 Removing agent script..."
if [[ -f "/usr/local/bin/patchmon-agent.sh" ]]; then if [ -f "/usr/local/bin/patchmon-agent.sh" ]; then
warning "Removing agent script: /usr/local/bin/patchmon-agent.sh" warning "Removing agent script: /usr/local/bin/patchmon-agent.sh"
rm -f /usr/local/bin/patchmon-agent.sh rm -f /usr/local/bin/patchmon-agent.sh
success "Agent script removed" success "Agent script removed"
@@ -77,7 +78,7 @@ fi
# Step 4: Remove configuration directory and files # Step 4: Remove configuration directory and files
info "📁 Removing configuration files..." info "📁 Removing configuration files..."
if [[ -d "/etc/patchmon" ]]; then if [ -d "/etc/patchmon" ]; then
warning "Removing configuration directory: /etc/patchmon" warning "Removing configuration directory: /etc/patchmon"
# Show what's being removed # Show what's being removed
@@ -95,7 +96,7 @@ fi
# Step 5: Remove log files # Step 5: Remove log files
info "📝 Removing log files..." info "📝 Removing log files..."
if [[ -f "/var/log/patchmon-agent.log" ]]; then if [ -f "/var/log/patchmon-agent.log" ]; then
warning "Removing log file: /var/log/patchmon-agent.log" warning "Removing log file: /var/log/patchmon-agent.log"
rm -f /var/log/patchmon-agent.log rm -f /var/log/patchmon-agent.log
success "Log file removed" success "Log file removed"
@@ -109,29 +110,29 @@ BACKUP_COUNT=0
# Count credential backups # Count credential backups
CRED_BACKUPS=$(ls /etc/patchmon/credentials.backup.* 2>/dev/null | wc -l || echo "0") CRED_BACKUPS=$(ls /etc/patchmon/credentials.backup.* 2>/dev/null | wc -l || echo "0")
if [[ $CRED_BACKUPS -gt 0 ]]; then if [ "$CRED_BACKUPS" -gt 0 ]; then
BACKUP_COUNT=$((BACKUP_COUNT + CRED_BACKUPS)) BACKUP_COUNT=$((BACKUP_COUNT + CRED_BACKUPS))
fi fi
# Count agent backups # Count agent backups
AGENT_BACKUPS=$(ls /usr/local/bin/patchmon-agent.sh.backup.* 2>/dev/null | wc -l || echo "0") AGENT_BACKUPS=$(ls /usr/local/bin/patchmon-agent.sh.backup.* 2>/dev/null | wc -l || echo "0")
if [[ $AGENT_BACKUPS -gt 0 ]]; then if [ "$AGENT_BACKUPS" -gt 0 ]; then
BACKUP_COUNT=$((BACKUP_COUNT + AGENT_BACKUPS)) BACKUP_COUNT=$((BACKUP_COUNT + AGENT_BACKUPS))
fi fi
# Count log backups # Count log backups
LOG_BACKUPS=$(ls /var/log/patchmon-agent.log.old.* 2>/dev/null | wc -l || echo "0") LOG_BACKUPS=$(ls /var/log/patchmon-agent.log.old.* 2>/dev/null | wc -l || echo "0")
if [[ $LOG_BACKUPS -gt 0 ]]; then if [ "$LOG_BACKUPS" -gt 0 ]; then
BACKUP_COUNT=$((BACKUP_COUNT + LOG_BACKUPS)) BACKUP_COUNT=$((BACKUP_COUNT + LOG_BACKUPS))
fi fi
if [[ $BACKUP_COUNT -gt 0 ]]; then if [ "$BACKUP_COUNT" -gt 0 ]; then
warning "Found $BACKUP_COUNT backup files" warning "Found $BACKUP_COUNT backup files"
echo "" echo ""
echo -e "${YELLOW}📋 Backup files found:${NC}" printf "%b\n" "${YELLOW}📋 Backup files found:${NC}"
# Show credential backups # Show credential backups
if [[ $CRED_BACKUPS -gt 0 ]]; then if [ "$CRED_BACKUPS" -gt 0 ]; then
echo " Credential backups:" echo " Credential backups:"
ls /etc/patchmon/credentials.backup.* 2>/dev/null | while read -r file; do ls /etc/patchmon/credentials.backup.* 2>/dev/null | while read -r file; do
echo "$file" echo "$file"
@@ -139,7 +140,7 @@ if [[ $BACKUP_COUNT -gt 0 ]]; then
fi fi
# Show agent backups # Show agent backups
if [[ $AGENT_BACKUPS -gt 0 ]]; then if [ "$AGENT_BACKUPS" -gt 0 ]; then
echo " Agent script backups:" echo " Agent script backups:"
ls /usr/local/bin/patchmon-agent.sh.backup.* 2>/dev/null | while read -r file; do ls /usr/local/bin/patchmon-agent.sh.backup.* 2>/dev/null | while read -r file; do
echo "$file" echo "$file"
@@ -147,7 +148,7 @@ if [[ $BACKUP_COUNT -gt 0 ]]; then
fi fi
# Show log backups # Show log backups
if [[ $LOG_BACKUPS -gt 0 ]]; then if [ "$LOG_BACKUPS" -gt 0 ]; then
echo " Log file backups:" echo " Log file backups:"
ls /var/log/patchmon-agent.log.old.* 2>/dev/null | while read -r file; do ls /var/log/patchmon-agent.log.old.* 2>/dev/null | while read -r file; do
echo "$file" echo "$file"
@@ -155,8 +156,8 @@ if [[ $BACKUP_COUNT -gt 0 ]]; then
fi fi
echo "" echo ""
echo -e "${BLUE}💡 Note: Backup files are preserved for safety${NC}" printf "%b\n" "${BLUE}💡 Note: Backup files are preserved for safety${NC}"
echo -e "${BLUE}💡 You can remove them manually if not needed${NC}" printf "%b\n" "${BLUE}💡 You can remove them manually if not needed${NC}"
else else
info "No backup files found" info "No backup files found"
fi fi
@@ -165,16 +166,16 @@ fi
info "📦 Checking for PatchMon-specific dependencies..." info "📦 Checking for PatchMon-specific dependencies..."
if command -v jq >/dev/null 2>&1; then if command -v jq >/dev/null 2>&1; then
warning "jq is installed (used by PatchMon)" warning "jq is installed (used by PatchMon)"
echo -e "${BLUE}💡 Note: jq may be used by other applications${NC}" printf "%b\n" "${BLUE}💡 Note: jq may be used by other applications${NC}"
echo -e "${BLUE}💡 Consider keeping it unless you're sure it's not needed${NC}" printf "%b\n" "${BLUE}💡 Consider keeping it unless you're sure it's not needed${NC}"
else else
info "jq not found" info "jq not found"
fi fi
if command -v curl >/dev/null 2>&1; then if command -v curl >/dev/null 2>&1; then
warning "curl is installed (used by PatchMon)" warning "curl is installed (used by PatchMon)"
echo -e "${BLUE}💡 Note: curl is commonly used by many applications${NC}" printf "%b\n" "${BLUE}💡 Note: curl is commonly used by many applications${NC}"
echo -e "${BLUE}💡 Consider keeping it unless you're sure it's not needed${NC}" printf "%b\n" "${BLUE}💡 Consider keeping it unless you're sure it's not needed${NC}"
else else
info "curl not found" info "curl not found"
fi fi
@@ -183,15 +184,15 @@ fi
info "🔍 Verifying removal..." info "🔍 Verifying removal..."
REMAINING_FILES=0 REMAINING_FILES=0
if [[ -f "/usr/local/bin/patchmon-agent.sh" ]]; then if [ -f "/usr/local/bin/patchmon-agent.sh" ]; then
REMAINING_FILES=$((REMAINING_FILES + 1)) REMAINING_FILES=$((REMAINING_FILES + 1))
fi fi
if [[ -d "/etc/patchmon" ]]; then if [ -d "/etc/patchmon" ]; then
REMAINING_FILES=$((REMAINING_FILES + 1)) REMAINING_FILES=$((REMAINING_FILES + 1))
fi fi
if [[ -f "/var/log/patchmon-agent.log" ]]; then if [ -f "/var/log/patchmon-agent.log" ]; then
REMAINING_FILES=$((REMAINING_FILES + 1)) REMAINING_FILES=$((REMAINING_FILES + 1))
fi fi
@@ -199,15 +200,15 @@ if crontab -l 2>/dev/null | grep -q "patchmon-agent.sh"; then
REMAINING_FILES=$((REMAINING_FILES + 1)) REMAINING_FILES=$((REMAINING_FILES + 1))
fi fi
if [[ $REMAINING_FILES -eq 0 ]]; then if [ "$REMAINING_FILES" -eq 0 ]; then
success "✅ PatchMon has been completely removed from the system!" success "✅ PatchMon has been completely removed from the system!"
else else
warning "⚠️ Some PatchMon files may still remain ($REMAINING_FILES items)" warning "⚠️ Some PatchMon files may still remain ($REMAINING_FILES items)"
echo -e "${BLUE}💡 You may need to remove them manually${NC}" printf "%b\n" "${BLUE}💡 You may need to remove them manually${NC}"
fi fi
echo "" echo ""
echo -e "${GREEN}📋 Removal Summary:${NC}" printf "%b\n" "${GREEN}📋 Removal Summary:${NC}"
echo " • Agent script: Removed" echo " • Agent script: Removed"
echo " • Configuration files: Removed" echo " • Configuration files: Removed"
echo " • Log files: Removed" echo " • Log files: Removed"
@@ -215,7 +216,7 @@ echo " • Crontab entries: Removed"
echo " • Running processes: Stopped" echo " • Running processes: Stopped"
echo " • Backup files: Preserved (if any)" echo " • Backup files: Preserved (if any)"
echo "" echo ""
echo -e "${BLUE}🔧 Manual cleanup (if needed):${NC}" printf "%b\n" "${BLUE}🔧 Manual cleanup (if needed):${NC}"
echo " • Remove backup files: rm /etc/patchmon/credentials.backup.* /usr/local/bin/patchmon-agent.sh.backup.* /var/log/patchmon-agent.log.old.*" echo " • Remove backup files: rm /etc/patchmon/credentials.backup.* /usr/local/bin/patchmon-agent.sh.backup.* /var/log/patchmon-agent.log.old.*"
echo " • Remove dependencies: apt remove jq curl (if not needed by other apps)" echo " • Remove dependencies: apt remove jq curl (if not needed by other apps)"
echo "" echo ""

View File

@@ -567,7 +567,7 @@ router.get("/proxmox-lxc", async (req, res) => {
const force_install = req.query.force === "true" || req.query.force === "1"; const force_install = req.query.force === "true" || req.query.force === "1";
// Inject the token credentials, server URL, curl flags, and force flag into the script // Inject the token credentials, server URL, curl flags, and force flag into the script
const env_vars = `#!/bin/bash const env_vars = `#!/bin/sh
# PatchMon Auto-Enrollment Configuration (Auto-generated) # PatchMon Auto-Enrollment Configuration (Auto-generated)
export PATCHMON_URL="${server_url}" export PATCHMON_URL="${server_url}"
export AUTO_ENROLLMENT_KEY="${token.token_key}" export AUTO_ENROLLMENT_KEY="${token.token_key}"

View File

@@ -1682,7 +1682,7 @@ router.get("/install", async (req, res) => {
const archExport = architecture const archExport = architecture
? `export ARCHITECTURE="${architecture}"\n` ? `export ARCHITECTURE="${architecture}"\n`
: ""; : "";
const envVars = `#!/bin/bash const envVars = `#!/bin/sh
export PATCHMON_URL="${serverUrl}" export PATCHMON_URL="${serverUrl}"
export API_ID="${host.api_id}" export API_ID="${host.api_id}"
export API_KEY="${host.api_key}" export API_KEY="${host.api_key}"
@@ -1781,7 +1781,7 @@ router.get("/remove", async (_req, res) => {
} catch (_) {} } catch (_) {}
// Prepend environment for CURL_FLAGS so script can use it if needed // Prepend environment for CURL_FLAGS so script can use it if needed
const envPrefix = `#!/bin/bash\nexport CURL_FLAGS="${curlFlags}"\n\n`; const envPrefix = `#!/bin/sh\nexport CURL_FLAGS="${curlFlags}"\n\n`;
script = script.replace(/^#!/, "#"); script = script.replace(/^#!/, "#");
script = envPrefix + script; script = envPrefix + script;

View File

@@ -1817,7 +1817,7 @@ const CredentialsModal = ({ host, isOpen, onClose }) => {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<input <input
type="text" type="text"
value={`curl ${getCurlFlags()} ${getInstallUrl()} -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" | bash`} value={`curl ${getCurlFlags()} ${getInstallUrl()} -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" | sh`}
readOnly readOnly
className="flex-1 px-3 py-2 border border-primary-300 dark:border-primary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white" className="flex-1 px-3 py-2 border border-primary-300 dark:border-primary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/> />
@@ -1825,7 +1825,7 @@ const CredentialsModal = ({ host, isOpen, onClose }) => {
type="button" type="button"
onClick={() => onClick={() =>
copyToClipboard( copyToClipboard(
`curl ${getCurlFlags()} ${getInstallUrl()} -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" | bash`, `curl ${getCurlFlags()} ${getInstallUrl()} -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" | sh`,
) )
} }
className="btn-primary flex items-center gap-1" className="btn-primary flex items-center gap-1"
@@ -1835,270 +1835,6 @@ const CredentialsModal = ({ host, isOpen, onClose }) => {
</button> </button>
</div> </div>
</div> </div>
<div className="bg-secondary-50 dark:bg-secondary-700 rounded-lg p-4">
<h4 className="text-sm font-medium text-secondary-900 dark:text-white mb-2">
Manual Installation
</h4>
<p className="text-sm text-secondary-600 dark:text-secondary-300 mb-3">
If you prefer to install manually, follow these steps:
</p>
<div className="space-y-3">
<div className="bg-white dark:bg-secondary-800 rounded-md p-3 border border-secondary-200 dark:border-secondary-600">
<h5 className="text-sm font-medium text-secondary-900 dark:text-white mb-2">
1. Create Configuration Directory
</h5>
<div className="flex items-center gap-2">
<input
type="text"
value="sudo mkdir -p /etc/patchmon"
readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/>
<button
type="button"
onClick={() =>
copyToClipboard("sudo mkdir -p /etc/patchmon")
}
className="btn-secondary flex items-center gap-1"
>
<Copy className="h-4 w-4" />
Copy
</button>
</div>
</div>
<div className="bg-white dark:bg-secondary-800 rounded-md p-3 border border-secondary-200 dark:border-secondary-600">
<h5 className="text-sm font-medium text-secondary-900 dark:text-white mb-2">
2. Download and Install Agent Binary
</h5>
<div className="flex items-center gap-2">
<input
type="text"
value={`curl ${getCurlFlags()} -o /usr/local/bin/patchmon-agent ${serverUrl}/api/v1/hosts/agent/download?arch=${architecture} -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" && sudo chmod +x /usr/local/bin/patchmon-agent`}
readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/>
<button
type="button"
onClick={() =>
copyToClipboard(
`curl ${getCurlFlags()} -o /usr/local/bin/patchmon-agent ${serverUrl}/api/v1/hosts/agent/download?arch=${architecture} -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" && sudo chmod +x /usr/local/bin/patchmon-agent`,
)
}
className="btn-secondary flex items-center gap-1"
>
<Copy className="h-4 w-4" />
Copy
</button>
</div>
</div>
<div className="bg-white dark:bg-secondary-800 rounded-md p-3 border border-secondary-200 dark:border-secondary-600">
<h5 className="text-sm font-medium text-secondary-900 dark:text-white mb-2">
3. Configure Credentials
</h5>
<div className="flex items-center gap-2">
<input
type="text"
value={`sudo /usr/local/bin/patchmon-agent config set-api "${host.api_id}" "${host.api_key}" "${serverUrl}"`}
readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/>
<button
type="button"
onClick={() =>
copyToClipboard(
`sudo /usr/local/bin/patchmon-agent config set-api "${host.api_id}" "${host.api_key}" "${serverUrl}"`,
)
}
className="btn-secondary flex items-center gap-1"
>
<Copy className="h-4 w-4" />
Copy
</button>
</div>
</div>
<div className="bg-white dark:bg-secondary-800 rounded-md p-3 border border-secondary-200 dark:border-secondary-600">
<h5 className="text-sm font-medium text-secondary-900 dark:text-white mb-2">
4. Test Configuration
</h5>
<div className="flex items-center gap-2">
<input
type="text"
value="sudo /usr/local/bin/patchmon-agent ping"
readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/>
<button
type="button"
onClick={() =>
copyToClipboard(
"sudo /usr/local/bin/patchmon-agent ping",
)
}
className="btn-secondary flex items-center gap-1"
>
<Copy className="h-4 w-4" />
Copy
</button>
</div>
</div>
<div className="bg-white dark:bg-secondary-800 rounded-md p-3 border border-secondary-200 dark:border-secondary-600">
<h5 className="text-sm font-medium text-secondary-900 dark:text-white mb-2">
5. Send Initial Data
</h5>
<div className="flex items-center gap-2">
<input
type="text"
value="sudo /usr/local/bin/patchmon-agent report"
readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/>
<button
type="button"
onClick={() =>
copyToClipboard(
"sudo /usr/local/bin/patchmon-agent report",
)
}
className="btn-secondary flex items-center gap-1"
>
<Copy className="h-4 w-4" />
Copy
</button>
</div>
</div>
<div className="bg-white dark:bg-secondary-800 rounded-md p-3 border border-secondary-200 dark:border-secondary-600">
<h5 className="text-sm font-medium text-secondary-900 dark:text-white mb-2">
6. Create Systemd Service File
</h5>
<div className="flex items-center gap-2">
<input
type="text"
value={`sudo tee /etc/systemd/system/patchmon-agent.service > /dev/null << 'EOF'
[Unit]
Description=PatchMon Agent Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/patchmon-agent serve
Restart=always
RestartSec=10
WorkingDirectory=/etc/patchmon
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=patchmon-agent
[Install]
WantedBy=multi-user.target
EOF`}
readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/>
<button
type="button"
onClick={() =>
copyToClipboard(
`sudo tee /etc/systemd/system/patchmon-agent.service > /dev/null << 'EOF'
[Unit]
Description=PatchMon Agent Service
After=network.target
Wants=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/patchmon-agent serve
Restart=always
RestartSec=10
WorkingDirectory=/etc/patchmon
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=patchmon-agent
[Install]
WantedBy=multi-user.target
EOF`,
)
}
className="btn-secondary flex items-center gap-1"
>
<Copy className="h-4 w-4" />
Copy
</button>
</div>
</div>
<div className="bg-white dark:bg-secondary-800 rounded-md p-3 border border-secondary-200 dark:border-secondary-600">
<h5 className="text-sm font-medium text-secondary-900 dark:text-white mb-2">
7. Enable and Start Service
</h5>
<div className="flex items-center gap-2">
<input
type="text"
value="sudo systemctl daemon-reload && sudo systemctl enable patchmon-agent && sudo systemctl start patchmon-agent"
readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/>
<button
type="button"
onClick={() =>
copyToClipboard(
"sudo systemctl daemon-reload && sudo systemctl enable patchmon-agent && sudo systemctl start patchmon-agent",
)
}
className="btn-secondary flex items-center gap-1"
>
<Copy className="h-4 w-4" />
Copy
</button>
</div>
<p className="text-xs text-secondary-600 dark:text-secondary-400 mt-2">
This will start the agent service and establish WebSocket
connection for real-time communication
</p>
</div>
<div className="bg-white dark:bg-secondary-800 rounded-md p-3 border border-secondary-200 dark:border-secondary-600">
<h5 className="text-sm font-medium text-secondary-900 dark:text-white mb-2">
8. Verify Service Status
</h5>
<div className="flex items-center gap-2">
<input
type="text"
value="sudo systemctl status patchmon-agent"
readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/>
<button
type="button"
onClick={() =>
copyToClipboard("sudo systemctl status patchmon-agent")
}
className="btn-secondary flex items-center gap-1"
>
<Copy className="h-4 w-4" />
Copy
</button>
</div>
<p className="text-xs text-secondary-600 dark:text-secondary-400 mt-2">
Check that the service is running and WebSocket connection
is established
</p>
</div>
</div>
</div>
</div> </div>
)} )}

View File

@@ -1669,7 +1669,7 @@ const Integrations = () => {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<input <input
type="text" type="text"
value={`curl -s "${getProxmoxUrl()}" | bash`} value={`curl -s "${getProxmoxUrl()}" | sh`}
readOnly readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-secondary-50 dark:bg-secondary-900 text-secondary-900 dark:text-white font-mono text-xs" className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-secondary-50 dark:bg-secondary-900 text-secondary-900 dark:text-white font-mono text-xs"
/> />
@@ -1677,7 +1677,7 @@ const Integrations = () => {
type="button" type="button"
onClick={() => onClick={() =>
copy_to_clipboard( copy_to_clipboard(
`curl -s "${getProxmoxUrl()}" | bash`, `curl -s "${getProxmoxUrl()}" | sh`,
"curl-command", "curl-command",
) )
} }