add installer alpha version
This commit is contained in:
249
internal/httpapp/service_handlers.go
Normal file
249
internal/httpapp/service_handlers.go
Normal file
@@ -0,0 +1,249 @@
|
||||
package httpapp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ManagedService represents a service with its status
|
||||
type ManagedService struct {
|
||||
Name string `json:"name"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Status string `json:"status"`
|
||||
Output string `json:"output,omitempty"`
|
||||
}
|
||||
|
||||
// getServiceName extracts service name from query parameter or defaults to atlas-api
|
||||
func getServiceName(r *http.Request) string {
|
||||
serviceName := r.URL.Query().Get("service")
|
||||
if serviceName == "" {
|
||||
return "atlas-api"
|
||||
}
|
||||
return serviceName
|
||||
}
|
||||
|
||||
// getAllServices returns list of all managed services
|
||||
func getAllServices() []ManagedService {
|
||||
services := []ManagedService{
|
||||
{Name: "atlas-api", DisplayName: "AtlasOS API"},
|
||||
{Name: "smbd", DisplayName: "SMB/CIFS (Samba)"},
|
||||
{Name: "nfs-server", DisplayName: "NFS Server"},
|
||||
{Name: "target", DisplayName: "iSCSI Target"},
|
||||
}
|
||||
return services
|
||||
}
|
||||
|
||||
// getServiceStatus returns the status of a specific service
|
||||
func getServiceStatus(serviceName string) (string, string, error) {
|
||||
cmd := exec.Command("systemctl", "status", serviceName, "--no-pager", "-l")
|
||||
output, err := cmd.CombinedOutput()
|
||||
outputStr := string(output)
|
||||
|
||||
if err != nil {
|
||||
// systemctl status returns non-zero exit code even when service is running
|
||||
// Check if output contains "active (running)" to determine actual status
|
||||
if strings.Contains(outputStr, "active (running)") {
|
||||
return "running", outputStr, nil
|
||||
}
|
||||
if strings.Contains(outputStr, "inactive (dead)") {
|
||||
return "stopped", outputStr, nil
|
||||
}
|
||||
if strings.Contains(outputStr, "failed") {
|
||||
return "failed", outputStr, nil
|
||||
}
|
||||
// Service might not exist
|
||||
if strings.Contains(outputStr, "could not be found") || strings.Contains(outputStr, "not found") {
|
||||
return "not-found", outputStr, nil
|
||||
}
|
||||
return "unknown", outputStr, err
|
||||
}
|
||||
|
||||
status := "unknown"
|
||||
if strings.Contains(outputStr, "active (running)") {
|
||||
status = "running"
|
||||
} else if strings.Contains(outputStr, "inactive (dead)") {
|
||||
status = "stopped"
|
||||
} else if strings.Contains(outputStr, "failed") {
|
||||
status = "failed"
|
||||
}
|
||||
|
||||
return status, outputStr, nil
|
||||
}
|
||||
|
||||
// handleListServices returns the status of all services
|
||||
func (a *App) handleListServices(w http.ResponseWriter, r *http.Request) {
|
||||
allServices := getAllServices()
|
||||
servicesStatus := make([]ManagedService, 0, len(allServices))
|
||||
|
||||
for _, svc := range allServices {
|
||||
status, output, err := getServiceStatus(svc.Name)
|
||||
if err != nil {
|
||||
log.Printf("error getting status for %s: %v", svc.Name, err)
|
||||
status = "error"
|
||||
}
|
||||
servicesStatus = append(servicesStatus, ManagedService{
|
||||
Name: svc.Name,
|
||||
DisplayName: svc.DisplayName,
|
||||
Status: status,
|
||||
Output: output,
|
||||
})
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"services": servicesStatus,
|
||||
})
|
||||
}
|
||||
|
||||
// handleServiceStatus returns the status of a specific service
|
||||
func (a *App) handleServiceStatus(w http.ResponseWriter, r *http.Request) {
|
||||
serviceName := getServiceName(r)
|
||||
status, output, err := getServiceStatus(serviceName)
|
||||
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{
|
||||
"error": "failed to get service status",
|
||||
"details": output,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"service": serviceName,
|
||||
"status": status,
|
||||
"output": output,
|
||||
})
|
||||
}
|
||||
|
||||
// handleServiceStart starts a service
|
||||
func (a *App) handleServiceStart(w http.ResponseWriter, r *http.Request) {
|
||||
serviceName := getServiceName(r)
|
||||
|
||||
var cmd *exec.Cmd
|
||||
// Special handling for SMB - use smbcontrol for reload, but systemctl for start/stop
|
||||
if serviceName == "smbd" {
|
||||
cmd = exec.Command("systemctl", "start", "smbd")
|
||||
} else {
|
||||
cmd = exec.Command("systemctl", "start", serviceName)
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("service start error for %s: %v", serviceName, err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]interface{}{
|
||||
"error": "failed to start service",
|
||||
"service": serviceName,
|
||||
"details": string(output),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"message": "service started successfully",
|
||||
"service": serviceName,
|
||||
})
|
||||
}
|
||||
|
||||
// handleServiceStop stops a service
|
||||
func (a *App) handleServiceStop(w http.ResponseWriter, r *http.Request) {
|
||||
serviceName := getServiceName(r)
|
||||
cmd := exec.Command("systemctl", "stop", serviceName)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("service stop error for %s: %v", serviceName, err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]interface{}{
|
||||
"error": "failed to stop service",
|
||||
"service": serviceName,
|
||||
"details": string(output),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"message": "service stopped successfully",
|
||||
"service": serviceName,
|
||||
})
|
||||
}
|
||||
|
||||
// handleServiceRestart restarts a service
|
||||
func (a *App) handleServiceRestart(w http.ResponseWriter, r *http.Request) {
|
||||
serviceName := getServiceName(r)
|
||||
cmd := exec.Command("systemctl", "restart", serviceName)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("service restart error for %s: %v", serviceName, err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]interface{}{
|
||||
"error": "failed to restart service",
|
||||
"service": serviceName,
|
||||
"details": string(output),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"message": "service restarted successfully",
|
||||
"service": serviceName,
|
||||
})
|
||||
}
|
||||
|
||||
// handleServiceReload reloads a service
|
||||
func (a *App) handleServiceReload(w http.ResponseWriter, r *http.Request) {
|
||||
serviceName := getServiceName(r)
|
||||
|
||||
var cmd *exec.Cmd
|
||||
// Special handling for SMB - use smbcontrol for reload
|
||||
if serviceName == "smbd" {
|
||||
cmd = exec.Command("smbcontrol", "all", "reload-config")
|
||||
} else {
|
||||
cmd = exec.Command("systemctl", "reload", serviceName)
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("service reload error for %s: %v", serviceName, err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]interface{}{
|
||||
"error": "failed to reload service",
|
||||
"service": serviceName,
|
||||
"details": string(output),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"message": "service reloaded successfully",
|
||||
"service": serviceName,
|
||||
})
|
||||
}
|
||||
|
||||
// handleServiceLogs returns the logs of a service
|
||||
func (a *App) handleServiceLogs(w http.ResponseWriter, r *http.Request) {
|
||||
serviceName := getServiceName(r)
|
||||
|
||||
// Get number of lines from query parameter (default: 50)
|
||||
linesStr := r.URL.Query().Get("lines")
|
||||
lines := "50"
|
||||
if linesStr != "" {
|
||||
if n, err := strconv.Atoi(linesStr); err == nil && n > 0 && n <= 1000 {
|
||||
lines = linesStr
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command("journalctl", "-u", serviceName, "-n", lines, "--no-pager")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("service logs error for %s: %v", serviceName, err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]interface{}{
|
||||
"error": "failed to get service logs",
|
||||
"service": serviceName,
|
||||
"details": string(output),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"service": serviceName,
|
||||
"logs": string(output),
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user