273 lines
7.8 KiB
Go
273 lines
7.8 KiB
Go
|
|
package handlers
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
"net/http"
|
||
|
|
"os"
|
||
|
|
"os/exec"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"setec-manager/internal/deploy"
|
||
|
|
)
|
||
|
|
|
||
|
|
type autarchStatus struct {
|
||
|
|
Installed bool `json:"installed"`
|
||
|
|
InstallDir string `json:"install_dir"`
|
||
|
|
GitCommit string `json:"git_commit"`
|
||
|
|
VenvReady bool `json:"venv_ready"`
|
||
|
|
PipPackages int `json:"pip_packages"`
|
||
|
|
WebRunning bool `json:"web_running"`
|
||
|
|
WebStatus string `json:"web_status"`
|
||
|
|
DNSRunning bool `json:"dns_running"`
|
||
|
|
DNSStatus string `json:"dns_status"`
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchStatus(w http.ResponseWriter, r *http.Request) {
|
||
|
|
status := h.getAutarchStatus()
|
||
|
|
h.render(w, "autarch.html", status)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchStatusAPI(w http.ResponseWriter, r *http.Request) {
|
||
|
|
writeJSON(w, http.StatusOK, h.getAutarchStatus())
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) getAutarchStatus() autarchStatus {
|
||
|
|
dir := h.Config.Autarch.InstallDir
|
||
|
|
status := autarchStatus{InstallDir: dir}
|
||
|
|
|
||
|
|
// Check if installed
|
||
|
|
if _, err := os.Stat(filepath.Join(dir, ".git")); err == nil {
|
||
|
|
status.Installed = true
|
||
|
|
}
|
||
|
|
|
||
|
|
// Git commit
|
||
|
|
if hash, message, err := deploy.CurrentCommit(dir); err == nil {
|
||
|
|
status.GitCommit = hash + " " + message
|
||
|
|
}
|
||
|
|
|
||
|
|
// Venv
|
||
|
|
status.VenvReady = deploy.VenvExists(dir)
|
||
|
|
|
||
|
|
// Pip packages
|
||
|
|
venvDir := filepath.Join(dir, "venv")
|
||
|
|
if pkgs, err := deploy.ListPackages(venvDir); err == nil {
|
||
|
|
status.PipPackages = len(pkgs)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Web service
|
||
|
|
webActive, _ := deploy.IsActive("autarch-web")
|
||
|
|
status.WebRunning = webActive
|
||
|
|
if webActive {
|
||
|
|
status.WebStatus = "active"
|
||
|
|
} else {
|
||
|
|
status.WebStatus = "inactive"
|
||
|
|
}
|
||
|
|
|
||
|
|
// DNS service
|
||
|
|
dnsActive, _ := deploy.IsActive("autarch-dns")
|
||
|
|
status.DNSRunning = dnsActive
|
||
|
|
if dnsActive {
|
||
|
|
status.DNSStatus = "active"
|
||
|
|
} else {
|
||
|
|
status.DNSStatus = "inactive"
|
||
|
|
}
|
||
|
|
|
||
|
|
return status
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchInstall(w http.ResponseWriter, r *http.Request) {
|
||
|
|
dir := h.Config.Autarch.InstallDir
|
||
|
|
repo := h.Config.Autarch.GitRepo
|
||
|
|
branch := h.Config.Autarch.GitBranch
|
||
|
|
|
||
|
|
if _, err := os.Stat(filepath.Join(dir, ".git")); err == nil {
|
||
|
|
writeError(w, http.StatusConflict, "AUTARCH already installed at "+dir)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
depID, _ := h.DB.CreateDeployment(nil, "autarch_install")
|
||
|
|
var output strings.Builder
|
||
|
|
|
||
|
|
steps := []struct {
|
||
|
|
label string
|
||
|
|
fn func() error
|
||
|
|
}{
|
||
|
|
{"Clone from GitHub", func() error {
|
||
|
|
os.MkdirAll(filepath.Dir(dir), 0755)
|
||
|
|
out, err := deploy.Clone(repo, branch, dir)
|
||
|
|
output.WriteString(out)
|
||
|
|
return err
|
||
|
|
}},
|
||
|
|
{"Create Python venv", func() error {
|
||
|
|
return deploy.CreateVenv(dir)
|
||
|
|
}},
|
||
|
|
{"Upgrade pip", func() error {
|
||
|
|
venvDir := filepath.Join(dir, "venv")
|
||
|
|
deploy.UpgradePip(venvDir)
|
||
|
|
return nil
|
||
|
|
}},
|
||
|
|
{"Install pip packages", func() error {
|
||
|
|
reqFile := filepath.Join(dir, "requirements.txt")
|
||
|
|
if _, err := os.Stat(reqFile); err != nil {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
venvDir := filepath.Join(dir, "venv")
|
||
|
|
out, err := deploy.InstallRequirements(venvDir, reqFile)
|
||
|
|
output.WriteString(out)
|
||
|
|
return err
|
||
|
|
}},
|
||
|
|
{"Install npm packages", func() error {
|
||
|
|
out, _ := deploy.NpmInstall(dir)
|
||
|
|
output.WriteString(out)
|
||
|
|
return nil
|
||
|
|
}},
|
||
|
|
{"Set permissions", func() error {
|
||
|
|
exec.Command("chown", "-R", "root:root", dir).Run()
|
||
|
|
exec.Command("chmod", "-R", "755", dir).Run()
|
||
|
|
for _, d := range []string{"data", "data/certs", "data/dns", "results", "dossiers", "models"} {
|
||
|
|
os.MkdirAll(filepath.Join(dir, d), 0755)
|
||
|
|
}
|
||
|
|
confPath := filepath.Join(dir, "autarch_settings.conf")
|
||
|
|
if _, err := os.Stat(confPath); err == nil {
|
||
|
|
exec.Command("chmod", "600", confPath).Run()
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}},
|
||
|
|
{"Install systemd units", func() error {
|
||
|
|
h.installAutarchUnits(dir)
|
||
|
|
return nil
|
||
|
|
}},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, step := range steps {
|
||
|
|
output.WriteString(fmt.Sprintf("\n=== %s ===\n", step.label))
|
||
|
|
if err := step.fn(); err != nil {
|
||
|
|
h.DB.FinishDeployment(depID, "failed", output.String())
|
||
|
|
writeError(w, http.StatusInternalServerError, fmt.Sprintf("%s failed: %v", step.label, err))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
h.DB.FinishDeployment(depID, "success", output.String())
|
||
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "installed"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchUpdate(w http.ResponseWriter, r *http.Request) {
|
||
|
|
dir := h.Config.Autarch.InstallDir
|
||
|
|
|
||
|
|
depID, _ := h.DB.CreateDeployment(nil, "autarch_update")
|
||
|
|
var output strings.Builder
|
||
|
|
|
||
|
|
// Git pull
|
||
|
|
out, err := deploy.Pull(dir)
|
||
|
|
output.WriteString(out)
|
||
|
|
if err != nil {
|
||
|
|
h.DB.FinishDeployment(depID, "failed", output.String())
|
||
|
|
writeError(w, http.StatusInternalServerError, "git pull failed")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// Reinstall pip packages
|
||
|
|
reqFile := filepath.Join(dir, "requirements.txt")
|
||
|
|
if _, err := os.Stat(reqFile); err == nil {
|
||
|
|
venvDir := filepath.Join(dir, "venv")
|
||
|
|
pipOut, _ := deploy.InstallRequirements(venvDir, reqFile)
|
||
|
|
output.WriteString(pipOut)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Restart services
|
||
|
|
deploy.Restart("autarch-web")
|
||
|
|
deploy.Restart("autarch-dns")
|
||
|
|
|
||
|
|
h.DB.FinishDeployment(depID, "success", output.String())
|
||
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "updated"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchStart(w http.ResponseWriter, r *http.Request) {
|
||
|
|
deploy.Start("autarch-web")
|
||
|
|
deploy.Start("autarch-dns")
|
||
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "started"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchStop(w http.ResponseWriter, r *http.Request) {
|
||
|
|
deploy.Stop("autarch-web")
|
||
|
|
deploy.Stop("autarch-dns")
|
||
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "stopped"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchRestart(w http.ResponseWriter, r *http.Request) {
|
||
|
|
deploy.Restart("autarch-web")
|
||
|
|
deploy.Restart("autarch-dns")
|
||
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "restarted"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchConfig(w http.ResponseWriter, r *http.Request) {
|
||
|
|
confPath := filepath.Join(h.Config.Autarch.InstallDir, "autarch_settings.conf")
|
||
|
|
data, err := os.ReadFile(confPath)
|
||
|
|
if err != nil {
|
||
|
|
writeError(w, http.StatusNotFound, "config not found")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
writeJSON(w, http.StatusOK, map[string]string{"config": string(data)})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchConfigUpdate(w http.ResponseWriter, r *http.Request) {
|
||
|
|
var body struct {
|
||
|
|
Config string `json:"config"`
|
||
|
|
}
|
||
|
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||
|
|
writeError(w, http.StatusBadRequest, "invalid body")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
confPath := filepath.Join(h.Config.Autarch.InstallDir, "autarch_settings.conf")
|
||
|
|
if err := os.WriteFile(confPath, []byte(body.Config), 0600); err != nil {
|
||
|
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "saved"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) AutarchDNSBuild(w http.ResponseWriter, r *http.Request) {
|
||
|
|
dnsDir := filepath.Join(h.Config.Autarch.InstallDir, "services", "dns-server")
|
||
|
|
|
||
|
|
depID, _ := h.DB.CreateDeployment(nil, "dns_build")
|
||
|
|
|
||
|
|
cmd := exec.Command("go", "build", "-o", "autarch-dns", ".")
|
||
|
|
cmd.Dir = dnsDir
|
||
|
|
out, err := cmd.CombinedOutput()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
h.DB.FinishDeployment(depID, "failed", string(out))
|
||
|
|
writeError(w, http.StatusInternalServerError, "build failed: "+string(out))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
h.DB.FinishDeployment(depID, "success", string(out))
|
||
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "built"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (h *Handler) installAutarchUnits(dir string) {
|
||
|
|
webUnit := deploy.GenerateUnit(deploy.UnitConfig{
|
||
|
|
Name: "autarch-web",
|
||
|
|
Description: "AUTARCH Web Dashboard",
|
||
|
|
ExecStart: filepath.Join(dir, "venv", "bin", "python3") + " " + filepath.Join(dir, "autarch_web.py"),
|
||
|
|
WorkingDirectory: dir,
|
||
|
|
User: "root",
|
||
|
|
Environment: map[string]string{"PYTHONUNBUFFERED": "1"},
|
||
|
|
})
|
||
|
|
|
||
|
|
dnsUnit := deploy.GenerateUnit(deploy.UnitConfig{
|
||
|
|
Name: "autarch-dns",
|
||
|
|
Description: "AUTARCH DNS Server",
|
||
|
|
ExecStart: filepath.Join(dir, "services", "dns-server", "autarch-dns") + " --config " + filepath.Join(dir, "data", "dns", "config.json"),
|
||
|
|
WorkingDirectory: dir,
|
||
|
|
User: "root",
|
||
|
|
})
|
||
|
|
|
||
|
|
deploy.InstallUnit("autarch-web", webUnit)
|
||
|
|
deploy.InstallUnit("autarch-dns", dnsUnit)
|
||
|
|
}
|