feat: Versions-Spalte im Dienste-Tab für Superadmin
Bislang war die einzige Möglichkeit, die laufende Manticore-/PostgreSQL-/ Postfix-/nginx-Version zu sehen, SSH + <binary> --version. serviceVersion() löst das best-effort pro Dienst auf (archivmail/-web: appVersion-Konstante, manticore: searchd --version, postgresql: psql --version, postfix: postconf mail_version, nginx: nginx -v). Fehler werden verschluckt (leerer String), eine unbekannte Version darf den Dienst-Status nicht auf "Fehler" kippen. manticore war bisher gar nicht in der Dienste-Whitelist (allowedServices) — jetzt ergänzt, damit es überhaupt in der Liste auftaucht und start/stop/restart wie die anderen Dienste möglich ist.
This commit is contained in:
@@ -17,6 +17,7 @@ import (
|
||||
var allowedServices = []string{
|
||||
"archivmail",
|
||||
"archivmail-web",
|
||||
"manticore",
|
||||
"postgresql@17-main",
|
||||
"postfix",
|
||||
"nginx",
|
||||
@@ -29,9 +30,57 @@ type ServiceStatus struct {
|
||||
Sub string `json:"sub"` // running, dead, exited, ...
|
||||
Enabled string `json:"enabled"` // enabled, disabled, static, unknown
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version,omitempty"` // best-effort, empty if not determinable
|
||||
ExternalBlocked *bool `json:"external_blocked,omitempty"` // only set for archivmail
|
||||
}
|
||||
|
||||
// serviceVersion resolves the installed version of a service, best-effort.
|
||||
// Superadmin-visible "which version is actually running" overview — before
|
||||
// this, the only way to see e.g. the Manticore version after an upgrade
|
||||
// (PROJ-67) was SSH + `searchd --version`. Errors are swallowed on purpose:
|
||||
// an unknown version must never turn the whole services list red.
|
||||
func (s *Server) serviceVersion(name string) string {
|
||||
switch name {
|
||||
case "archivmail", "archivmail-web":
|
||||
return s.appVersion
|
||||
case "manticore":
|
||||
out, err := exec.Command("searchd", "--version").CombinedOutput()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return firstLine(string(out))
|
||||
case "postgresql@17-main":
|
||||
out, err := exec.Command("psql", "--version").Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return firstLine(string(out))
|
||||
case "postfix":
|
||||
out, err := exec.Command("postconf", "mail_version").Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
_, v, ok := strings.Cut(firstLine(string(out)), "=")
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(v)
|
||||
case "nginx":
|
||||
out, err := exec.Command("nginx", "-v").CombinedOutput()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return firstLine(string(out))
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func firstLine(s string) string {
|
||||
line, _, _ := strings.Cut(s, "\n")
|
||||
return strings.TrimSpace(line)
|
||||
}
|
||||
|
||||
func isAllowedService(name string) bool {
|
||||
for _, s := range allowedServices {
|
||||
if s == name {
|
||||
@@ -41,7 +90,7 @@ func isAllowedService(name string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func systemctlShow(name string) ServiceStatus {
|
||||
func (s *Server) systemctlShow(name string) ServiceStatus {
|
||||
svc := ServiceStatus{Name: name, DisplayName: name}
|
||||
out, err := exec.Command("systemctl", "show", name+".service",
|
||||
"--property=ActiveState,SubState,UnitFileState,Description",
|
||||
@@ -72,6 +121,7 @@ func systemctlShow(name string) ServiceStatus {
|
||||
blocked := nftAPIBlocked()
|
||||
svc.ExternalBlocked = &blocked
|
||||
}
|
||||
svc.Version = s.serviceVersion(name)
|
||||
return svc
|
||||
}
|
||||
|
||||
@@ -87,7 +137,7 @@ func nftAPIBlocked() bool {
|
||||
func (s *Server) handleListServices(w http.ResponseWriter, r *http.Request) {
|
||||
result := make([]ServiceStatus, 0, len(allowedServices))
|
||||
for _, name := range allowedServices {
|
||||
result = append(result, systemctlShow(name))
|
||||
result = append(result, s.systemctlShow(name))
|
||||
}
|
||||
writeJSON(w, http.StatusOK, result)
|
||||
}
|
||||
@@ -142,7 +192,7 @@ func (s *Server) handleServiceAction(w http.ResponseWriter, r *http.Request) {
|
||||
Detail: name,
|
||||
Success: true,
|
||||
})
|
||||
writeJSON(w, http.StatusOK, systemctlShow(name))
|
||||
writeJSON(w, http.StatusOK, s.systemctlShow(name))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -166,5 +216,5 @@ func (s *Server) handleServiceAction(w http.ResponseWriter, r *http.Request) {
|
||||
Success: true,
|
||||
})
|
||||
|
||||
writeJSON(w, http.StatusOK, systemctlShow(name))
|
||||
writeJSON(w, http.StatusOK, s.systemctlShow(name))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user