50 lines
2.0 KiB
Go
50 lines
2.0 KiB
Go
package meta
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/exec"
|
|
"syscall"
|
|
|
|
"nadir/internal/oscmd"
|
|
|
|
"github.com/danielgtaylor/huma/v2"
|
|
)
|
|
|
|
// RegisterUpdate wires POST /api/meta/update. It runs the equivalent of
|
|
// `sudo nadir update` in a detached session and returns 202 immediately; the
|
|
// systemctl restart that ends the updater drops in-flight connections, so the
|
|
// caller should poll /api/health to confirm the new version is up.
|
|
//
|
|
// Authorization: requires (meta, root). Only roles with a wildcard grant
|
|
// (the default admin role) match, since "meta" isn't a real module with a
|
|
// declared permission vocabulary.
|
|
func RegisterUpdate(api huma.API) {
|
|
huma.Register(api, huma.Operation{
|
|
OperationID: "meta-update",
|
|
Method: "POST",
|
|
Path: "/api/update",
|
|
Summary: "Update nadir to the latest release",
|
|
Description: "Equivalent to running `sudo nadir update` on the host: queries server.release_repo for the latest release, downloads the binary matching the host's architecture, atomically replaces the running binary, and restarts the systemd unit. Returns 202 immediately; the service restart drops in-flight connections, so poll /api/health to confirm the new version is up. Requires the wildcard admin role.",
|
|
Tags: []string{"Meta"},
|
|
Metadata: map[string]any{"module": "meta", "permission": "root"},
|
|
Errors: []int{401, 403, 500},
|
|
DefaultStatus: 202,
|
|
}, func(ctx context.Context, _ *struct{}) (*oscmd.StatusOutput, error) {
|
|
exe, err := os.Executable()
|
|
if err != nil {
|
|
return nil, huma.Error500InternalServerError("could not resolve own binary path", err)
|
|
}
|
|
cmd := exec.Command(exe, "update")
|
|
// Detach from the server's process group so `systemctl restart nadir`
|
|
// (the final step of `nadir update`) doesn't kill its own updater.
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
if err := cmd.Start(); err != nil {
|
|
return nil, huma.Error500InternalServerError("could not start updater", err)
|
|
}
|
|
return oscmd.OK(), nil
|
|
})
|
|
}
|