Correct backend cleanup and return code (#268)

The backend cleanup was only called from the signal handler, defer was ignored. Now there's proper messages and return codes

time="03-05-2023 12:43:02" level=info msg="6987 decisions added"
time="03-05-2023 12:43:10" level=info msg="Shutting down backend"
time="03-05-2023 12:43:10" level=info msg="removing 'crowdsec' table"
time="03-05-2023 12:43:10" level=info msg="removing 'crowdsec6' table"
time="03-05-2023 12:43:10" level=fatal msg="process terminating with error: received SIGTERM"
This commit is contained in:
mmetc
2023-05-04 10:20:51 +02:00
committed by GitHub
parent 9f27212e5b
commit 8b3009d717
2 changed files with 31 additions and 29 deletions

View File

@@ -31,29 +31,23 @@ const (
name = "crowdsec-firewall-bouncer" name = "crowdsec-firewall-bouncer"
) )
func termHandler(sig os.Signal, backend *backend.BackendCTX) error {
if err := backend.ShutDown(); err != nil {
return err
}
return nil
}
func backendCleanup(backend *backend.BackendCTX) { func backendCleanup(backend *backend.BackendCTX) {
log.Info("Shutting down backend")
if err := backend.ShutDown(); err != nil { if err := backend.ShutDown(); err != nil {
log.Errorf("unable to shutdown backend: %s", err) log.Errorf("unable to shutdown backend: %s", err)
} }
} }
func HandleSignals(backend *backend.BackendCTX) { func HandleSignals(ctx context.Context) error {
signalChan := make(chan os.Signal, 1) signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGTERM) signal.Notify(signalChan, syscall.SIGTERM)
s := <-signalChan select {
if err := termHandler(s, backend); err != nil { case <-signalChan:
log.Fatalf("shutdown fail: %s", err) return fmt.Errorf("received SIGTERM")
case <-ctx.Done():
return ctx.Err()
} }
log.Infof("Shutting down firewall-bouncer service")
os.Exit(0)
} }
func deleteDecisions(backend *backend.BackendCTX, decisions []*models.Decision, config *cfg.BouncerConfig) { func deleteDecisions(backend *backend.BackendCTX, decisions []*models.Decision, config *cfg.BouncerConfig) {
@@ -119,7 +113,7 @@ func addDecisions(backend *backend.BackendCTX, decisions []*models.Decision, con
} }
} }
func Execute() { func Execute() error {
var err error var err error
configPath := flag.String("c", "", "path to crowdsec-firewall-bouncer.yaml") configPath := flag.String("c", "", "path to crowdsec-firewall-bouncer.yaml")
verbose := flag.Bool("v", false, "set verbose mode") verbose := flag.Bool("v", false, "set verbose mode")
@@ -136,17 +130,17 @@ func Execute() {
log.Infof("crowdsec-firewall-bouncer %s", version.VersionStr()) log.Infof("crowdsec-firewall-bouncer %s", version.VersionStr())
if configPath == nil || *configPath == "" { if configPath == nil || *configPath == "" {
log.Fatalf("configuration file is required") return fmt.Errorf("configuration file is required")
} }
configBytes, err := cfg.MergedConfig(*configPath) configBytes, err := cfg.MergedConfig(*configPath)
if err != nil { if err != nil {
log.Fatalf("unable to read config file: %s", err) return fmt.Errorf("unable to read config file: %w", err)
} }
config, err := cfg.NewConfig(bytes.NewReader(configBytes)) config, err := cfg.NewConfig(bytes.NewReader(configBytes))
if err != nil { if err != nil {
log.Fatalf("unable to load configuration: %s", err) return fmt.Errorf("unable to load configuration: %w", err)
} }
if *verbose { if *verbose {
@@ -155,7 +149,7 @@ func Execute() {
backend, err := backend.NewBackend(config) backend, err := backend.NewBackend(config)
if err != nil { if err != nil {
log.Fatal(err) return err
} }
if *testConfig { if *testConfig {
@@ -164,21 +158,19 @@ func Execute() {
} }
if err = backend.Init(); err != nil { if err = backend.Init(); err != nil {
log.Fatal(err) return err
} }
// No call to fatalf after this point
defer backendCleanup(backend) defer backendCleanup(backend)
bouncer := &csbouncer.StreamBouncer{} bouncer := &csbouncer.StreamBouncer{}
err = bouncer.ConfigReader(bytes.NewReader(configBytes)) err = bouncer.ConfigReader(bytes.NewReader(configBytes))
if err != nil { if err != nil {
log.Errorf("unable to configure bouncer: %s", err) return fmt.Errorf("unable to configure bouncer: %w", err)
return
} }
bouncer.UserAgent = fmt.Sprintf("%s/%s", name, version.VersionStr()) bouncer.UserAgent = fmt.Sprintf("%s/%s", name, version.VersionStr())
if err := bouncer.Init(); err != nil { if err := bouncer.Init(); err != nil {
log.Error(err) return err
return
} }
if bouncer.InsecureSkipVerify != nil { if bouncer.InsecureSkipVerify != nil {
@@ -213,7 +205,6 @@ func Execute() {
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
log.Info("terminating bouncer process")
return nil return nil
case decisions := <-bouncer.Stream: case decisions := <-bouncer.Stream:
if decisions == nil { if decisions == nil {
@@ -230,10 +221,14 @@ func Execute() {
if !sent && err != nil { if !sent && err != nil {
log.Errorf("Failed to notify: %v", err) log.Errorf("Failed to notify: %v", err)
} }
go HandleSignals(backend) g.Go(func() error {
return HandleSignals(ctx)
})
} }
if err := g.Wait(); err != nil { if err := g.Wait(); err != nil {
log.Errorf("process return with error: %s", err) return fmt.Errorf("process terminated with error: %w", err)
} }
return nil
} }

11
main.go
View File

@@ -1,7 +1,14 @@
package main package main
import "github.com/crowdsecurity/cs-firewall-bouncer/cmd" import (
log "github.com/sirupsen/logrus"
"github.com/crowdsecurity/cs-firewall-bouncer/cmd"
)
func main() { func main() {
cmd.Execute() err := cmd.Execute()
if err != nil {
log.Fatal(err)
}
} }