diff --git a/.gitignore b/.gitignore index 555a420..03c8052 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ android/.gradle/ android/build/ android/app/build/ android/local.properties +config/firebase-service-account.json diff --git a/AGENTS.md b/AGENTS.md index 5afa882..9b65dce 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,6 @@ Repo-specific guidance for OpenCode sessions. Verified against code. ## Commands - `composer install` — install deps (no dev deps in `composer.json`) - `php bin/generate-key.php` — generate master key at `/etc/servermanager/master.key` -- `php bin/monitor.php` — collect server metrics (runs via cron every minute) - `sudo bash install.sh` — full Ubuntu 22.04+/24.04+ install (needs sudo) - `mysql servermanager < database/migrations/001_initial_schema.sql` — db setup - `export ANDROID_HOME=/opt/android-sdk && cd android && ./gradlew assembleDebug` — build APK → `public/sysadmin.apk` @@ -55,6 +54,11 @@ Repo-specific guidance for OpenCode sessions. Verified against code. - `api_token` column on users for Bearer token auth - `server_permissions` table stores required SSH permissions per server (FK to `servers.id` CASCADE) +## PR creation workflow +- If the current branch **exists on remote** (`git ls-remote --heads origin `), create a new PR from it via API: `POST /api/v1/repos/devlab/server-manager/pulls` with `head=`, `base=master`. +- If the current branch **does not exist on remote**, create a new one from master first: `git checkout -b master`, push it, then create the PR. +- The API token for `git.devlab.lat` is embedded in the remote URL (`agent:@git.devlab.lat`). Use `-u "agent:"` for basic auth. The token is accessible via `git remote get-url origin`. + ## Testing / CI - **No tests, no CI, no linter, no formatter, no typechecker** exist in this repo diff --git a/README.md b/README.md index 9cd9de9..137d0b3 100755 --- a/README.md +++ b/README.md @@ -116,17 +116,7 @@ server { } ``` -### 5. Cron Job for Monitoring - -```bash -# Add to crontab (runs every minute) -sudo crontab -u www-data -e - -# Add line: -* * * * * php /var/www/servermanager/bin/monitor.php >> /var/www/servermanager/logs/cron.log 2>&1 -``` - -### 6. Start Services +### 5. Start Services ```bash sudo systemctl restart php8.3-fpm nginx mysql @@ -171,7 +161,6 @@ All credential accesses are logged: ``` ServerManager/ ├── bin/ -│ ├── monitor.php # CLI: collect metrics │ └── generate-key.php # CLI: generate master key ├── config/ │ └── config.php # App configuration diff --git a/install/agent-install.sh b/bin/agent-install.sh similarity index 100% rename from install/agent-install.sh rename to bin/agent-install.sh diff --git a/install/agent-uninstall.sh b/bin/agent-uninstall.sh similarity index 100% rename from install/agent-uninstall.sh rename to bin/agent-uninstall.sh diff --git a/bin/agent.sh b/bin/agent.sh deleted file mode 100644 index 8638b57..0000000 --- a/bin/agent.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash -# ServerManager Monitoring Agent -# This script runs as a systemd service on monitored servers. -set -e - -CONFIG_FILE="/etc/servermanager/agent.conf" - -load_config() { - if [ -f "$CONFIG_FILE" ]; then - source "$CONFIG_FILE" - fi - SERVER_URL="${SERVER_URL:-}" - AGENT_KEY="${AGENT_KEY:-}" - INTERVAL="${INTERVAL:-60}" -} - -collect_metrics() { - CPU=$(top -bn1 2>/dev/null | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1) - [ -z "$CPU" ] && CPU=0 - - RAM=$(free 2>/dev/null | grep Mem | awk '{printf "%.1f", $3/$2 * 100}') - [ -z "$RAM" ] && RAM=0 - - DISK=$(df / 2>/dev/null | tail -1 | awk '{print $5}' | sed 's/%//') - [ -z "$DISK" ] && DISK=0 - - LOAD=$(cat /proc/loadavg 2>/dev/null | awk '{print $1}') - [ -z "$LOAD" ] && LOAD=0 - - UPTIME=$(uptime -p 2>/dev/null | sed 's/^up //') - [ -z "$UPTIME" ] && UPTIME="" -} - -push_metrics() { - local payload - payload=$(cat </dev/null || echo "000" -} - -main() { - load_config - - if [ -z "$SERVER_URL" ] || [ -z "$AGENT_KEY" ]; then - echo "ERROR: SERVER_URL and AGENT_KEY must be set in $CONFIG_FILE" - exit 1 - fi - - echo "ServerManager Agent started" - echo "Server: $SERVER_URL" - echo "Interval: ${INTERVAL}s" - - sleep 5 - - while true; do - collect_metrics - http_code=$(push_metrics) - - if [ "$http_code" = "200" ]; then - echo "[$(date)] Metrics pushed successfully" - else - echo "[$(date)] Failed to push metrics (HTTP $http_code)" - fi - - sleep "$INTERVAL" - done -} - -main diff --git a/bin/monitor.php b/bin/monitor.php deleted file mode 100755 index c66adb6..0000000 --- a/bin/monitor.php +++ /dev/null @@ -1,23 +0,0 @@ -boot(dirname(__DIR__)); - - $monitoring = new MonitoringService(); - $results = $monitoring->collectAllMetrics(); - - $online = count(array_filter($results, fn($r) => $r && ($r['status'] ?? '') === 'online')); - $offline = count($results) - $online; - - echo sprintf("[%s] Metrics collected: %d servers (%d online, %d offline)\n", - date('Y-m-d H:i:s'), count($results), $online, $offline); -} catch (\Throwable $e) { - echo sprintf("[%s] ERROR: %s\n", date('Y-m-d H:i:s'), $e->getMessage()); - exit(1); -} diff --git a/database/migrations/011_cleanup_unused_tables.sql b/database/migrations/011_cleanup_unused_tables.sql new file mode 100644 index 0000000..c218bee --- /dev/null +++ b/database/migrations/011_cleanup_unused_tables.sql @@ -0,0 +1,4 @@ +DROP TABLE IF EXISTS `scheduled_tasks`; +DROP TABLE IF EXISTS `api_tokens`; +DROP TABLE IF EXISTS `rate_limits`; +DROP TABLE IF EXISTS `sessions`; diff --git a/install.sh b/install.sh index 6e236ea..c82699f 100755 --- a/install.sh +++ b/install.sh @@ -241,11 +241,8 @@ configure_cron() { log_step "Configuring Cron Jobs" cat > /etc/cron.d/servermanager << CRONEOF -# ServerManager Monitoring Cron -# Collect metrics every minute -* * * * * www-data /usr/bin/php ${APP_DIR}/bin/monitor.php >> ${APP_DIR}/logs/cron.log 2>&1 - -# Cleanup old logs weekly +# ServerManager Cron Jobs +# Logs cleanup — weekly 0 3 * * 0 www-data find ${APP_DIR}/logs/ -name "*.log" -mtime +30 -delete CRONEOF @@ -259,32 +256,6 @@ create_binaries() { mkdir -p "${APP_DIR}/bin" - cat > "${APP_DIR}/bin/monitor.php" << 'PHPEOF' -boot(dirname(__DIR__)); - - $monitoring = new MonitoringService(); - $results = $monitoring->collectAllMetrics(); - - $online = count(array_filter($results, fn($r) => $r && ($r['status'] ?? '') === 'online')); - $offline = count($results) - $online; - - echo sprintf("[%s] Metrics collected: %d servers (%d online, %d offline)\n", - date('Y-m-d H:i:s'), count($results), $online, $offline); -} catch (\Throwable $e) { - echo sprintf("[%s] ERROR: %s\n", date('Y-m-d H:i:s'), $e->getMessage()); - exit(1); -} -PHPEOF - cat > "${APP_DIR}/bin/generate-key.php" << 'PHPEOF' Cloud Messaging and copy the -# Server key (legacy) or Cloud Messaging API key -# -# 5. Set the server key in .env: -# FCM_SERVER_KEY=your_server_key_here -# -# 6. OR place your Firebase Admin service account key at: -# config/firebase-service-account.json -# (for the OAuth-based API - more secure) -# -# The app will work without FCM configured; push notifications -# simply won't be sent until Firebase is set up. -# -# --- - -echo "Firebase setup script" -echo "=====================" -echo "" -echo "To enable push notifications:" -echo "" -echo "1. Create a Firebase project: https://console.firebase.google.com" -echo "2. Add Android app with package: com.devlab.app" -echo "3. Download google-services.json → android/app/google-services.json" -echo "4. Get Server Key from Cloud Messaging settings" -echo "5. Add to .env: FCM_SERVER_KEY=your_key_here" -echo "" -echo "Without these steps, push notifications are disabled." -echo "The app will continue to work using polling as fallback." diff --git a/install/servermanager-agent.service b/install/servermanager-agent.service deleted file mode 100644 index 3c24384..0000000 --- a/install/servermanager-agent.service +++ /dev/null @@ -1,21 +0,0 @@ -[Unit] -Description=ServerManager Monitoring Agent -Documentation=https://github.com/servermanager -After=network-online.target -Wants=network-online.target - -[Service] -Type=simple -ExecStart=/usr/local/bin/servermanager-agent -Restart=always -RestartSec=10 -StartLimitIntervalSec=60 -StartLimitBurst=5 -NoNewPrivileges=yes -ProtectSystem=full -ProtectHome=yes -PrivateDevices=yes -PrivateTmp=yes - -[Install] -WantedBy=multi-user.target diff --git a/src/Services/AgentService.php b/src/Services/AgentService.php index ea05604..ff97ab7 100644 --- a/src/Services/AgentService.php +++ b/src/Services/AgentService.php @@ -43,7 +43,7 @@ class AgentService $serverUrl = $scheme . $host; } - $scriptPath = $this->basePath . '/install/agent-install.sh'; + $scriptPath = $this->basePath . '/bin/agent-install.sh'; if (!file_exists($scriptPath)) { return ['success' => false, 'error' => 'Agent install script not found']; @@ -114,7 +114,7 @@ class AgentService $server = App::getEncryption()->decryptArray($server, ['ssh_password', 'ssh_key']); - $scriptPath = $this->basePath . '/install/agent-uninstall.sh'; + $scriptPath = $this->basePath . '/bin/agent-uninstall.sh'; if (!file_exists($scriptPath)) { return ['success' => false, 'error' => 'Agent uninstall script not found'];