Skip to content

Commit 865d56a

Browse files
authored
Merge pull request #1588 from sbueringer/pr-enable-webhook-started-readiness-check
✨ add health check for webhook server
2 parents 40cffdc + 0fd3e3f commit 865d56a

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

pkg/webhook/server.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ import (
2828
"path/filepath"
2929
"strconv"
3030
"sync"
31+
"time"
3132

3233
"k8s.io/apimachinery/pkg/runtime"
3334
kscheme "k8s.io/client-go/kubernetes/scheme"
3435
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
36+
"sigs.k8s.io/controller-runtime/pkg/healthz"
3537
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
3638
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
3739
)
@@ -87,6 +89,10 @@ type Server struct {
8789
// defaultingOnce ensures that the default fields are only ever set once.
8890
defaultingOnce sync.Once
8991

92+
// started is set to true immediately before the server is started
93+
// and thus can be used to check if the server has been started
94+
started bool
95+
9096
// mu protects access to the webhook map & setFields for Start, Register, etc
9197
mu sync.Mutex
9298
}
@@ -272,6 +278,9 @@ func (s *Server) Start(ctx context.Context) error {
272278
close(idleConnsClosed)
273279
}()
274280

281+
s.mu.Lock()
282+
s.started = true
283+
s.mu.Unlock()
275284
if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
276285
return err
277286
}
@@ -280,6 +289,27 @@ func (s *Server) Start(ctx context.Context) error {
280289
return nil
281290
}
282291

292+
// StartedChecker returns an healthz.Checker which is healthy after the
293+
// server has been started.
294+
func (s *Server) StartedChecker() healthz.Checker {
295+
return func(req *http.Request) error {
296+
s.mu.Lock()
297+
defer s.mu.Unlock()
298+
299+
if !s.started {
300+
return fmt.Errorf("webhook server has not been started yet")
301+
}
302+
303+
conn, err := net.DialTimeout("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), 10*time.Second)
304+
if err != nil {
305+
return fmt.Errorf("webhook server is not reachable: %v", err)
306+
}
307+
conn.Close()
308+
309+
return nil
310+
}
311+
}
312+
283313
// InjectFunc injects the field setter into the server.
284314
func (s *Server) InjectFunc(f inject.Func) error {
285315
s.setFields = f

pkg/webhook/server_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ var _ = Describe("Webhook Server", func() {
128128
It("should serve a webhook on the requested path", func() {
129129
server.Register("/somepath", &testHandler{})
130130

131+
Expect(server.StartedChecker()(nil)).ToNot(Succeed())
132+
131133
doneCh := startServer()
132134

133135
Eventually(func() ([]byte, error) {
@@ -137,6 +139,8 @@ var _ = Describe("Webhook Server", func() {
137139
return ioutil.ReadAll(resp.Body)
138140
}).Should(Equal([]byte("gadzooks!")))
139141

142+
Expect(server.StartedChecker()(nil)).To(Succeed())
143+
140144
ctxCancel()
141145
Eventually(doneCh, "4s").Should(BeClosed())
142146
})

0 commit comments

Comments
 (0)