From 8b4cf40e7bfaf35aad233a4ab4b039b8ef80d659 Mon Sep 17 00:00:00 2001 From: David Prodinger Date: Thu, 14 Nov 2024 17:14:14 +0100 Subject: [PATCH 1/5] feat: systemd improvements Set notify-reload type and use the sd_notify to signal the daemon the readiness of the application --- contrib/coraza-spoa.service | 6 +++--- go.mod | 2 +- go.sum | 3 +-- main.go | 28 ++++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/contrib/coraza-spoa.service b/contrib/coraza-spoa.service index 545aca1..bb068de 100644 --- a/contrib/coraza-spoa.service +++ b/contrib/coraza-spoa.service @@ -4,9 +4,9 @@ Documentation=https://www.coraza.io [Service] ExecStart=/usr/bin/coraza-spoa -config=/etc/coraza-spoa/config.yaml -WorkingDirectory=/ +WorkingDirectory=/etc/coraza-spoa/ Restart=always -Type=exec +Type=notify-reload User=coraza-spoa Group=coraza-spoa @@ -45,7 +45,7 @@ InaccessiblePaths=-/opt InaccessiblePaths=-/srv #InaccessiblePaths=-/bin InaccessiblePaths=-/bin/bash -inaccessiblepaths=-/bin/find +InaccessiblePaths=-/bin/find InaccessiblePaths=-/bin/less InaccessiblePaths=-/bin/zcat InaccessiblePaths=-/bin/rm diff --git a/go.mod b/go.mod index b1bd84a..102d5df 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,11 @@ go 1.23.1 require ( github.com/corazawaf/coraza-coreruleset v0.0.0-20240226094324-415b1017abdc github.com/corazawaf/coraza/v3 v3.2.1 + github.com/coreos/go-systemd/v22 v22.5.0 github.com/dropmorepackets/haproxy-go v0.0.5 github.com/jcchavezs/mergefs v0.0.0-20230503083351-07f27d256761 github.com/magefile/mage v1.15.0 github.com/mccutchen/go-httpbin/v2 v2.14.0 - github.com/pires/go-proxyproto v0.8.0 github.com/rs/zerolog v1.33.0 gopkg.in/yaml.v3 v3.0.1 istio.io/istio v0.0.0-20240218163812-d80ef7b19049 diff --git a/go.sum b/go.sum index 65da1c3..64c7053 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,7 @@ github.com/corazawaf/coraza/v3 v3.2.1 h1:zBIji4ut9FtFe8lXdqFwXMAkUoDJZ7HsOlEUYWE github.com/corazawaf/coraza/v3 v3.2.1/go.mod h1:fVndCGdUHJWl9c26VZPcORQRzUYwMPnRkC6TyTkhbUg= github.com/corazawaf/libinjection-go v0.2.1 h1:vNJ7L6c4xkhRgYU6sIO0Tl54TmeCQv/yfxBma30Dy/Y= github.com/corazawaf/libinjection-go v0.2.1/go.mod h1:OP4TM7xdJ2skyXqNX1AN1wN5nNZEmJNuWbNPOItn7aw= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -30,8 +31,6 @@ github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/petar-dambovaliev/aho-corasick v0.0.0-20240411101913-e07a1f0e8eb4 h1:1Kw2vDBXmjop+LclnzCb/fFy+sgb3gYARwfmoUcQe6o= github.com/petar-dambovaliev/aho-corasick v0.0.0-20240411101913-e07a1f0e8eb4/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw= -github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= -github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/main.go b/main.go index b468dc7..5b91a7e 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,7 @@ import ( "runtime/pprof" "syscall" + "github.com/coreos/go-systemd/v22/daemon" "github.com/rs/zerolog" "github.com/corazawaf/coraza-spoa/internal" @@ -79,8 +80,15 @@ func main() { defer cancelFunc() globalLogger.Info().Msg("Starting coraza-spoa") + + _, err := daemon.SdNotify(false, daemon.SdNotifyReady) + if err != nil { + globalLogger.Error().Err(err).Msg("Failed notifying daemon") + } + if err := a.Serve(l); err != nil { globalLogger.Fatal().Err(err).Msg("listener closed") + _, _ = daemon.SdNotify(false, daemon.SdNotifyStopping) } }() @@ -92,10 +100,20 @@ outer: switch sig { case syscall.SIGTERM: globalLogger.Info().Msg("Received SIGTERM, shutting down...") + + _, err := daemon.SdNotify(false, daemon.SdNotifyStopping) + if err != nil { + globalLogger.Error().Err(err).Msg("Failed notifying daemon") + } // this return will run cancel() and close the server break outer case syscall.SIGINT: globalLogger.Info().Msg("Received SIGINT, shutting down...") + + _, err := daemon.SdNotify(false, daemon.SdNotifyStopping) + if err != nil { + globalLogger.Error().Err(err).Msg("Failed notifying daemon") + } break outer case syscall.SIGHUP: globalLogger.Info().Msg("Received SIGHUP, reloading configuration...") @@ -126,8 +144,18 @@ outer: continue } + _, err = daemon.SdNotify(false, daemon.SdNotifyReloading) + if err != nil { + globalLogger.Error().Err(err).Msg("Failed notifying daemon") + } + a.ReplaceApplications(apps) cfg = newCfg + + _, err = daemon.SdNotify(false, daemon.SdNotifyReady) + if err != nil { + globalLogger.Error().Err(err).Msg("Failed notifying daemon") + } } } From aadee2ce330e7760c2635660c781b378bcfa1cb0 Mon Sep 17 00:00:00 2001 From: David Prodinger Date: Mon, 18 Nov 2024 17:32:14 +0100 Subject: [PATCH 2/5] feat: implement daemon communication directly --- go.mod | 2 +- go.sum | 3 ++- internal/daemon.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ main.go | 25 ++++++++++--------------- 4 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 internal/daemon.go diff --git a/go.mod b/go.mod index 102d5df..b1bd84a 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,11 @@ go 1.23.1 require ( github.com/corazawaf/coraza-coreruleset v0.0.0-20240226094324-415b1017abdc github.com/corazawaf/coraza/v3 v3.2.1 - github.com/coreos/go-systemd/v22 v22.5.0 github.com/dropmorepackets/haproxy-go v0.0.5 github.com/jcchavezs/mergefs v0.0.0-20230503083351-07f27d256761 github.com/magefile/mage v1.15.0 github.com/mccutchen/go-httpbin/v2 v2.14.0 + github.com/pires/go-proxyproto v0.8.0 github.com/rs/zerolog v1.33.0 gopkg.in/yaml.v3 v3.0.1 istio.io/istio v0.0.0-20240218163812-d80ef7b19049 diff --git a/go.sum b/go.sum index 64c7053..65da1c3 100644 --- a/go.sum +++ b/go.sum @@ -4,7 +4,6 @@ github.com/corazawaf/coraza/v3 v3.2.1 h1:zBIji4ut9FtFe8lXdqFwXMAkUoDJZ7HsOlEUYWE github.com/corazawaf/coraza/v3 v3.2.1/go.mod h1:fVndCGdUHJWl9c26VZPcORQRzUYwMPnRkC6TyTkhbUg= github.com/corazawaf/libinjection-go v0.2.1 h1:vNJ7L6c4xkhRgYU6sIO0Tl54TmeCQv/yfxBma30Dy/Y= github.com/corazawaf/libinjection-go v0.2.1/go.mod h1:OP4TM7xdJ2skyXqNX1AN1wN5nNZEmJNuWbNPOItn7aw= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -31,6 +30,8 @@ github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/petar-dambovaliev/aho-corasick v0.0.0-20240411101913-e07a1f0e8eb4 h1:1Kw2vDBXmjop+LclnzCb/fFy+sgb3gYARwfmoUcQe6o= github.com/petar-dambovaliev/aho-corasick v0.0.0-20240411101913-e07a1f0e8eb4/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw= +github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= +github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/internal/daemon.go b/internal/daemon.go new file mode 100644 index 0000000..4fab860 --- /dev/null +++ b/internal/daemon.go @@ -0,0 +1,44 @@ +package internal + +import ( + "net" + "os" + "strconv" + "time" +) + +func SdNotify(message string) error { + socketAddr := &net.UnixAddr{ + Name: os.Getenv("NOTIFY_SOCKET"), + Net: "unixgram", + } + + if socketAddr.Name == "" { + return nil + } + + conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr) + if err != nil { + return err + } + defer conn.Close() + + if _, err = conn.Write([]byte(message)); err != nil { + return err + } + + return nil +} + +func SdNotifyReady() error { + return SdNotify("READY=1") +} + +func SdNotifyReloading() error { + microseconds := time.Now().UnixMicro() + return SdNotify("RELOADING=1\nMONOTONIC_USEC=" + strconv.FormatInt(microseconds, 10)) +} + +func SdNotifyStopping() error { + return SdNotify("STOPPING=1") +} diff --git a/main.go b/main.go index 5b91a7e..cef3df1 100644 --- a/main.go +++ b/main.go @@ -13,7 +13,6 @@ import ( "runtime/pprof" "syscall" - "github.com/coreos/go-systemd/v22/daemon" "github.com/rs/zerolog" "github.com/corazawaf/coraza-spoa/internal" @@ -81,14 +80,13 @@ func main() { globalLogger.Info().Msg("Starting coraza-spoa") - _, err := daemon.SdNotify(false, daemon.SdNotifyReady) + err := internal.SdNotifyReady() if err != nil { globalLogger.Error().Err(err).Msg("Failed notifying daemon") } if err := a.Serve(l); err != nil { globalLogger.Fatal().Err(err).Msg("listener closed") - _, _ = daemon.SdNotify(false, daemon.SdNotifyStopping) } }() @@ -100,20 +98,10 @@ outer: switch sig { case syscall.SIGTERM: globalLogger.Info().Msg("Received SIGTERM, shutting down...") - - _, err := daemon.SdNotify(false, daemon.SdNotifyStopping) - if err != nil { - globalLogger.Error().Err(err).Msg("Failed notifying daemon") - } // this return will run cancel() and close the server break outer case syscall.SIGINT: globalLogger.Info().Msg("Received SIGINT, shutting down...") - - _, err := daemon.SdNotify(false, daemon.SdNotifyStopping) - if err != nil { - globalLogger.Error().Err(err).Msg("Failed notifying daemon") - } break outer case syscall.SIGHUP: globalLogger.Info().Msg("Received SIGHUP, reloading configuration...") @@ -144,7 +132,7 @@ outer: continue } - _, err = daemon.SdNotify(false, daemon.SdNotifyReloading) + err = internal.SdNotifyReloading() if err != nil { globalLogger.Error().Err(err).Msg("Failed notifying daemon") } @@ -152,13 +140,20 @@ outer: a.ReplaceApplications(apps) cfg = newCfg - _, err = daemon.SdNotify(false, daemon.SdNotifyReady) + err = internal.SdNotifyReady() if err != nil { globalLogger.Error().Err(err).Msg("Failed notifying daemon") } } } + globalLogger.Info().Msg("Stopping coraza-spoa") + + err = internal.SdNotifyStopping() + if err != nil { + globalLogger.Error().Err(err).Msg("Failed notifying daemon") + } + if memProfile != "" { f, err := os.Create(memProfile) if err != nil { From b76443809be623dd374f9e81be67e3d368e367ea Mon Sep 17 00:00:00 2001 From: David Prodinger Date: Tue, 19 Nov 2024 17:15:47 +0100 Subject: [PATCH 3/5] fix(systemd): change type to notify Debian 12 doesn't support the new notify-reload type, therefore selecting the notify type --- contrib/coraza-spoa.service | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/contrib/coraza-spoa.service b/contrib/coraza-spoa.service index bb068de..7f3642b 100644 --- a/contrib/coraza-spoa.service +++ b/contrib/coraza-spoa.service @@ -1,12 +1,17 @@ [Unit] Description=Coraza WAF SPOA Daemon Documentation=https://www.coraza.io +After=network.target [Service] ExecStart=/usr/bin/coraza-spoa -config=/etc/coraza-spoa/config.yaml +ExecReload=/bin/kill -HUP $MAINPID WorkingDirectory=/etc/coraza-spoa/ Restart=always -Type=notify-reload +Type=notify +# notify-reload is pretty new and isn't available on debian 12 +#Type=notify-reload +NotifyAccess=all User=coraza-spoa Group=coraza-spoa @@ -105,7 +110,7 @@ InaccessiblePaths=-/usr/bin/htop InaccessiblePaths=-/usr/bin/ipcmk InaccessiblePaths=-/usr/bin/journalctl InaccessiblePaths=-/usr/bin/keyctl -InaccessiblePaths=-/usr/bin/kill +# InaccessiblePaths=-/usr/bin/kill InaccessiblePaths=-/usr/bin/killall InaccessiblePaths=-/usr/bin/ksh InaccessiblePaths=-/usr/bin/last @@ -293,7 +298,7 @@ PrivateTmp=true RemoveIPC=true -RestrictAddressFamilies=AF_INET AF_INET6 +RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX #RestrictNamespaces=uts ipc pid user cgroup SystemCallArchitectures=native From 95fd3ba39643af9e69e35bc51f10ff2a0b97cbcd Mon Sep 17 00:00:00 2001 From: David Prodinger Date: Wed, 20 Nov 2024 15:34:29 +0100 Subject: [PATCH 4/5] feat(systemd): put messages in const do not use the extra functions for the SdNotify Allow multiple parameters, which are joined into separate lines Add logging hook on fatal level to send message as STOPPING=1\nSTATUS=[msg] to the service manager --- daemon.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++ internal/daemon.go | 44 ---------------------------------------- main.go | 20 ++++++++++++++----- 3 files changed, 65 insertions(+), 49 deletions(-) create mode 100644 daemon.go delete mode 100644 internal/daemon.go diff --git a/daemon.go b/daemon.go new file mode 100644 index 0000000..b06d6d0 --- /dev/null +++ b/daemon.go @@ -0,0 +1,50 @@ +// This provides the functionality for notifying the service manager about status changes via sd_notify +// see https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html +package main + +import ( + "net" + "os" + "strings" +) + +const ( + // SdNotifyReady Tells the service manager that service startup is finished, or the service finished re-loading its configuration. + SdNotifyReady = "READY=1" + + // SdNotifyReloading Tells the service manager that the service is beginning to reload its configuration. + SdNotifyReloading = "RELOADING=1" + + // SdNotifyStopping Tells the service manager that the service is beginning its shutdown. + SdNotifyStopping = "STOPPING=1" + + // SdNotifyStatus Passes a single-line UTF-8 status string back to the service manager that describes the service state. + SdNotifyStatus = "STATUS=" +) + +// SdNotify Communicates with the NOTIFY_SOCKET +// Accepts +// Returns nil, if the socket doesn't exist, or the message was sent successfully +// Returns an error, if the message wasn't sent successfully +func SdNotify(messages ...string) error { + socketAddr := &net.UnixAddr{ + Name: os.Getenv("NOTIFY_SOCKET"), + Net: "unixgram", + } + + if socketAddr.Name == "" { + return nil + } + + conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr) + if err != nil { + return err + } + defer conn.Close() + + if _, err = conn.Write([]byte(strings.Join(messages, "\n"))); err != nil { + return err + } + + return nil +} diff --git a/internal/daemon.go b/internal/daemon.go deleted file mode 100644 index 4fab860..0000000 --- a/internal/daemon.go +++ /dev/null @@ -1,44 +0,0 @@ -package internal - -import ( - "net" - "os" - "strconv" - "time" -) - -func SdNotify(message string) error { - socketAddr := &net.UnixAddr{ - Name: os.Getenv("NOTIFY_SOCKET"), - Net: "unixgram", - } - - if socketAddr.Name == "" { - return nil - } - - conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr) - if err != nil { - return err - } - defer conn.Close() - - if _, err = conn.Write([]byte(message)); err != nil { - return err - } - - return nil -} - -func SdNotifyReady() error { - return SdNotify("READY=1") -} - -func SdNotifyReloading() error { - microseconds := time.Now().UnixMicro() - return SdNotify("RELOADING=1\nMONOTONIC_USEC=" + strconv.FormatInt(microseconds, 10)) -} - -func SdNotifyStopping() error { - return SdNotify("STOPPING=1") -} diff --git a/main.go b/main.go index cef3df1..173e73e 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ package main import ( "context" "flag" + "fmt" "net" "os" "os/signal" @@ -18,10 +19,19 @@ import ( "github.com/corazawaf/coraza-spoa/internal" ) +type SeverityHook struct{} + +func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) { + if level == zerolog.FatalLevel { + _ = SdNotify(SdNotifyStopping, fmt.Sprintf("%s%s", SdNotifyStatus, msg)) + } +} + var configPath string var cpuProfile string var memProfile string -var globalLogger = zerolog.New(os.Stderr).With().Timestamp().Logger() +var hook SeverityHook +var globalLogger = zerolog.New(os.Stderr).Hook(hook).With().Timestamp().Logger() func main() { flag.StringVar(&cpuProfile, "cpuprofile", "", "write cpu profile to `file`") @@ -80,7 +90,7 @@ func main() { globalLogger.Info().Msg("Starting coraza-spoa") - err := internal.SdNotifyReady() + err := SdNotify(SdNotifyReady) if err != nil { globalLogger.Error().Err(err).Msg("Failed notifying daemon") } @@ -132,7 +142,7 @@ outer: continue } - err = internal.SdNotifyReloading() + err = SdNotify(SdNotifyReloading) if err != nil { globalLogger.Error().Err(err).Msg("Failed notifying daemon") } @@ -140,7 +150,7 @@ outer: a.ReplaceApplications(apps) cfg = newCfg - err = internal.SdNotifyReady() + err = SdNotify(SdNotifyReady) if err != nil { globalLogger.Error().Err(err).Msg("Failed notifying daemon") } @@ -149,7 +159,7 @@ outer: globalLogger.Info().Msg("Stopping coraza-spoa") - err = internal.SdNotifyStopping() + err = SdNotify(SdNotifyStopping) if err != nil { globalLogger.Error().Err(err).Msg("Failed notifying daemon") } From 4b6ce904b308a2e1e77c37d14956bba3a360bc4a Mon Sep 17 00:00:00 2001 From: David Prodinger Date: Mon, 25 Nov 2024 18:13:54 +0100 Subject: [PATCH 5/5] test: add unit tests for sd_notify functionality --- daemon_test.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 daemon_test.go diff --git a/daemon_test.go b/daemon_test.go new file mode 100644 index 0000000..1fc1164 --- /dev/null +++ b/daemon_test.go @@ -0,0 +1,94 @@ +package main + +import ( + "net" + "os" + "strings" + "testing" +) + +func TestSdNotify(t *testing.T) { + socketAddr := &net.UnixAddr{ + Name: "/tmp/coraza-spoa-daemon.sock", + Net: "unixgram", + } + socket, err := net.ListenUnixgram(socketAddr.Net, socketAddr) + if err != nil { + t.Fatal(err) + } + + defer os.Remove(socketAddr.Name) + + t.Setenv("NOTIFY_SOCKET", socketAddr.Name) + + tests := []struct { + name string + messages []string + }{ + { + "Ready", + []string{SdNotifyReady}, + }, + { + "Reloading", + []string{SdNotifyReloading}, + }, + { + "Stopping", + []string{SdNotifyStopping}, + }, + { + "Ready with status", + []string{SdNotifyReady, SdNotifyStatus + "Test Ready"}, + }, + { + "Reloading with status", + []string{SdNotifyReloading, SdNotifyStatus + "Test Reloading"}, + }, + { + "Stopping with status", + []string{SdNotifyStopping, SdNotifyStatus + "Test Stopping"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := SdNotify(tt.messages...) + if err != nil { + t.Errorf("SdNotify() error = %v", err) + } + + // getting the messages + var buf [1024]byte + n, err := socket.Read(buf[:]) + if err != nil { + t.Fatal(err) + } + + var received = string(buf[:n]) + var expected = strings.Join(tt.messages, "\n") + if received != expected { + t.Errorf("SdNotify() = returned:\n---\n%v\n---\nWanted:\n---\n%v\n---", received, expected) + } + }) + } +} + +func TestSdNotify_NoSocketSet(t *testing.T) { + t.Setenv("NOTIFY_SOCKET", "") + + err := SdNotify(SdNotifyReady) + if err != nil { + t.Errorf("SdNotify() error = not nil, %v", err) + } +} + +func TestSdNotify_WrongSocketSet(t *testing.T) { + t.Setenv("NOTIFY_SOCKET", "/tmp/coraza-spoa-wrong.sock") + + err := SdNotify(SdNotifyReady) + if err != nil && err.Error() == "dial unixgram /tmp/coraza-spoa-wrong.sock: connect: no such file or directory" { + return + } + t.Error("SdNotify() no error") +}