Created
June 11, 2025 17:20
-
-
Save mujdat/dee14ae3d99f7812a4fcc9cc0d450270 to your computer and use it in GitHub Desktop.
Portiyer Helper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Fail on any error | |
| set -e | |
| # Make sure we have three arguments | |
| if [ $# -ne 3 ]; then | |
| echo "Usage: $0 <SERVER_ID> <ACCESS_TOKEN> <BACKEND_URL>" | |
| exit 1 | |
| fi | |
| SERVER_ID="$1" | |
| ACCESS_TOKEN="$2" | |
| BACKEND_URL="$3" | |
| echo "Installing dstat and setting up collector script..." | |
| echo "Server ID: $SERVER_ID" | |
| echo "Backend URL: $BACKEND_URL" | |
| # Ask for confirmation before proceeding | |
| read -p "Do you want to install dstat and set up monitoring? (y/N) " choice | |
| case "$choice" in | |
| y|Y ) echo "Proceeding...";; | |
| * ) echo "Installation aborted."; exit 1;; | |
| esac | |
| # 1) Detect distro and install dstat | |
| if [ -f /etc/debian_version ]; then | |
| echo "Detected Debian/Ubuntu system." | |
| sudo apt-get update -y | |
| sudo apt-get install -y dstat | |
| elif [ -f /etc/redhat-release ]; then | |
| echo "Detected RHEL/CentOS/Fedora system." | |
| sudo yum install -y dstat | |
| else | |
| echo "Unsupported or unknown Linux distribution." | |
| exit 1 | |
| fi | |
| # 2) Create portiyer user if not exists | |
| if ! id "portiyer" &>/dev/null; then | |
| sudo useradd -r -s /bin/false portiyer | |
| fi | |
| # 3) Store credentials securely in /etc/portiyer.conf | |
| sudo tee /etc/portiyer.conf > /dev/null <<EOF | |
| SERVER_ID=${SERVER_ID} | |
| ACCESS_TOKEN=${ACCESS_TOKEN} | |
| BACKEND_URL=${BACKEND_URL} | |
| EOF | |
| # 4) Fix permissions for /etc/portiyer.conf | |
| sudo chown portiyer:portiyer /etc/portiyer.conf | |
| sudo chmod 600 /etc/portiyer.conf | |
| # 5) Create a dedicated log directory for Portiyer | |
| LOG_DIR="/var/lib/portiyer" | |
| sudo mkdir -p ${LOG_DIR} | |
| sudo chown portiyer:portiyer ${LOG_DIR} | |
| sudo chmod 755 ${LOG_DIR} | |
| # 6) Update collector.sh with CPU normalization & dstat fixes | |
| COLLECTOR_SCRIPT_PATH="/usr/local/bin/collector.sh" | |
| sudo tee ${COLLECTOR_SCRIPT_PATH} > /dev/null << 'EOF' | |
| #!/usr/bin/env bash | |
| # Fix cron job execution issue by setting PATH manually | |
| export PATH=/usr/local/bin:/usr/bin:/bin | |
| # Load credentials securely | |
| source /etc/portiyer.conf | |
| # Get total CPU cores | |
| CPU_CORES=$(nproc) | |
| # Use a dedicated directory for dstat logs instead of /tmp | |
| LOG_DIR="/var/lib/portiyer" | |
| CSV_FILE="${LOG_DIR}/dstat.csv" | |
| # Ensure the log directory exists and is writable | |
| mkdir -p ${LOG_DIR} | |
| chown portiyer:portiyer ${LOG_DIR} | |
| chmod 755 ${LOG_DIR} | |
| # Ensure the CSV file is writable | |
| touch ${CSV_FILE} | |
| chown portiyer:portiyer ${CSV_FILE} | |
| chmod 644 ${CSV_FILE} | |
| # Run dstat with correct formatting (avoiding empty CSV issue) | |
| dstat --time --cpu --mem --disk --net 1 1 --output ${CSV_FILE} 2>/dev/null | |
| # Extract the last line of dstat output (avoid empty reads) | |
| CSV_LINE=$(tail -n 1 ${CSV_FILE} | tr -d '\r') | |
| # If CSV_LINE is empty, log it and exit (prevent sending bad data) | |
| if [[ -z "$CSV_LINE" ]]; then | |
| echo "[$(date)] WARNING: dstat output was empty!" >> ${LOG_DIR}/collector.log | |
| exit 1 | |
| fi | |
| # Escape JSON special characters in CSV_LINE | |
| CSV_LINE_ESCAPED=$(echo ${CSV_LINE} | sed 's/"/\\"/g') | |
| # Get total disk usage stats | |
| DISK_USAGE=$(df -k --output=used,size,pcent / | tail -1 | awk '{print "{ \"used\": " $1 ", \"total\": " $2 ", \"percent\": \"" $3 "\" }"}') | |
| # Get top 10 CPU-intensive processes (now normalized per core) | |
| TOP_CPU=$(ps -eo pid,%cpu,%mem,cmd --sort=-%cpu | head -11 | tail -10 | awk -v cores="$CPU_CORES" '{printf "{ \"pid\": %s, \"cpu\": %.2f, \"mem\": %s, \"cmd\": \"%s\" },", $1, $2/cores, $3, $4}' | sed 's/,$//') | |
| # Get top 10 Memory-intensive processes | |
| TOP_MEM=$(ps -eo pid,%cpu,%mem,cmd --sort=-%mem | head -11 | tail -10 | awk '{printf "{ \"pid\": %s, \"cpu\": %s, \"mem\": %s, \"cmd\": \"%s\" },", $1, $2, $3, $4}' | sed 's/,$//') | |
| # Build final JSON payload | |
| PAYLOAD=$(cat <<EOF_JSON | |
| { | |
| "serverId": "${SERVER_ID}", | |
| "metrics": "${CSV_LINE_ESCAPED}", | |
| "diskUsage": ${DISK_USAGE}, | |
| "topProcesses": { | |
| "cpu": [ ${TOP_CPU} ], | |
| "memory": [ ${TOP_MEM} ] | |
| } | |
| } | |
| EOF_JSON | |
| ) | |
| # Send metrics via secure POST request | |
| curl -s -X POST -H "Content-Type: application/json" \ | |
| -H "Authorization: ${ACCESS_TOKEN}" \ | |
| -H "x-server-id: ${SERVER_ID}" \ | |
| -d "${PAYLOAD}" ${BACKEND_URL} | |
| # **Clear the file after sending data to keep storage clean** | |
| > ${CSV_FILE} | |
| EOF | |
| # 7) Make the collector script executable | |
| sudo chmod +x "${COLLECTOR_SCRIPT_PATH}" | |
| sudo chown portiyer:portiyer "${COLLECTOR_SCRIPT_PATH}" | |
| # 8) REMOVE OLD CRON JOBS BEFORE ADDING A NEW ONE | |
| if [ -f "/etc/cron.d/portiyer-monitor" ]; then | |
| sudo rm -f /etc/cron.d/portiyer-monitor | |
| fi | |
| # 9) Add a cron job to run the script every 5 seconds (Can be modified for different intervals) | |
| CRON_JOB="* * * * * portiyer ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 5; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 10; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 15; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 20; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 25; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 30; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 35; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 40; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 45; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 50; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1 | |
| * * * * * portiyer sleep 55; ${COLLECTOR_SCRIPT_PATH} > /dev/null 2>&1" | |
| echo "${CRON_JOB}" | sudo tee /etc/cron.d/portiyer-monitor > /dev/null | |
| sudo chmod 644 /etc/cron.d/portiyer-monitor | |
| sudo systemctl restart cron || sudo service cron restart | |
| echo "Installation complete!" | |
| echo "Collector script created at: ${COLLECTOR_SCRIPT_PATH}" | |
| echo | |
| echo "A cron job has been automatically added to run every 5 seconds." | |
| echo "Metrics are being sent to ${BACKEND_URL}." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment