mirror of
				https://github.com/kubenetworks/kubevpn.git
				synced 2025-10-31 18:52:50 +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)
 | |
| 	}
 | |
| }
 | 
