95 lines
3.0 KiB
Go
95 lines
3.0 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 := ¬ify.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)
|
|
if err := svc.Wait(shutdownCtx); err != nil {
|
|
log.Warn("queue cleanup did not finish before shutdown timeout", "error", err)
|
|
}
|
|
log.Info("urbm daemon stopped")
|
|
}
|