kubelatte-ce
Форк от sbertech/kubelatte-ce
167 строк · 5.1 Кб
1package webhook
2
3import (
4"context"
5"encoding/json"
6"fmt"
7"gitverse.ru/synapse/kubelatte/pkg/observability/logger"
8"io"
9"k8s.io/api/admission/v1beta1"
10metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11"net/http"
12"strings"
13)
14
15func (whsvr *Server) Healthz(w http.ResponseWriter, _ *http.Request) {
16w.WriteHeader(http.StatusOK)
17}
18
19func (whsvr *Server) Liveness(w http.ResponseWriter, _ *http.Request) {
20w.WriteHeader(http.StatusOK)
21}
22
23func (whsvr *Server) Readyness(w http.ResponseWriter, _ *http.Request) {
24w.WriteHeader(http.StatusOK)
25}
26
27func (whsvr *Server) MutateHandler(w http.ResponseWriter, r *http.Request) {
28ctx := r.Context()
29log := logger.FromContext(ctx)
30
31var admissionResponse *v1beta1.AdmissionResponse
32var body, err = getIncomingRequestBody(ctx, w, r, "mutation")
33if body == nil {
34return
35}
36
37admissionReview := v1beta1.AdmissionReview{}
38_, _, err = deserializer.Decode(body, nil, &admissionReview)
39if err != nil {
40log.Errorf("api=mutateHandler, reason=deserializer.Decode, message=cannot decode body, err=%v", err)
41http.Error(w, "empty body", http.StatusBadRequest)
42admissionResponse = &v1beta1.AdmissionResponse{
43Result: &metav1.Status{
44Message: err.Error(),
45},
46}
47createAdmissionResponse(ctx, w, &admissionReview, admissionResponse)
48return
49}
50
51arfields, _, err := parseRequest(ctx, admissionReview.Request, body)
52if err != nil {
53log.Errorf("api=mutateHandler, reason=deserializer.Decode, message=cannot decode body, err=%v", err)
54http.Error(w, "empty body", http.StatusBadRequest)
55admissionResponse = &v1beta1.AdmissionResponse{
56Result: &metav1.Status{
57Message: err.Error(),
58},
59}
60createAdmissionResponse(ctx, w, &admissionReview, admissionResponse)
61return
62}
63
64patches, _ := whsvr.act.ApplyMutation(ctx, arfields, admissionReview.Request.Object.Raw)
65patches, _ = whsvr.act.StartSideEffect(context.Background(), arfields, patches)
66
67patchBytes, _ := json.Marshal(patches)
68createAdmissionResponse(ctx, w, &admissionReview, &v1beta1.AdmissionResponse{
69Allowed: true,
70Patch: patchBytes,
71PatchType: func() *v1beta1.PatchType {
72pt := v1beta1.PatchTypeJSONPatch
73return &pt
74}(),
75})
76}
77
78func (whsvr *Server) ValidateHandler(w http.ResponseWriter, r *http.Request) {
79ctx := r.Context()
80log := logger.FromContext(ctx)
81if whsvr.state != ServerReady {
82w.WriteHeader(http.StatusServiceUnavailable)
83_, _ = w.Write([]byte(ServerStateText[whsvr.state]))
84return
85}
86
87var body, err = getIncomingRequestBody(ctx, w, r, "validation")
88if body == nil {
89return
90}
91
92admissionResponse := &v1beta1.AdmissionResponse{Allowed: true}
93
94ar := v1beta1.AdmissionReview{}
95_, _, err = deserializer.Decode(body, nil, &ar)
96if err != nil {
97log.Errorf("api=validation, reason=deserializer.Decode, message=cannot decode body, err=%s", err.Error())
98http.Error(w, "empty body", http.StatusBadRequest)
99admissionResponse.Allowed = false
100admissionResponse.Result = &metav1.Status{
101Message: err.Error(),
102}
103} else {
104admissionResponse.UID = ar.Request.UID
105
106requestData, originalRequest, err := parseRequest(ctx, ar.Request, body)
107if err != nil {
108log.Errorf("api=validation, reason=parseRequest, message=could not parse request, err=%s", err.Error())
109http.Error(w, fmt.Sprintf("could not parse request: %v", err), http.StatusBadRequest)
110return
111}
112
113err = whsvr.act.Validate(ctx, originalRequest, *requestData)
114if err != nil {
115admissionResponse.Allowed = false
116admissionResponse.Result = &metav1.Status{
117Message: fmt.Sprintf("validation webhook error: %v", err),
118}
119}
120}
121
122ar.Response = admissionResponse
123resp, err := json.Marshal(ar)
124if err != nil {
125log.Errorf("api=validation, reason=json.Marshal, message=could not encode response, err=%s", err.Error())
126http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError)
127}
128
129log.Infof("api=validation, message=ready to write response, result=%t", ar.Response.Allowed)
130if _, err := w.Write(resp); err != nil {
131log.Errorf("api=validation, reason=w.Write, message=could not write response, err=%s", err.Error())
132http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
133}
134}
135
136func (whsvr *Server) ImmutableHandler(w http.ResponseWriter, r *http.Request) {
137log := logger.FromContext(r.Context())
138var body []byte
139
140if r.Body != nil {
141if data, err := io.ReadAll(r.Body); err == nil {
142body = data
143}
144}
145
146prettyS := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(string(body), "\"", "'"), " ", ""), "\n", " ")
147log.Infof("api=ImmutableHandler, message=incoming request, body=%s", prettyS)
148
149ar := v1beta1.AdmissionReview{}
150_, _, _ = deserializer.Decode(body, nil, &ar)
151
152admissionResponse := &v1beta1.AdmissionResponse{
153Allowed: false,
154Result: &metav1.Status{
155Message: "Immutable resource",
156},
157}
158
159admissionResponse.UID = ar.Request.UID
160resp, _ := json.Marshal(ar)
161
162w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
163if _, err := w.Write(resp); err != nil {
164log.Errorf("api=ImmutableHandler, reason=w.Write, message=could not write response, err=%s", err.Error())
165http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
166}
167}
168