Update-Commands: update, major_update, update_check, reboot

Agent:
- update: opnsense-update + pkg upgrade -y, optionaler Reboot
- major_update: opnsense-update -r <version>, optionaler Reboot
- update_check: Prueft Core- und Paket-Updates, liefert Details
- reboot: Shutdown mit konfigurierbarer Verzoegerung

Backend:
- Synchrone API-Endpoints (warten auf Agent-Response)
- Response-Waiter-System im Hub (Command-ID basiert)
- Konfigurierbare Timeouts pro Command-Typ
- POST /agents/{id}/update[-check] und /major-update und /reboot

README mit Update-Beispielen und API-Doku aktualisiert
This commit is contained in:
cynfo3000
2026-02-28 09:01:04 +01:00
parent 68e712b3a3
commit ebc70f17eb
4 changed files with 544 additions and 45 deletions
+57 -8
View File
@@ -22,14 +22,19 @@ type Hub struct {
broadcast chan []byte
tunnelManager *TunnelManager
// Response-Waiters: Command-ID -> Response-Channel
responseWaiters map[string]chan map[string]interface{}
waitersMux sync.RWMutex
}
func NewHub() *Hub {
hub := &Hub{
agents: make(map[string]*AgentConnection),
register: make(chan *AgentConnection),
unregister: make(chan *AgentConnection),
broadcast: make(chan []byte, 256),
agents: make(map[string]*AgentConnection),
register: make(chan *AgentConnection),
unregister: make(chan *AgentConnection),
broadcast: make(chan []byte, 256),
responseWaiters: make(map[string]chan map[string]interface{}),
}
hub.tunnelManager = NewTunnelManager(hub)
@@ -193,6 +198,22 @@ func (h *Hub) cleanupInactiveAgents() {
}
}
// RegisterResponseWaiter registriert einen Channel fuer eine Command-Response
func (h *Hub) RegisterResponseWaiter(cmdID string) chan map[string]interface{} {
ch := make(chan map[string]interface{}, 1)
h.waitersMux.Lock()
h.responseWaiters[cmdID] = ch
h.waitersMux.Unlock()
return ch
}
// UnregisterResponseWaiter entfernt einen Response-Waiter
func (h *Hub) UnregisterResponseWaiter(cmdID string) {
h.waitersMux.Lock()
delete(h.responseWaiters, cmdID)
h.waitersMux.Unlock()
}
// GetTunnelManager gibt den TunnelManager zurück (für API-Handler)
func (h *Hub) GetTunnelManager() *TunnelManager {
return h.tunnelManager
@@ -245,10 +266,38 @@ func (h *Hub) ProcessAgentMessage(agentID string, messageType int, data []byte)
return nil // Ignorieren wenn nicht parsebar
}
// Tunnel-Connect Responses verarbeiten
if msg.Type == "response" && msg.Status == "ok" && msg.Data != nil {
if sessionID, ok := msg.Data["session_id"].(string); ok {
h.tunnelManager.ConfirmSession(sessionID)
if msg.Type == "response" {
// Tunnel-Connect Responses verarbeiten
if msg.Status == "ok" && msg.Data != nil {
if sessionID, ok := msg.Data["session_id"].(string); ok {
h.tunnelManager.ConfirmSession(sessionID)
}
}
// Response an wartende API-Handler weiterleiten
if msg.ID != "" {
h.waitersMux.RLock()
ch, exists := h.responseWaiters[msg.ID]
h.waitersMux.RUnlock()
if exists {
resp := map[string]interface{}{
"status": msg.Status,
"data": msg.Data,
}
if msg.Status == "error" {
var errMsg struct {
Error string `json:"error"`
}
json.Unmarshal(data, &errMsg)
resp["error"] = errMsg.Error
}
select {
case ch <- resp:
default:
}
}
}
}