Files
URBM/cmd/urbmd/main.go
T

92 lines
2.9 KiB
Go

package main
import (
"context"
"flag"
"log/slog"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
"git.casaderoll.de/michael/urbm/internal/api"
"git.casaderoll.de/michael/urbm/internal/notify"
"git.casaderoll.de/michael/urbm/internal/platform"
"git.casaderoll.de/michael/urbm/internal/restic"
"git.casaderoll.de/michael/urbm/internal/rsync"
"git.casaderoll.de/michael/urbm/internal/scheduler"
"git.casaderoll.de/michael/urbm/internal/secrets"
"git.casaderoll.de/michael/urbm/internal/service"
"git.casaderoll.de/michael/urbm/internal/store"
)
var version = "dev"
func main() {
configDir := flag.String("config-dir", "/boot/config/plugins/urbm", "persistent configuration directory")
runtimeDir := flag.String("runtime-dir", "/run/urbm", "runtime directory")
stateDir := flag.String("state-dir", "/var/lib/urbm", "volatile state directory")
socket := flag.String("socket", "/run/urbm/urbm.sock", "Unix API socket")
flag.Parse()
log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
if err := os.MkdirAll(*runtimeDir, 0750); err != nil {
log.Error("create runtime directory", "error", err)
os.Exit(1)
}
if err := os.MkdirAll(*stateDir, 0750); err != nil {
log.Error("create state directory", "error", err)
os.Exit(1)
}
configStore := store.New(*configDir)
if err := configStore.Init(); err != nil {
log.Error("initialize config store", "error", err)
os.Exit(1)
}
secretStore := secrets.New(filepath.Join(*configDir, "secrets"))
if err := secretStore.Init(); err != nil {
log.Error("initialize secret store", "error", err)
os.Exit(1)
}
config, err := configStore.LoadConfig()
if err != nil {
log.Error("load config", "error", err)
os.Exit(1)
}
rr := &restic.Runner{Binary: config.Settings.ResticPath, RuntimeDir: *runtimeDir, Secrets: secretStore, Log: log}
rs := &rsync.Runner{Binary: config.Settings.RsyncPath}
mounts := &platform.MountManager{RuntimeDir: *runtimeDir, Secrets: secretStore}
workloads := &platform.WorkloadManager{RuntimeDir: *runtimeDir}
notifier := &notify.Sender{Secrets: secretStore}
svc, err := service.New(configStore, secretStore, rr, rs, mounts, workloads, notifier, log)
if err != nil {
log.Error("initialize service", "error", err)
os.Exit(1)
}
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
go svc.RunQueue(ctx)
api.Version = version
sched := scheduler.New(svc.Config, svc.EnqueueScheduled, svc.EnqueueMaintenance, svc.LastRun, log)
go sched.Run(ctx)
server := api.New(*socket, svc, log)
go func() {
if err := server.ListenAndServe(); err != nil {
log.Error("api server stopped", "error", err)
cancel()
}
}()
log.Info("urbm daemon started", "socket", *socket)
<-ctx.Done()
svc.Stop()
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 15*time.Second)
defer shutdownCancel()
_ = server.Shutdown(shutdownCtx)
log.Info("urbm daemon stopped")
}