From 8b8d524c52b94f4abaf432d2c69b90b615544081 Mon Sep 17 00:00:00 2001 From: Stefan Bueringer Date: Fri, 9 Jul 2021 17:50:20 +0200 Subject: [PATCH 1/2] make it possible to monitor if the webhook server has been started MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Büringer buringerst@vmware.com --- pkg/webhook/server.go | 21 +++++++++++++++++++++ pkg/webhook/server_test.go | 2 ++ 2 files changed, 23 insertions(+) diff --git a/pkg/webhook/server.go b/pkg/webhook/server.go index 99b6ae9eb4..2c7a012f7d 100644 --- a/pkg/webhook/server.go +++ b/pkg/webhook/server.go @@ -32,6 +32,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" kscheme "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/certwatcher" + "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/runtime/inject" "sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics" ) @@ -87,6 +88,10 @@ type Server struct { // defaultingOnce ensures that the default fields are only ever set once. defaultingOnce sync.Once + // started is set to true immediately before the server is started + // and thus can be used to check if the server has been started + started bool + // mu protects access to the webhook map & setFields for Start, Register, etc mu sync.Mutex } @@ -272,6 +277,9 @@ func (s *Server) Start(ctx context.Context) error { close(idleConnsClosed) }() + s.mu.Lock() + s.started = true + s.mu.Unlock() if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed { return err } @@ -280,6 +288,19 @@ func (s *Server) Start(ctx context.Context) error { return nil } +// StartedChecker returns an healthz.Checker which is healthy after the +// server has been started. +func (s *Server) StartedChecker() healthz.Checker { + return func(req *http.Request) error { + s.mu.Lock() + defer s.mu.Unlock() + if !s.started { + return fmt.Errorf("webhook server has not been started yet") + } + return nil + } +} + // InjectFunc injects the field setter into the server. func (s *Server) InjectFunc(f inject.Func) error { s.setFields = f diff --git a/pkg/webhook/server_test.go b/pkg/webhook/server_test.go index ca7da4ce49..310a88b246 100644 --- a/pkg/webhook/server_test.go +++ b/pkg/webhook/server_test.go @@ -137,6 +137,8 @@ var _ = Describe("Webhook Server", func() { return ioutil.ReadAll(resp.Body) }).Should(Equal([]byte("gadzooks!"))) + Expect(server.StartedChecker()(nil)).To(Succeed()) + ctxCancel() Eventually(doneCh, "4s").Should(BeClosed()) }) From 0fd3e3f45db1afdbbfba3bd5f22d2f0ff90b9b40 Mon Sep 17 00:00:00 2001 From: Stefan Bueringer Date: Fri, 9 Jul 2021 21:09:58 +0200 Subject: [PATCH 2/2] also ping the webhook server after start --- pkg/webhook/server.go | 9 +++++++++ pkg/webhook/server_test.go | 2 ++ 2 files changed, 11 insertions(+) diff --git a/pkg/webhook/server.go b/pkg/webhook/server.go index 2c7a012f7d..0895397fcb 100644 --- a/pkg/webhook/server.go +++ b/pkg/webhook/server.go @@ -28,6 +28,7 @@ import ( "path/filepath" "strconv" "sync" + "time" "k8s.io/apimachinery/pkg/runtime" kscheme "k8s.io/client-go/kubernetes/scheme" @@ -294,9 +295,17 @@ func (s *Server) StartedChecker() healthz.Checker { return func(req *http.Request) error { s.mu.Lock() defer s.mu.Unlock() + if !s.started { return fmt.Errorf("webhook server has not been started yet") } + + conn, err := net.DialTimeout("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), 10*time.Second) + if err != nil { + return fmt.Errorf("webhook server is not reachable: %v", err) + } + conn.Close() + return nil } } diff --git a/pkg/webhook/server_test.go b/pkg/webhook/server_test.go index 310a88b246..03323eede8 100644 --- a/pkg/webhook/server_test.go +++ b/pkg/webhook/server_test.go @@ -128,6 +128,8 @@ var _ = Describe("Webhook Server", func() { It("should serve a webhook on the requested path", func() { server.Register("/somepath", &testHandler{}) + Expect(server.StartedChecker()(nil)).ToNot(Succeed()) + doneCh := startServer() Eventually(func() ([]byte, error) {