mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-05 07:26:55 +00:00
NK-10: Implemented basic logic for mutation, added logs
This commit is contained in:
parent
5680480600
commit
3661e012a5
2 changed files with 116 additions and 8 deletions
|
@ -14,11 +14,6 @@ case $i in
|
|||
esac
|
||||
done
|
||||
|
||||
if [ -z "${serverIp}" ]; then
|
||||
# This is the standard IP of minikube
|
||||
serverIp="192.168.10.117" #TODO: ! Read it from ~/.kube/config !
|
||||
fi
|
||||
|
||||
hub_user_name="nirmata"
|
||||
project_name="kube-policy"
|
||||
|
||||
|
@ -30,6 +25,11 @@ chmod +x "${certsGenerator}"
|
|||
|
||||
if [ -z "${namespace}" ]; then # controller is launched locally
|
||||
|
||||
if [ -z "${serverIp}" ]; then
|
||||
echo "--serverIp should be explicitly specified if --namespace is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
${certsGenerator} "--serverIp=${serverIp}" || exit 2
|
||||
|
||||
echo "Applying webhook..."
|
||||
|
|
114
server/server.go
114
server/server.go
|
@ -1,13 +1,21 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http/httputil"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
//"net/http/httputil"
|
||||
"crypto/tls"
|
||||
"context"
|
||||
"time"
|
||||
"log"
|
||||
"os"
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
|
||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||
//appsv1 "k8s.io/api/apps/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
// WebhookServer is a struct that describes
|
||||
|
@ -17,9 +25,109 @@ type WebhookServer struct {
|
|||
logger *log.Logger
|
||||
}
|
||||
|
||||
type patchOperation struct {
|
||||
Op string `json:"op"`
|
||||
Path string `json:"path"`
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
|
||||
dump, _ := httputil.DumpRequest(r, true)
|
||||
ws.logger.Printf("%s", dump)
|
||||
if r.URL.Path == "/mutate" {
|
||||
admissionReview := ws.parseAdmissionReview(r, w)
|
||||
if admissionReview == nil {
|
||||
return
|
||||
}
|
||||
|
||||
admissionResponse := ws.mutate(admissionReview)
|
||||
if admissionResponse != nil {
|
||||
admissionReview.Response = admissionResponse
|
||||
if admissionReview.Request != nil {
|
||||
admissionReview.Response.UID = admissionReview.Request.UID
|
||||
}
|
||||
}
|
||||
|
||||
responseJson, err := json.Marshal(admissionReview)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Could not encode response: %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
ws.logger.Printf("Response body: %v", string(responseJson))
|
||||
if _, err := w.Write(responseJson); err != nil {
|
||||
http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
http.Error(w, fmt.Sprintf("Unexpected method path: %v", r.URL.Path), http.StatusNotFound)
|
||||
}
|
||||
|
||||
// Answers to the http.ResponseWriter if request is not valid
|
||||
func (ws *WebhookServer) parseAdmissionReview(request *http.Request, writer http.ResponseWriter) *v1beta1.AdmissionReview {
|
||||
var body []byte
|
||||
if request.Body != nil {
|
||||
if data, err := ioutil.ReadAll(request.Body); err == nil {
|
||||
body = data
|
||||
}
|
||||
}
|
||||
if len(body) == 0 {
|
||||
http.Error(writer, "empty body", http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
contentType := request.Header.Get("Content-Type")
|
||||
if contentType != "application/json" {
|
||||
http.Error(writer, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType)
|
||||
return nil
|
||||
}
|
||||
|
||||
admissionReview := &v1beta1.AdmissionReview{}
|
||||
if err := json.Unmarshal(body, &admissionReview); err != nil {
|
||||
http.Error(writer, "Can't decode body as AdmissionReview", http.StatusExpectationFailed)
|
||||
return nil
|
||||
} else {
|
||||
return admissionReview
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *WebhookServer) mutate(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
|
||||
req := ar.Request
|
||||
|
||||
ws.logger.Printf("AdmissionReview for Kind=%v, Namespace=%v Name=%v (%v) UID=%v patchOperation=%v UserInfo=%v",
|
||||
req.Kind.Kind, req.Namespace, req.Name, req.UID, req.Operation, req.UserInfo)
|
||||
|
||||
if req.Kind.Kind == "ConfigMap" {
|
||||
var configMap core.ConfigMap
|
||||
if err := json.Unmarshal(req.Object.Raw, &configMap); err != nil {
|
||||
ws.logger.Printf("Could not unmarshal raw object: %v", err)
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Result: &metav1.Status{
|
||||
Message: err.Error(),
|
||||
},
|
||||
}
|
||||
}
|
||||
for k, v := range configMap.Data {
|
||||
ws.logger.Printf("CONFIG MAP DATA: %v=%v", k, v)
|
||||
}
|
||||
patch := patchOperation{
|
||||
Path: "labels/isMutated",
|
||||
Op: "Add",
|
||||
Value: "TRUE",
|
||||
}
|
||||
patchBytes, _ := json.Marshal(patch)
|
||||
ws.logger.Printf("AdmissionResponse: patch=%v\n", "TODO")
|
||||
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Patch: patchBytes,
|
||||
PatchType: func() *v1beta1.PatchType {
|
||||
pt := v1beta1.PatchTypeJSONPatch
|
||||
return &pt
|
||||
}(),
|
||||
}
|
||||
} else {
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RunAsync runs TLS server in separate
|
||||
|
|
Loading…
Add table
Reference in a new issue