-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhttp_server.go
131 lines (109 loc) · 3.22 KB
/
http_server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"context"
"crypto/tls"
"log/slog"
"net/http"
"os"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"k8s.io/apiserver/pkg/authentication/authenticator"
)
const (
patternGetNamespaces string = "GET /api/v1/namespaces"
)
type NamespaceListerServer struct {
*http.Server
useTLS bool
tlsOpts []func(*tls.Config)
}
func addInjectLoggerMiddleware(l *slog.Logger, next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := setLoggerIntoContext(r.Context(), l)
next.ServeHTTP(w, r.WithContext(ctx))
}
}
func addLogRequestMiddleware(next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := getLoggerFromContext(r.Context())
l.Info("received request", "request", r.URL.Path)
next.ServeHTTP(w, r)
}
}
func addAuthnMiddleware(ar authenticator.Request, next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
rs, ok, err := ar.AuthenticateRequest(r)
switch {
case err != nil: // error contacting the APIServer for authenticating the request
w.WriteHeader(http.StatusUnauthorized)
l := getLoggerFromContext(r.Context())
l.Error("error authenticating request", "error", err, "request-headers", r.Header)
return
case !ok: // request could not be authenticated
w.WriteHeader(http.StatusUnauthorized)
return
default: // request is authenticated
// Inject authentication details into request context
ctx := r.Context()
authCtx := context.WithValue(ctx, ContextKeyUserDetails, rs)
// serve next request
next.ServeHTTP(w, r.WithContext(authCtx))
}
}
}
func NewServer(l *slog.Logger, ar authenticator.Request, lister NamespaceLister) *NamespaceListerServer {
reg := prometheus.NewRegistry()
// configure the server
h := http.NewServeMux()
h.Handle(patternGetNamespaces,
AddMetricsMiddleware(reg,
addInjectLoggerMiddleware(l,
addLogRequestMiddleware(
addAuthnMiddleware(ar,
NewListNamespacesHandler(lister))))))
h.Handle("/metrics",
promhttp.HandlerFor(reg, promhttp.HandlerOpts{
Registry: reg,
}))
return &NamespaceListerServer{
Server: &http.Server{
Addr: getAddress(),
Handler: h,
ReadHeaderTimeout: 3 * time.Second,
},
}
}
func (s *NamespaceListerServer) WithTLS(enableTLS bool) *NamespaceListerServer {
s.useTLS = enableTLS
return s
}
func (s *NamespaceListerServer) WithTLSOpts(tlsOpts ...func(*tls.Config)) *NamespaceListerServer {
s.tlsOpts = tlsOpts
return s
}
func (s *NamespaceListerServer) Start(ctx context.Context) error {
// HTTP Server graceful shutdown
go func() {
<-ctx.Done()
sctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
//nolint:contextcheck
if err := s.Shutdown(sctx); err != nil {
getLoggerFromContext(ctx).Error("error gracefully shutting down the HTTP server", "error", err)
os.Exit(1)
}
}()
// setup and serve over TLS if configured
if s.useTLS {
s.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
}
for _, fun := range s.tlsOpts {
fun(s.TLSConfig)
}
return s.ListenAndServeTLS("", "")
}
// start server
return s.ListenAndServe()
}