// tera-alarmd is the bounded alarm delivery and retry service. package main import ( "errors" "log" "net" "os" "os/signal" "path/filepath" "strconv" "syscall" "tera-clone/services/tera-api/internal/alarmdelivery" "tera-clone/services/tera-api/internal/alarmdelivery/alarmsocket" "tera-clone/services/tera-api/internal/secretstore" ) func main() { secretPath := getenv("TERA_ALARMD_SECRET_STORE", "/var/lib/tera-api/secrets.json") _, err := secretstore.Open(secretPath) if err != nil { log.Fatalf("tera-alarmd secret store setup failed: %v", err) } secrets := secretstore.FileReader{Path: secretPath} dispatcher, err := alarmdelivery.NewDispatcher(map[string]alarmdelivery.Transport{ alarmdelivery.ChannelWeb: alarmdelivery.WebTransport{}, alarmdelivery.ChannelSyslog: alarmdelivery.SyslogTransport{}, alarmdelivery.ChannelEmail: alarmdelivery.EmailTransport{Secrets: secrets}, alarmdelivery.ChannelSNMPTrap: alarmdelivery.SNMPTrapTransport{Secrets: secrets}, }, alarmdelivery.DispatcherOptions{ StatePath: getenv("TERA_ALARMD_STATE", "/var/lib/tera-alarmd/deliveries.json"), MaxJobs: getenvInt("TERA_ALARMD_MAX_JOBS", 256), }) if err != nil { log.Fatalf("tera-alarmd dispatcher setup failed: %v", err) } defer dispatcher.Close() socketPath := getenv("TERA_ALARMD_SOCKET", alarmsocket.DefaultSocketPath) listener, err := listen(socketPath) if err != nil { log.Fatalf("tera-alarmd socket setup failed: %v", err) } defer func() { _ = listener.Close() _ = os.Remove(socketPath) }() server := alarmsocket.Server{Controller: dispatcher} done := make(chan error, 1) go func() { done <- server.Serve(listener) }() log.Printf("tera-alarmd serving delivery control on %s", socketPath) signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) select { case signal := <-signals: log.Printf("tera-alarmd stopping after %s", signal) _ = listener.Close() if err := <-done; err != nil { log.Printf("tera-alarmd stop error: %v", err) } case err := <-done: if err != nil { log.Fatalf("tera-alarmd failed: %v", err) } } } func listen(socketPath string) (net.Listener, error) { if socketPath == "" || !filepath.IsAbs(socketPath) { return nil, errors.New("TERA_ALARMD_SOCKET must be an absolute path") } if err := os.MkdirAll(filepath.Dir(socketPath), 0o750); err != nil { return nil, err } if info, err := os.Lstat(socketPath); err == nil { if info.Mode()&os.ModeSocket == 0 { return nil, errors.New("refusing to replace non-socket alarm delivery path") } if err := os.Remove(socketPath); err != nil { return nil, err } } else if !os.IsNotExist(err) { return nil, err } listener, err := net.Listen("unix", socketPath) if err != nil { return nil, err } if err := os.Chmod(socketPath, 0o660); err != nil { _ = listener.Close() return nil, err } return listener, nil } func getenv(key, fallback string) string { if value := os.Getenv(key); value != "" { return value } return fallback } func getenvInt(key string, fallback int) int { value, err := strconv.Atoi(os.Getenv(key)) if err != nil || value <= 0 { return fallback } return value }