feat: push-based monitoring with remote agent

- Add database migration 006 for agent_key, agent_installed, agent_install_path, agent_last_seen_at columns
- Add Server model methods: findByAgentKey, generateAgentKey, regenerateAgentKey, updateAgentLastSeen, setAgentInstalled
- Auto-generate agent_key on server creation
- Create AgentService for SSH-based install/uninstall of remote agent
- Create bin/agent.sh - bash agent script for remote servers
- Create install/agent-install.sh and install/agent-uninstall.sh
- Create install/servermanager-agent.service systemd unit
- Add POST /api/metrics/push endpoint (auth via agent_key)
- Add web routes for agent install/uninstall/regenerate-key
- Add agent status section to server detail view with install/uninstall modals
- Make MonitoringService::saveMetrics() public for reuse
This commit is contained in:
2026-06-11 18:28:22 -04:00
parent 6e4bf2ad1d
commit bfa102cf97
12 changed files with 731 additions and 1 deletions

View File

@@ -122,6 +122,10 @@ class Server
$data['ssh_key'] = null;
}
if (empty($data['agent_key'])) {
$data['agent_key'] = $this->generateAgentKey();
}
$data['created_at'] = date('Y-m-d H:i:s');
$data['updated_at'] = date('Y-m-d H:i:s');
@@ -405,4 +409,47 @@ class Server
[$userId]
);
}
public function findByAgentKey(string $key): ?array
{
$server = $this->db->fetch(
'SELECT * FROM servers WHERE agent_key = ? AND status = \'active\'',
[$key]
);
if ($server) {
$server = $this->encryption->decryptArray($server, $this->encryptedFields);
}
return $server;
}
public function generateAgentKey(): string
{
return bin2hex(random_bytes(32));
}
public function regenerateAgentKey(int $id): string
{
$key = $this->generateAgentKey();
$this->db->update('servers', [
'agent_key' => $key,
'updated_at' => date('Y-m-d H:i:s'),
], 'id = ?', [$id]);
return $key;
}
public function updateAgentLastSeen(int $id): bool
{
return $this->db->update('servers', [
'agent_last_seen_at' => date('Y-m-d H:i:s'),
], 'id = ?', [$id]) > 0;
}
public function setAgentInstalled(int $id, bool $installed, ?string $path = null): bool
{
return $this->db->update('servers', [
'agent_installed' => $installed ? 1 : 0,
'agent_install_path' => $path,
'updated_at' => date('Y-m-d H:i:s'),
], 'id = ?', [$id]) > 0;
}
}