mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-10-23 07:19:30 +08:00
139 lines
4.1 KiB
Go
139 lines
4.1 KiB
Go
package webhook
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
v1 "k8s.io/api/admission/v1"
|
|
"k8s.io/api/admission/v1beta1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/klog/v2"
|
|
)
|
|
|
|
// admitv1beta1Func handles a v1beta1 admission
|
|
type admitv1beta1Func func(v1beta1.AdmissionReview) *v1beta1.AdmissionResponse
|
|
|
|
// admitv1beta1Func handles a v1 admission
|
|
type admitv1Func func(v1.AdmissionReview) *v1.AdmissionResponse
|
|
|
|
// admitHandler is a handler, for both validators and mutators, that supports multiple admission review versions
|
|
type admitHandler struct {
|
|
v1beta1 admitv1beta1Func
|
|
v1 admitv1Func
|
|
}
|
|
|
|
func newDelegateToV1AdmitHandler(f admitv1Func) admitHandler {
|
|
return admitHandler{
|
|
v1beta1: delegateV1beta1AdmitToV1(f),
|
|
v1: f,
|
|
}
|
|
}
|
|
|
|
func delegateV1beta1AdmitToV1(f admitv1Func) admitv1beta1Func {
|
|
return func(review v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
|
|
in := v1.AdmissionReview{Request: convertAdmissionRequestToV1(review.Request)}
|
|
out := f(in)
|
|
return convertAdmissionResponseToV1beta1(out)
|
|
}
|
|
}
|
|
|
|
// serve handles the http portion of a request prior to handing to an admit
|
|
// function
|
|
func serve(w http.ResponseWriter, r *http.Request, admit admitHandler) {
|
|
var body []byte
|
|
if r.Body != nil {
|
|
if data, err := ioutil.ReadAll(r.Body); err == nil {
|
|
body = data
|
|
}
|
|
}
|
|
|
|
// verify the content type is accurate
|
|
contentType := r.Header.Get("Content-Type")
|
|
if contentType != "application/json" {
|
|
klog.Errorf("contentType=%s, expect application/json", contentType)
|
|
return
|
|
}
|
|
|
|
klog.V(2).Info(fmt.Sprintf("handling request: %s", body))
|
|
|
|
deserializer := codecs.UniversalDeserializer()
|
|
obj, gvk, err := deserializer.Decode(body, nil, nil)
|
|
if err != nil {
|
|
msg := fmt.Sprintf("Request could not be decoded: %v", err)
|
|
klog.Error(msg)
|
|
http.Error(w, msg, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var responseObj runtime.Object
|
|
switch *gvk {
|
|
case v1beta1.SchemeGroupVersion.WithKind("AdmissionReview"):
|
|
requestedAdmissionReview, ok := obj.(*v1beta1.AdmissionReview)
|
|
if !ok {
|
|
klog.Errorf("Expected v1beta1.AdmissionReview but got: %T", obj)
|
|
return
|
|
}
|
|
responseAdmissionReview := &v1beta1.AdmissionReview{}
|
|
responseAdmissionReview.SetGroupVersionKind(*gvk)
|
|
responseAdmissionReview.Response = admit.v1beta1(*requestedAdmissionReview)
|
|
responseAdmissionReview.Response.UID = requestedAdmissionReview.Request.UID
|
|
responseObj = responseAdmissionReview
|
|
case v1.SchemeGroupVersion.WithKind("AdmissionReview"):
|
|
requestedAdmissionReview, ok := obj.(*v1.AdmissionReview)
|
|
if !ok {
|
|
klog.Errorf("Expected v1.AdmissionReview but got: %T", obj)
|
|
return
|
|
}
|
|
responseAdmissionReview := &v1.AdmissionReview{}
|
|
responseAdmissionReview.SetGroupVersionKind(*gvk)
|
|
responseAdmissionReview.Response = admit.v1(*requestedAdmissionReview)
|
|
responseAdmissionReview.Response.UID = requestedAdmissionReview.Request.UID
|
|
responseObj = responseAdmissionReview
|
|
default:
|
|
msg := fmt.Sprintf("Unsupported group version kind: %v", gvk)
|
|
klog.Error(msg)
|
|
http.Error(w, msg, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
klog.V(2).Info(fmt.Sprintf("sending response: %v", responseObj))
|
|
respBytes, err := json.Marshal(responseObj)
|
|
if err != nil {
|
|
klog.Error(err)
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write(respBytes); err != nil {
|
|
klog.Error(err)
|
|
}
|
|
}
|
|
|
|
func servePods(w http.ResponseWriter, r *http.Request) {
|
|
serve(w, r, newDelegateToV1AdmitHandler(admitPods))
|
|
}
|
|
|
|
func Main(cmd *cobra.Command, args []string) {
|
|
http.HandleFunc("/pods", servePods)
|
|
http.HandleFunc("/readyz", func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("ok")) })
|
|
cert, _ := base64.StdEncoding.DecodeString(os.Getenv("CERT"))
|
|
key, _ := base64.StdEncoding.DecodeString(os.Getenv("KEY"))
|
|
pair, _ := tls.X509KeyPair(cert, key)
|
|
t := &tls.Config{Certificates: []tls.Certificate{pair}}
|
|
server := &http.Server{
|
|
Addr: fmt.Sprintf(":%d", 80),
|
|
TLSConfig: t,
|
|
}
|
|
err := server.ListenAndServeTLS("", "")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|