Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions controller/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func Execute() {
ctx, cancel := context.WithCancel(context.Background())

go serveMetrics(cfg.MetricsAddress)
go handleSigterm(cancel)
setupSigtermHandler(cancel)

endpointsSource, err := buildSource(ctx, cfg)
if err != nil {
Expand Down Expand Up @@ -474,14 +474,16 @@ func createDomainFilter(cfg *externaldns.Config) *endpoint.DomainFilter {
}
}

// handleSigterm listens for a SIGTERM signal and triggers the provided cancel function
// setupSigtermHandler start a routine that listens for a SIGTERM signal and triggers the provided cancel function
// to gracefully terminate the application. It logs a message when the signal is received.
func handleSigterm(cancel func()) {
func setupSigtermHandler(cancel func()) {
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGTERM)
<-signals
log.Info("Received SIGTERM. Terminating...")
cancel()
go func() {
<-signals
log.Info("Received SIGTERM. Terminating...")
cancel()
}()
}

// serveMetrics starts an HTTP server that serves health and metrics endpoints.
Expand Down
37 changes: 37 additions & 0 deletions controller/execute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import (
"net/http/httptest"
"os"
"os/exec"
"os/signal"
"reflect"
"regexp"
"syscall"
"testing"
"time"

Expand All @@ -34,6 +36,7 @@ import (
"github.com/stretchr/testify/require"

"sigs.k8s.io/external-dns/endpoint"
"sigs.k8s.io/external-dns/internal/testutils"
"sigs.k8s.io/external-dns/pkg/apis/externaldns"
"sigs.k8s.io/external-dns/provider"
fakeprovider "sigs.k8s.io/external-dns/provider/fakes"
Expand Down Expand Up @@ -219,6 +222,40 @@ func TestSelectRegistry(t *testing.T) {
}
}

func TestSetupSigtermHandler(t *testing.T) {
cancelCalled := make(chan bool, 1)
cancel := func() {
cancelCalled <- true
}

hook := testutils.LogsUnderTestWithLogLevel(log.InfoLevel, t)

defer signal.Reset(syscall.SIGTERM)
setupSigtermHandler(cancel)

// Simulate sending a SIGTERM signal
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGTERM)
err := syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
assert.NoError(t, err)

// Wait for the signal to be received
select {
case sig := <-sigChan:
assert.Equal(t, syscall.SIGTERM, sig)
case <-time.After(1 * time.Second):
t.Fatal("signal was not recieved")
}

// Wait for the cancel function to be called
select {
case <-cancelCalled:
testutils.TestHelperLogContainsWithLogLevel("Received SIGTERM. Terminating...", log.InfoLevel, hook, t)
case <-time.After(1 * time.Second):
t.Fatal("cancel function was not called")
}
}

// Provider
func TestBuildProvider(t *testing.T) {
tests := []struct {
Expand Down