7
7
"errors"
8
8
"fmt"
9
9
"io"
10
+ "net"
10
11
"net/http"
11
12
"os"
12
13
"strings"
@@ -25,6 +26,7 @@ import (
25
26
"k8s.io/client-go/kubernetes"
26
27
clientgocorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
27
28
"k8s.io/client-go/tools/record"
29
+ "k8s.io/klog/v2"
28
30
"sigs.k8s.io/controller-runtime/pkg/manager"
29
31
30
32
"github.com/jetstack/preflight/api"
@@ -50,7 +52,12 @@ const schemaVersion string = "v2.0.0"
50
52
// Run starts the agent process
51
53
func Run (cmd * cobra.Command , args []string ) {
52
54
logs .Log .Printf ("Preflight agent version: %s (%s)" , version .PreflightVersion , version .Commit )
53
- ctx , cancel := context .WithCancel (context .Background ())
55
+ ctx , cancel := context .WithCancel (
56
+ klog .NewContext (
57
+ context .Background (),
58
+ klog .Background (),
59
+ ),
60
+ )
54
61
defer cancel ()
55
62
56
63
file , err := os .Open (Flags .ConfigFilePath )
@@ -83,11 +90,13 @@ func Run(cmd *cobra.Command, args []string) {
83
90
}
84
91
}()
85
92
86
- group . Go ( func () error {
93
+ {
87
94
server := http .NewServeMux ()
95
+ const serverAddress = ":8081"
96
+ log := klog .FromContext (ctx ).WithName ("APIServer" ).WithValues ("addr" , serverAddress )
88
97
89
98
if Flags .Profiling {
90
- logs . Log . Printf ( "pprof profiling was enabled. " )
99
+ log . Info ( "Profiling endpoints enabled" , "path" , "/debug/pprof " )
91
100
server .HandleFunc ("/debug/pprof/" , pprof .Index )
92
101
server .HandleFunc ("/debug/pprof/cmdline" , pprof .Cmdline )
93
102
server .HandleFunc ("/debug/pprof/profile" , pprof .Profile )
@@ -96,7 +105,7 @@ func Run(cmd *cobra.Command, args []string) {
96
105
}
97
106
98
107
if Flags .Prometheus {
99
- logs . Log . Printf ( "Prometheus was enabled. \n Running prometheus on port :8081 " )
108
+ log . Info ( "Metrics endpoints enabled" , "path" , "/metrics " )
100
109
prometheus .MustRegister (metricPayloadSize )
101
110
server .Handle ("/metrics" , promhttp .Handler ())
102
111
}
@@ -105,21 +114,32 @@ func Run(cmd *cobra.Command, args []string) {
105
114
// what "ready" means for the agent, we just return 200 OK inconditionally.
106
115
// The goal is to satisfy some Kubernetes distributions, like OpenShift,
107
116
// that require a liveness and health probe to be present for each pod.
117
+ log .Info ("Healthz endpoints enabled" , "path" , "/healthz" )
108
118
server .HandleFunc ("/healthz" , func (w http.ResponseWriter , r * http.Request ) {
109
119
w .WriteHeader (http .StatusOK )
110
120
})
121
+ log .Info ("Readyz endpoints enabled" , "path" , "/readyz" )
111
122
server .HandleFunc ("/readyz" , func (w http.ResponseWriter , r * http.Request ) {
112
123
w .WriteHeader (http .StatusOK )
113
124
})
114
125
115
- err := http .ListenAndServe (":8081" , server )
116
- if err != nil && ! errors .Is (err , http .ErrServerClosed ) {
117
- return fmt .Errorf ("failed to run the health check server: %s" , err )
118
- }
119
- // The agent must stop if the management server stops
120
- cancel ()
121
- return nil
122
- })
126
+ group .Go (func () error {
127
+ err := listenAndServe (
128
+ klog .NewContext (gctx , log ),
129
+ & http.Server {
130
+ Addr : serverAddress ,
131
+ Handler : server ,
132
+ BaseContext : func (_ net.Listener ) context.Context {
133
+ return gctx
134
+ },
135
+ },
136
+ )
137
+ if err != nil {
138
+ return fmt .Errorf ("APIServer: %s" , err )
139
+ }
140
+ return nil
141
+ })
142
+ }
123
143
124
144
_ , isVenConn := preflightClient .(* client.VenConnClient )
125
145
if isVenConn {
@@ -412,3 +432,48 @@ func postData(config CombinedConfig, preflightClient client.Client, readings []*
412
432
413
433
return nil
414
434
}
435
+
436
+ // listenAndServe starts the supplied HTTP server and stops it gracefully when
437
+ // the supplied context is cancelled.
438
+ // It returns when the graceful server shutdown is complete or when the server
439
+ // exits with an error.
440
+ // If the server fails to start, it returns the server error.
441
+ // If the server fails to shutdown gracefully, it returns the shutdown error.
442
+ // The server is given 3 seconds to shutdown gracefully before it is stopped
443
+ // forcefully.
444
+ func listenAndServe (ctx context.Context , server * http.Server ) error {
445
+ log := klog .FromContext (ctx ).WithName ("ListenAndServe" )
446
+
447
+ log .V (1 ).Info ("Starting" )
448
+
449
+ listenCTX , listenCancelCause := context .WithCancelCause (context .WithoutCancel (ctx ))
450
+ go func () {
451
+ err := server .ListenAndServe ()
452
+ listenCancelCause (fmt .Errorf ("ListenAndServe: %s" , err ))
453
+ }()
454
+
455
+ select {
456
+ case <- listenCTX .Done ():
457
+ log .V (1 ).Info ("Shutdown skipped" , "reason" , "Server already stopped" )
458
+ return context .Cause (listenCTX )
459
+
460
+ case <- ctx .Done ():
461
+ log .V (1 ).Info ("Shutting down" )
462
+ }
463
+
464
+ shutdownCTX , shutdownCancel := context .WithTimeout (context .WithoutCancel (ctx ), time .Second * 3 )
465
+ shutdownErr := server .Shutdown (shutdownCTX )
466
+ shutdownCancel ()
467
+ if shutdownErr != nil {
468
+ shutdownErr = fmt .Errorf ("Shutdown: %s" , shutdownErr )
469
+ }
470
+
471
+ closeErr := server .Close ()
472
+ if closeErr != nil {
473
+ closeErr = fmt .Errorf ("Close: %s" , closeErr )
474
+ }
475
+
476
+ log .V (1 ).Info ("Shutdown complete" )
477
+
478
+ return errors .Join (shutdownErr , closeErr )
479
+ }
0 commit comments