mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-12-24 11:51:13 +08:00
feat: webhook not use klog
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
FROM naison/kubevpn:test
|
FROM naison/kubevpn:v1.1.19
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||||
|
|
||||||
|
"github.com/wencaiwulue/kubevpn/pkg/util"
|
||||||
"github.com/wencaiwulue/kubevpn/pkg/webhook"
|
"github.com/wencaiwulue/kubevpn/pkg/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,6 +16,9 @@ func CmdWebhook(f cmdutil.Factory) *cobra.Command {
|
|||||||
After deploying it to Kubernetes cluster, the Administrator needs to create a MutatingWebhookConfiguration
|
After deploying it to Kubernetes cluster, the Administrator needs to create a MutatingWebhookConfiguration
|
||||||
in the Kubernetes cluster to register remote webhook admission controllers.`,
|
in the Kubernetes cluster to register remote webhook admission controllers.`,
|
||||||
Args: cobra.MaximumNArgs(0),
|
Args: cobra.MaximumNArgs(0),
|
||||||
|
PreRun: func(cmd *cobra.Command, args []string) {
|
||||||
|
util.InitLogger(true)
|
||||||
|
},
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return webhook.Main(f)
|
return webhook.Main(f)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -76,8 +76,12 @@ func InjectVPNAndEnvoySidecar(ctx1 context.Context, factory cmdutil.Factory, cli
|
|||||||
}
|
}
|
||||||
// (1) add mesh container
|
// (1) add mesh container
|
||||||
removePatch, restorePatch := patch(*origin, path)
|
removePatch, restorePatch := patch(*origin, path)
|
||||||
b, _ := json.Marshal(restorePatch)
|
var b []byte
|
||||||
mesh.AddMeshContainer(templateSpec, namespace, nodeID, c)
|
b, err = json.Marshal(restorePatch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mesh.AddMeshContainer(templateSpec, nodeID, c)
|
||||||
helper := pkgresource.NewHelper(object.Client, object.Mapping)
|
helper := pkgresource.NewHelper(object.Client, object.Mapping)
|
||||||
ps := []P{
|
ps := []P{
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func RemoveContainers(spec *v1.PodTemplateSpec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddMeshContainer(spec *v1.PodTemplateSpec, ns, nodeId string, c util.PodRouteConfig) {
|
func AddMeshContainer(spec *v1.PodTemplateSpec, nodeId string, c util.PodRouteConfig) {
|
||||||
// remove envoy proxy containers if already exist
|
// remove envoy proxy containers if already exist
|
||||||
RemoveContainers(spec)
|
RemoveContainers(spec)
|
||||||
spec.Spec.ServiceAccountName = config.ConfigMapPodTrafficManager
|
spec.Spec.ServiceAccountName = config.ConfigMapPodTrafficManager
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
v1 "k8s.io/api/admission/v1"
|
v1 "k8s.io/api/admission/v1"
|
||||||
"k8s.io/api/admission/v1beta1"
|
"k8s.io/api/admission/v1beta1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/klog/v2"
|
|
||||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ func delegateV1beta1AdmitToV1(f admitv1Func) admitv1beta1Func {
|
|||||||
func serve(w http.ResponseWriter, r *http.Request, admit admitHandler) {
|
func serve(w http.ResponseWriter, r *http.Request, admit admitHandler) {
|
||||||
var body []byte
|
var body []byte
|
||||||
if r.Body != nil {
|
if r.Body != nil {
|
||||||
if data, err := ioutil.ReadAll(r.Body); err == nil {
|
if data, err := io.ReadAll(r.Body); err == nil {
|
||||||
body = data
|
body = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,17 +61,17 @@ func serve(w http.ResponseWriter, r *http.Request, admit admitHandler) {
|
|||||||
// verify the content type is accurate
|
// verify the content type is accurate
|
||||||
contentType := r.Header.Get("Content-Type")
|
contentType := r.Header.Get("Content-Type")
|
||||||
if contentType != "application/json" {
|
if contentType != "application/json" {
|
||||||
klog.Errorf("contentType=%s, expect application/json", contentType)
|
log.Errorf("contentType=%s, expect application/json", contentType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
klog.V(2).Info(fmt.Sprintf("handling request: %s", body))
|
log.Infof("handling request: %s", body)
|
||||||
|
|
||||||
deserializer := codecs.UniversalDeserializer()
|
deserializer := codecs.UniversalDeserializer()
|
||||||
obj, gvk, err := deserializer.Decode(body, nil, nil)
|
obj, gvk, err := deserializer.Decode(body, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("Request could not be decoded: %v", err)
|
msg := fmt.Sprintf("Request could not be decoded: %v", err)
|
||||||
klog.Error(msg)
|
log.Error(msg)
|
||||||
http.Error(w, msg, http.StatusBadRequest)
|
http.Error(w, msg, http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ func serve(w http.ResponseWriter, r *http.Request, admit admitHandler) {
|
|||||||
case v1beta1.SchemeGroupVersion.WithKind("AdmissionReview"):
|
case v1beta1.SchemeGroupVersion.WithKind("AdmissionReview"):
|
||||||
requestedAdmissionReview, ok := obj.(*v1beta1.AdmissionReview)
|
requestedAdmissionReview, ok := obj.(*v1beta1.AdmissionReview)
|
||||||
if !ok {
|
if !ok {
|
||||||
klog.Errorf("Expected v1beta1.AdmissionReview but got: %T", obj)
|
log.Errorf("Expected v1beta1.AdmissionReview but got: %T", obj)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
responseAdmissionReview := &v1beta1.AdmissionReview{}
|
responseAdmissionReview := &v1beta1.AdmissionReview{}
|
||||||
@@ -92,7 +92,7 @@ func serve(w http.ResponseWriter, r *http.Request, admit admitHandler) {
|
|||||||
case v1.SchemeGroupVersion.WithKind("AdmissionReview"):
|
case v1.SchemeGroupVersion.WithKind("AdmissionReview"):
|
||||||
requestedAdmissionReview, ok := obj.(*v1.AdmissionReview)
|
requestedAdmissionReview, ok := obj.(*v1.AdmissionReview)
|
||||||
if !ok {
|
if !ok {
|
||||||
klog.Errorf("Expected v1.AdmissionReview but got: %T", obj)
|
log.Errorf("Expected v1.AdmissionReview but got: %T", obj)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
responseAdmissionReview := &v1.AdmissionReview{}
|
responseAdmissionReview := &v1.AdmissionReview{}
|
||||||
@@ -102,21 +102,21 @@ func serve(w http.ResponseWriter, r *http.Request, admit admitHandler) {
|
|||||||
responseObj = responseAdmissionReview
|
responseObj = responseAdmissionReview
|
||||||
default:
|
default:
|
||||||
msg := fmt.Sprintf("Unsupported group version kind: %v", gvk)
|
msg := fmt.Sprintf("Unsupported group version kind: %v", gvk)
|
||||||
klog.Error(msg)
|
log.Error(msg)
|
||||||
http.Error(w, msg, http.StatusBadRequest)
|
http.Error(w, msg, http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
klog.V(2).Info(fmt.Sprintf("sending response: %v", responseObj))
|
log.Infof("sending response: %v", responseObj)
|
||||||
respBytes, err := json.Marshal(responseObj)
|
respBytes, err := json.Marshal(responseObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
log.Error(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
if _, err := w.Write(respBytes); err != nil {
|
if _, err := w.Write(respBytes); err != nil {
|
||||||
klog.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/mattbaird/jsonpatch"
|
"github.com/mattbaird/jsonpatch"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"k8s.io/api/admission/v1"
|
"k8s.io/api/admission/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/kubectl/pkg/cmd/util/podcmd"
|
"k8s.io/kubectl/pkg/cmd/util/podcmd"
|
||||||
|
|
||||||
"github.com/wencaiwulue/kubevpn/pkg/config"
|
"github.com/wencaiwulue/kubevpn/pkg/config"
|
||||||
@@ -18,26 +20,30 @@ import (
|
|||||||
|
|
||||||
// only allow pods to pull images from specific registry.
|
// only allow pods to pull images from specific registry.
|
||||||
func (h *admissionReviewHandler) admitPods(ar v1.AdmissionReview) *v1.AdmissionResponse {
|
func (h *admissionReviewHandler) admitPods(ar v1.AdmissionReview) *v1.AdmissionResponse {
|
||||||
klog.V(2).Info("admitting pods")
|
r, _ := json.Marshal(ar)
|
||||||
|
log.Infof("admitting pods called, req: %v", string(r))
|
||||||
podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
||||||
if ar.Request.Resource != podResource {
|
if ar.Request.Resource != podResource {
|
||||||
err := fmt.Errorf("expect resource to be %s", podResource)
|
err := fmt.Errorf("expect resource to be %s but real %s", podResource, ar.Request.Resource)
|
||||||
klog.Error(err)
|
log.Error(err)
|
||||||
return toV1AdmissionResponse(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
raw := ar.Request.Object.Raw
|
|
||||||
pod := corev1.Pod{}
|
|
||||||
|
|
||||||
deserializer := codecs.UniversalDeserializer()
|
|
||||||
if _, _, err := deserializer.Decode(raw, nil, &pod); err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return toV1AdmissionResponse(err)
|
return toV1AdmissionResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ar.Request.Operation {
|
switch ar.Request.Operation {
|
||||||
case v1.Create:
|
case v1.Create:
|
||||||
from, _ := json.Marshal(pod)
|
raw := ar.Request.Object.Raw
|
||||||
|
pod := corev1.Pod{}
|
||||||
|
deserializer := codecs.UniversalDeserializer()
|
||||||
|
if _, _, err := deserializer.Decode(raw, nil, &pod); err != nil {
|
||||||
|
log.Errorf("can not decode into pod, err: %v, raw: %s", err, string(raw))
|
||||||
|
return toV1AdmissionResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
from, err := json.Marshal(pod)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("can not marshal into pod, err: %v", err)
|
||||||
|
return toV1AdmissionResponse(err)
|
||||||
|
}
|
||||||
var found bool
|
var found bool
|
||||||
for i := 0; i < len(pod.Spec.Containers); i++ {
|
for i := 0; i < len(pod.Spec.Containers); i++ {
|
||||||
if pod.Spec.Containers[i].Name == config.ContainerSidecarVPN {
|
if pod.Spec.Containers[i].Name == config.ContainerSidecarVPN {
|
||||||
@@ -45,27 +51,50 @@ func (h *admissionReviewHandler) admitPods(ar v1.AdmissionReview) *v1.AdmissionR
|
|||||||
pair := pod.Spec.Containers[i].Env[j]
|
pair := pod.Spec.Containers[i].Env[j]
|
||||||
if pair.Name == config.EnvInboundPodTunIP && pair.Value == "" {
|
if pair.Name == config.EnvInboundPodTunIP && pair.Value == "" {
|
||||||
found = true
|
found = true
|
||||||
clientset, err := h.f.KubernetesClientSet()
|
var clientset *kubernetes.Clientset
|
||||||
|
clientset, err = h.f.KubernetesClientSet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
log.Errorf("can not get clientset, err: %v", err)
|
||||||
return toV1AdmissionResponse(err)
|
return toV1AdmissionResponse(err)
|
||||||
}
|
}
|
||||||
cmi := clientset.CoreV1().ConfigMaps(ar.Request.Namespace)
|
cmi := clientset.CoreV1().ConfigMaps(ar.Request.Namespace)
|
||||||
dhcp := handler.NewDHCPManager(cmi, ar.Request.Namespace, &net.IPNet{IP: config.RouterIP, Mask: config.CIDR.Mask})
|
dhcp := handler.NewDHCPManager(cmi, ar.Request.Namespace, &net.IPNet{IP: config.RouterIP, Mask: config.CIDR.Mask})
|
||||||
random, err := dhcp.RentIPRandom()
|
var random *net.IPNet
|
||||||
|
random, err = dhcp.RentIPRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
log.Errorf("rent ip random failed, err: %v", err)
|
||||||
return toV1AdmissionResponse(err)
|
return toV1AdmissionResponse(err)
|
||||||
}
|
}
|
||||||
|
var name string
|
||||||
|
if accessor, errT := meta.Accessor(ar.Request.Object); errT == nil {
|
||||||
|
name = accessor.GetName()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("rent ip %s for pod %s in namespace: %s", random.String(), name, ar.Request.Namespace)
|
||||||
pod.Spec.Containers[i].Env[j].Value = random.String()
|
pod.Spec.Containers[i].Env[j].Value = random.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found {
|
if found {
|
||||||
to, _ := json.Marshal(pod)
|
var to []byte
|
||||||
patch, _ := jsonpatch.CreatePatch(from, to)
|
to, err = json.Marshal(pod)
|
||||||
marshal, _ := json.Marshal(patch)
|
if err != nil {
|
||||||
|
log.Errorf("can not marshal pod, err: %v", err)
|
||||||
|
return toV1AdmissionResponse(err)
|
||||||
|
}
|
||||||
|
var patch []jsonpatch.JsonPatchOperation
|
||||||
|
patch, err = jsonpatch.CreatePatch(from, to)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("can not create patch json, err: %v", err)
|
||||||
|
return toV1AdmissionResponse(err)
|
||||||
|
}
|
||||||
|
var marshal []byte
|
||||||
|
marshal, err = json.Marshal(patch)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("can not marshal json patch %v, err: %v", patch, err)
|
||||||
|
return toV1AdmissionResponse(err)
|
||||||
|
}
|
||||||
return applyPodPatch(
|
return applyPodPatch(
|
||||||
ar,
|
ar,
|
||||||
func(pod *corev1.Pod) bool {
|
func(pod *corev1.Pod) bool {
|
||||||
@@ -76,18 +105,28 @@ func (h *admissionReviewHandler) admitPods(ar v1.AdmissionReview) *v1.AdmissionR
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return &v1.AdmissionResponse{
|
return &v1.AdmissionResponse{
|
||||||
|
UID: ar.Request.UID,
|
||||||
Allowed: true,
|
Allowed: true,
|
||||||
}
|
}
|
||||||
case v1.Delete:
|
case v1.Delete:
|
||||||
|
raw := ar.Request.OldObject.Raw
|
||||||
|
pod := corev1.Pod{}
|
||||||
|
deserializer := codecs.UniversalDeserializer()
|
||||||
|
if _, _, err := deserializer.Decode(raw, nil, &pod); err != nil {
|
||||||
|
log.Errorf("can not decode into pod, err: %v, raw: %s", err, string(raw))
|
||||||
|
return toV1AdmissionResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
name, _ := podcmd.FindContainerByName(&pod, config.ContainerSidecarVPN)
|
name, _ := podcmd.FindContainerByName(&pod, config.ContainerSidecarVPN)
|
||||||
if name != nil {
|
if name != nil {
|
||||||
for _, envVar := range name.Env {
|
for _, envVar := range name.Env {
|
||||||
if envVar.Name == config.EnvInboundPodTunIP && envVar.Value != "" {
|
if envVar.Name == config.EnvInboundPodTunIP && envVar.Value != "" {
|
||||||
ip, cidr, err := net.ParseCIDR(envVar.Value)
|
ip, cidr, err := net.ParseCIDR(envVar.Value)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
clientset, err := h.f.KubernetesClientSet()
|
var clientset *kubernetes.Clientset
|
||||||
|
clientset, err = h.f.KubernetesClientSet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
log.Errorf("can not get clientset, err: %v", err)
|
||||||
return toV1AdmissionResponse(err)
|
return toV1AdmissionResponse(err)
|
||||||
}
|
}
|
||||||
cmi := clientset.CoreV1().ConfigMaps(ar.Request.Namespace)
|
cmi := clientset.CoreV1().ConfigMaps(ar.Request.Namespace)
|
||||||
@@ -97,7 +136,9 @@ func (h *admissionReviewHandler) admitPods(ar v1.AdmissionReview) *v1.AdmissionR
|
|||||||
}
|
}
|
||||||
err = handler.NewDHCPManager(cmi, ar.Request.Namespace, &net.IPNet{IP: config.RouterIP, Mask: config.CIDR.Mask}).ReleaseIpToDHCP(ipnet)
|
err = handler.NewDHCPManager(cmi, ar.Request.Namespace, &net.IPNet{IP: config.RouterIP, Mask: config.CIDR.Mask}).ReleaseIpToDHCP(ipnet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(1).Infof("release ip to dhcp err: %v", err)
|
log.Errorf("release ip to dhcp err: %v, ip: %s", err, envVar.Value)
|
||||||
|
} else {
|
||||||
|
log.Errorf("release ip to dhcp ok, ip: %s", envVar.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,16 +150,17 @@ func (h *admissionReviewHandler) admitPods(ar v1.AdmissionReview) *v1.AdmissionR
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err := fmt.Errorf("expect operation is %s or %s, not %s", v1.Create, v1.Delete, ar.Request.Operation)
|
err := fmt.Errorf("expect operation is %s or %s, not %s", v1.Create, v1.Delete, ar.Request.Operation)
|
||||||
klog.Error(err)
|
log.Error(err)
|
||||||
return toV1AdmissionResponse(err)
|
return toV1AdmissionResponse(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyPodPatch(ar v1.AdmissionReview, shouldPatchPod func(*corev1.Pod) bool, patch string) *v1.AdmissionResponse {
|
func applyPodPatch(ar v1.AdmissionReview, shouldPatchPod func(*corev1.Pod) bool, patch string) *v1.AdmissionResponse {
|
||||||
klog.V(2).Info("mutating pods")
|
r, _ := json.Marshal(ar)
|
||||||
|
log.Infof("mutating pods called, req: %s", string(r))
|
||||||
podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
||||||
if ar.Request.Resource != podResource {
|
if ar.Request.Resource != podResource {
|
||||||
klog.Errorf("expect resource to be %s", podResource)
|
log.Errorf("expect resource to be %s but real is %s", podResource, ar.Request.Resource)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +168,7 @@ func applyPodPatch(ar v1.AdmissionReview, shouldPatchPod func(*corev1.Pod) bool,
|
|||||||
pod := corev1.Pod{}
|
pod := corev1.Pod{}
|
||||||
deserializer := codecs.UniversalDeserializer()
|
deserializer := codecs.UniversalDeserializer()
|
||||||
if _, _, err := deserializer.Decode(raw, nil, &pod); err != nil {
|
if _, _, err := deserializer.Decode(raw, nil, &pod); err != nil {
|
||||||
klog.Error(err)
|
log.Errorf("can not decode request into pod, err: %v, req: %s", err, string(raw))
|
||||||
return toV1AdmissionResponse(err)
|
return toV1AdmissionResponse(err)
|
||||||
}
|
}
|
||||||
reviewResponse := v1.AdmissionResponse{}
|
reviewResponse := v1.AdmissionResponse{}
|
||||||
|
|||||||
Reference in New Issue
Block a user