Files
atlas/internal/httpapp/maintenance_handlers.go
Othman H. Suseno a7ba6c83ea
Some checks failed
CI / test-build (push) Has been cancelled
switch to postgresql
2025-12-16 01:31:27 +07:00

163 lines
4.1 KiB
Go

package httpapp
import (
"encoding/json"
"net/http"
"gitea.avt.data-center.id/othman.suseno/atlas/internal/backup"
"gitea.avt.data-center.id/othman.suseno/atlas/internal/errors"
"gitea.avt.data-center.id/othman.suseno/atlas/internal/models"
)
// handleGetMaintenanceStatus returns the current maintenance mode status
func (a *App) handleGetMaintenanceStatus(w http.ResponseWriter, r *http.Request) {
if a.maintenanceService == nil {
writeError(w, errors.NewAPIError(
errors.ErrCodeInternal,
"maintenance service not available",
http.StatusInternalServerError,
))
return
}
status := a.maintenanceService.GetStatus()
writeJSON(w, http.StatusOK, status)
}
// handleEnableMaintenance enables maintenance mode
func (a *App) handleEnableMaintenance(w http.ResponseWriter, r *http.Request) {
if a.maintenanceService == nil {
writeError(w, errors.NewAPIError(
errors.ErrCodeInternal,
"maintenance service not available",
http.StatusInternalServerError,
))
return
}
// Require administrator role
user, ok := getUserFromContext(r)
if !ok {
writeError(w, errors.NewAPIError(
errors.ErrCodeUnauthorized,
"authentication required",
http.StatusUnauthorized,
))
return
}
if user.Role != models.RoleAdministrator {
writeError(w, errors.NewAPIError(
errors.ErrCodeForbidden,
"administrator role required",
http.StatusForbidden,
))
return
}
var req struct {
Reason string `json:"reason"`
AllowedUsers []string `json:"allowed_users,omitempty"`
CreateBackup bool `json:"create_backup,omitempty"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
// Description is optional, so we'll continue even if body is empty
_ = err
}
// Create backup before entering maintenance if requested
var backupID string
if req.CreateBackup && a.backupService != nil {
// Collect all configuration data
backupData := backup.BackupData{
Users: a.userStore.List(),
SMBShares: a.smbStore.List(),
NFSExports: a.nfsStore.List(),
ISCSITargets: a.iscsiStore.List(),
Policies: a.snapshotPolicy.List(),
Config: map[string]interface{}{
"database_conn": a.cfg.DatabaseConn,
},
}
id, err := a.backupService.CreateBackup(backupData, "Automatic backup before maintenance mode")
if err != nil {
writeError(w, errors.NewAPIError(
errors.ErrCodeInternal,
"failed to create backup",
http.StatusInternalServerError,
).WithDetails(err.Error()))
return
}
backupID = id
}
// Enable maintenance mode
if err := a.maintenanceService.Enable(user.ID, req.Reason, req.AllowedUsers); err != nil {
writeError(w, errors.NewAPIError(
errors.ErrCodeInternal,
"failed to enable maintenance mode",
http.StatusInternalServerError,
).WithDetails(err.Error()))
return
}
// Set backup ID if created
if backupID != "" {
a.maintenanceService.SetLastBackupID(backupID)
}
status := a.maintenanceService.GetStatus()
writeJSON(w, http.StatusOK, map[string]interface{}{
"message": "maintenance mode enabled",
"status": status,
"backup_id": backupID,
})
}
// handleDisableMaintenance disables maintenance mode
func (a *App) handleDisableMaintenance(w http.ResponseWriter, r *http.Request) {
if a.maintenanceService == nil {
writeError(w, errors.NewAPIError(
errors.ErrCodeInternal,
"maintenance service not available",
http.StatusInternalServerError,
))
return
}
// Require administrator role
user, ok := getUserFromContext(r)
if !ok {
writeError(w, errors.NewAPIError(
errors.ErrCodeUnauthorized,
"authentication required",
http.StatusUnauthorized,
))
return
}
if user.Role != models.RoleAdministrator {
writeError(w, errors.NewAPIError(
errors.ErrCodeForbidden,
"administrator role required",
http.StatusForbidden,
))
return
}
if err := a.maintenanceService.Disable(user.ID); err != nil {
writeError(w, errors.NewAPIError(
errors.ErrCodeInternal,
"failed to disable maintenance mode",
http.StatusInternalServerError,
).WithDetails(err.Error()))
return
}
writeJSON(w, http.StatusOK, map[string]string{
"message": "maintenance mode disabled",
})
}