Major-Update Ablauf korrigiert und getestet
Agent: - major_update: opnsense-update -r <ver> -bkp + pkg-static update -f + pkg-static upgrade -y - Reboot ist bei Major-Updates default true (immer noetig) - update_check: reboot_required Flag hinzugefuegt - update: reboot_required korrekt aus opnsense-update -c Exit-Code - Alle Steps liefern strukturierte Ergebnisse fuer Frontend-Workflow Getestet auf 192.168.85.19: - Normales Update: 25.7 → 25.7.11_9 (93 Pakete) erfolgreich - Major-Upgrade: 25.7.11_9 → 26.1.2_5 erfolgreich (Base+Kernel+Packages+Reboot) README: Update-Ablauf dokumentiert (Normal vs Major)
This commit is contained in:
parent
f55536623e
commit
23c8f2cd66
25
README.md
25
README.md
@ -234,20 +234,37 @@ curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
|
|||||||
https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/reboot
|
https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/reboot
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Update-Ablauf
|
||||||
|
|
||||||
|
**Normales Update** (Patches innerhalb der gleichen Version):
|
||||||
|
1. `opnsense-update` — Core-Update herunterladen
|
||||||
|
2. `pkg upgrade -y` — Paket-Updates installieren
|
||||||
|
3. Nachpruefung: `opnsense-update -c` — Exit 1 = Reboot noetig
|
||||||
|
|
||||||
|
Response enthaelt `reboot_required: true/false` fuer das Frontend.
|
||||||
|
|
||||||
|
**Major-Upgrade** (z.B. 25.7 → 26.1):
|
||||||
|
1. `opnsense-update -r <version> -bkp` — Repository wechseln + Base + Kernel + Packages herunterladen
|
||||||
|
2. `pkg-static update -f` — Repository-Katalog forciert aktualisieren
|
||||||
|
3. `pkg-static upgrade -y` — Alle Pakete auf neue Version installieren
|
||||||
|
4. **Reboot erforderlich** (immer bei Major-Upgrade)
|
||||||
|
|
||||||
|
Major-Upgrades setzen `reboot_required: true` und `reboot` ist standardmaessig aktiviert.
|
||||||
|
|
||||||
### WebSocket Commands (Backend → Agent)
|
### WebSocket Commands (Backend → Agent)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
// Remote-Befehl ausfuehren
|
// Remote-Befehl ausfuehren
|
||||||
{"type":"command","id":"cmd1","command":"exec","params":{"command":"uptime","timeout":30}}
|
{"type":"command","id":"cmd1","command":"exec","params":{"command":"uptime","timeout":30}}
|
||||||
|
|
||||||
// Update-Check
|
// Update-Check (liefert core_update_available, pending_packages, reboot_required)
|
||||||
{"type":"command","id":"cmd2","command":"update_check"}
|
{"type":"command","id":"cmd2","command":"update_check"}
|
||||||
|
|
||||||
// Normales Update
|
// Normales Update (reboot optional)
|
||||||
{"type":"command","id":"cmd3","command":"update","params":{"reboot":false}}
|
{"type":"command","id":"cmd3","command":"update","params":{"reboot":false}}
|
||||||
|
|
||||||
// Major-Update
|
// Major-Update (reboot default true)
|
||||||
{"type":"command","id":"cmd4","command":"major_update","params":{"version":"26.7","reboot":true}}
|
{"type":"command","id":"cmd4","command":"major_update","params":{"version":"26.1","reboot":true}}
|
||||||
|
|
||||||
// Reboot
|
// Reboot
|
||||||
{"type":"command","id":"cmd5","command":"reboot","params":{"delay":5}}
|
{"type":"command","id":"cmd5","command":"reboot","params":{"delay":5}}
|
||||||
|
|||||||
@ -102,14 +102,42 @@ func (h *Handler) handleUpdateCheck(msg Message) Message {
|
|||||||
// 1. OPNsense Core Update pruefen
|
// 1. OPNsense Core Update pruefen
|
||||||
coreOutput, coreErr := h.runCommand("/usr/local/sbin/opnsense-update -c", 60)
|
coreOutput, coreErr := h.runCommand("/usr/local/sbin/opnsense-update -c", 60)
|
||||||
if coreErr != nil {
|
if coreErr != nil {
|
||||||
// Exit 1 = Update verfuegbar
|
// Exit 1 = Update verfuegbar ODER Reboot noetig
|
||||||
|
info := strings.TrimSpace(coreOutput)
|
||||||
result["core_update_available"] = true
|
result["core_update_available"] = true
|
||||||
result["core_update_info"] = strings.TrimSpace(coreOutput)
|
result["core_update_info"] = info
|
||||||
} else {
|
} else {
|
||||||
result["core_update_available"] = false
|
result["core_update_available"] = false
|
||||||
result["core_update_info"] = "Kein Core-Update verfuegbar"
|
result["core_update_info"] = "Kein Core-Update verfuegbar"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reboot-Check: Base/Kernel Version != installierte Version?
|
||||||
|
baseVer, _ := h.runCommand("cat /usr/local/opnsense/version/base", 5)
|
||||||
|
kernelVer, _ := h.runCommand("cat /usr/local/opnsense/version/kernel", 5)
|
||||||
|
coreJson, _ := h.runCommand("cat /usr/local/opnsense/version/core", 5)
|
||||||
|
baseVer = strings.TrimSpace(baseVer)
|
||||||
|
kernelVer = strings.TrimSpace(kernelVer)
|
||||||
|
|
||||||
|
rebootRequired := false
|
||||||
|
// Pruefen ob CORE_SERIES sich von Base/Kernel unterscheidet
|
||||||
|
if strings.Contains(coreJson, "CORE_NEXT") && baseVer != "" && kernelVer != "" {
|
||||||
|
// Einfacher Check: wenn base/kernel neuer als core → reboot noetig
|
||||||
|
coreVer := ""
|
||||||
|
for _, line := range strings.Split(coreJson, "\n") {
|
||||||
|
if strings.Contains(line, "CORE_PKGVERSION") {
|
||||||
|
parts := strings.SplitN(line, ":", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
coreVer = strings.Trim(strings.TrimSpace(parts[1]), "\",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if coreVer != "" && baseVer != "" && !strings.HasPrefix(baseVer, strings.Split(coreVer, ".")[0]+"."+strings.Split(coreVer, ".")[1]) {
|
||||||
|
// Base-Version Major.Minor unterscheidet sich von Core → Reboot
|
||||||
|
rebootRequired = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result["reboot_required"] = rebootRequired
|
||||||
|
|
||||||
// 2. Paket-Updates pruefen
|
// 2. Paket-Updates pruefen
|
||||||
pkgOutput, _ := h.runCommand("/usr/sbin/pkg upgrade -n", 60)
|
pkgOutput, _ := h.runCommand("/usr/sbin/pkg upgrade -n", 60)
|
||||||
pendingPackages := h.parsePkgUpgrade(pkgOutput)
|
pendingPackages := h.parsePkgUpgrade(pkgOutput)
|
||||||
@ -168,23 +196,28 @@ func (h *Handler) handleUpdate(msg Message) Message {
|
|||||||
// Schritt 3: opnsense-update -c (Nachpruefung)
|
// Schritt 3: opnsense-update -c (Nachpruefung)
|
||||||
log.Println("Update Schritt 3: Nachpruefung")
|
log.Println("Update Schritt 3: Nachpruefung")
|
||||||
checkOutput, checkErr := h.runCommand("/usr/local/sbin/opnsense-update -c", 60)
|
checkOutput, checkErr := h.runCommand("/usr/local/sbin/opnsense-update -c", 60)
|
||||||
stillPending := checkErr != nil
|
rebootRequired := checkErr != nil // Exit 1 nach Update = Reboot noetig
|
||||||
step3 := map[string]interface{}{
|
step3 := map[string]interface{}{
|
||||||
"step": "verify",
|
"step": "verify",
|
||||||
"output": checkOutput,
|
"output": checkOutput,
|
||||||
"updates_pending": stillPending,
|
"reboot_required": rebootRequired,
|
||||||
}
|
}
|
||||||
steps = append(steps, step3)
|
steps = append(steps, step3)
|
||||||
|
|
||||||
result["steps"] = steps
|
result["steps"] = steps
|
||||||
|
result["reboot_required"] = rebootRequired
|
||||||
result["reboot_requested"] = reboot
|
result["reboot_requested"] = reboot
|
||||||
|
|
||||||
// Gesamtstatus
|
// Gesamtstatus
|
||||||
if coreErr == nil && pkgErr == nil {
|
if coreErr == nil && pkgErr == nil {
|
||||||
response.Status = "ok"
|
response.Status = "ok"
|
||||||
result["message"] = "Update erfolgreich abgeschlossen"
|
if rebootRequired {
|
||||||
|
result["message"] = "Update erfolgreich — Reboot erforderlich"
|
||||||
} else {
|
} else {
|
||||||
response.Status = "ok" // Nicht "error" — teilweise Updates sind OK
|
result["message"] = "Update erfolgreich abgeschlossen"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response.Status = "ok"
|
||||||
result["message"] = "Update mit Warnungen abgeschlossen"
|
result["message"] = "Update mit Warnungen abgeschlossen"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,17 +243,18 @@ func (h *Handler) handleUpdate(msg Message) Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handleMajorUpdate fuehrt ein Major-Upgrade durch
|
// handleMajorUpdate fuehrt ein Major-Upgrade durch
|
||||||
|
// Ablauf: opnsense-update -r <ver> -bkp → pkg-static update -f → pkg-static upgrade -y → Reboot
|
||||||
func (h *Handler) handleMajorUpdate(msg Message) Message {
|
func (h *Handler) handleMajorUpdate(msg Message) Message {
|
||||||
response := Message{Type: "response", ID: msg.ID}
|
response := Message{Type: "response", ID: msg.ID}
|
||||||
|
|
||||||
targetVersion, ok := msg.Params["version"].(string)
|
targetVersion, ok := msg.Params["version"].(string)
|
||||||
if !ok || targetVersion == "" {
|
if !ok || targetVersion == "" {
|
||||||
response.Status = "error"
|
response.Status = "error"
|
||||||
response.Error = "Parameter 'version' erforderlich (z.B. '26.7')"
|
response.Error = "Parameter 'version' erforderlich (z.B. '26.1')"
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
reboot := false
|
reboot := true // Major-Update braucht immer Reboot, default an
|
||||||
if r, ok := msg.Params["reboot"].(bool); ok {
|
if r, ok := msg.Params["reboot"].(bool); ok {
|
||||||
reboot = r
|
reboot = r
|
||||||
}
|
}
|
||||||
@ -231,63 +265,59 @@ func (h *Handler) handleMajorUpdate(msg Message) Message {
|
|||||||
"target_version": targetVersion,
|
"target_version": targetVersion,
|
||||||
}
|
}
|
||||||
var steps []map[string]interface{}
|
var steps []map[string]interface{}
|
||||||
|
hasError := false
|
||||||
|
|
||||||
// Schritt 1: opnsense-update -r <version> (Release wechseln)
|
// Schritt 1: opnsense-update -r <version> -bkp (Release wechseln + Base + Kernel + Packages)
|
||||||
log.Printf("Major-Update Schritt 1: opnsense-update -r %s", targetVersion)
|
log.Printf("Schritt 1: opnsense-update -r %s -bkp", targetVersion)
|
||||||
releaseCmd := fmt.Sprintf("/usr/local/sbin/opnsense-update -r %s", targetVersion)
|
releaseCmd := fmt.Sprintf("/usr/local/sbin/opnsense-update -r %s -bkp", targetVersion)
|
||||||
releaseOutput, releaseErr := h.runCommand(releaseCmd, 300)
|
releaseOutput, releaseErr := h.runCommand(releaseCmd, 900)
|
||||||
step1 := map[string]interface{}{
|
step1 := map[string]interface{}{
|
||||||
"step": fmt.Sprintf("opnsense-update -r %s", targetVersion),
|
"step": fmt.Sprintf("opnsense-update -r %s -bkp", targetVersion),
|
||||||
"output": releaseOutput,
|
"output": releaseOutput,
|
||||||
"ok": releaseErr == nil,
|
"ok": releaseErr == nil,
|
||||||
}
|
}
|
||||||
if releaseErr != nil {
|
if releaseErr != nil {
|
||||||
step1["error"] = releaseErr.Error()
|
step1["error"] = releaseErr.Error()
|
||||||
steps = append(steps, step1)
|
hasError = true
|
||||||
|
|
||||||
// Bei Fehler im Release-Wechsel abbrechen
|
|
||||||
result["steps"] = steps
|
|
||||||
result["message"] = "Release-Wechsel fehlgeschlagen"
|
|
||||||
response.Status = "error"
|
|
||||||
response.Error = "Release-Wechsel fehlgeschlagen"
|
|
||||||
response.Data = result
|
|
||||||
return response
|
|
||||||
}
|
}
|
||||||
steps = append(steps, step1)
|
steps = append(steps, step1)
|
||||||
|
|
||||||
// Schritt 2: opnsense-update (eigentliches Update laden)
|
// Schritt 2: pkg-static update -f (Repository-Katalog auf neuen Release aktualisieren)
|
||||||
log.Println("Major-Update Schritt 2: opnsense-update")
|
log.Println("Schritt 2: pkg-static update -f")
|
||||||
updateOutput, updateErr := h.runCommand("/usr/local/sbin/opnsense-update", 900)
|
catalogOutput, catalogErr := h.runCommand("/usr/local/sbin/pkg-static update -f", 120)
|
||||||
step2 := map[string]interface{}{
|
step2 := map[string]interface{}{
|
||||||
"step": "opnsense-update",
|
"step": "pkg-static update -f",
|
||||||
"output": updateOutput,
|
"output": catalogOutput,
|
||||||
"ok": updateErr == nil,
|
"ok": catalogErr == nil,
|
||||||
}
|
}
|
||||||
if updateErr != nil {
|
if catalogErr != nil {
|
||||||
step2["error"] = updateErr.Error()
|
step2["error"] = catalogErr.Error()
|
||||||
|
hasError = true
|
||||||
}
|
}
|
||||||
steps = append(steps, step2)
|
steps = append(steps, step2)
|
||||||
|
|
||||||
// Schritt 3: pkg upgrade -y
|
// Schritt 3: pkg-static upgrade -y (alle Pakete auf neue Version)
|
||||||
log.Println("Major-Update Schritt 3: pkg upgrade -y")
|
log.Println("Schritt 3: pkg-static upgrade -y")
|
||||||
pkgOutput, pkgErr := h.runCommand("/usr/sbin/pkg upgrade -y", 600)
|
pkgOutput, pkgErr := h.runCommand("/usr/local/sbin/pkg-static upgrade -y", 900)
|
||||||
step3 := map[string]interface{}{
|
step3 := map[string]interface{}{
|
||||||
"step": "pkg upgrade",
|
"step": "pkg-static upgrade -y",
|
||||||
"output": pkgOutput,
|
"output": pkgOutput,
|
||||||
"ok": pkgErr == nil,
|
"ok": pkgErr == nil,
|
||||||
}
|
}
|
||||||
if pkgErr != nil {
|
if pkgErr != nil {
|
||||||
step3["error"] = pkgErr.Error()
|
step3["error"] = pkgErr.Error()
|
||||||
|
hasError = true
|
||||||
}
|
}
|
||||||
steps = append(steps, step3)
|
steps = append(steps, step3)
|
||||||
|
|
||||||
result["steps"] = steps
|
result["steps"] = steps
|
||||||
|
result["reboot_required"] = true
|
||||||
result["reboot_requested"] = reboot
|
result["reboot_requested"] = reboot
|
||||||
|
|
||||||
if updateErr == nil {
|
if !hasError {
|
||||||
result["message"] = fmt.Sprintf("Major-Update auf %s abgeschlossen", targetVersion)
|
result["message"] = fmt.Sprintf("Major-Update auf %s abgeschlossen — Reboot erforderlich", targetVersion)
|
||||||
} else {
|
} else {
|
||||||
result["message"] = fmt.Sprintf("Major-Update auf %s mit Warnungen", targetVersion)
|
result["message"] = fmt.Sprintf("Major-Update auf %s mit Warnungen — Reboot erforderlich", targetVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Status = "ok"
|
response.Status = "ok"
|
||||||
@ -307,7 +337,7 @@ func (h *Handler) handleMajorUpdate(msg Message) Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response.Data = result
|
response.Data = result
|
||||||
log.Printf("Major-Update auf %s abgeschlossen", targetVersion)
|
log.Printf("Major-Update auf %s abgeschlossen (Reboot noch ausstehend)", targetVersion)
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user