mirror of
https://github.com/kairos-io/entangle.git
synced 2025-04-28 03:21:59 +00:00
133 lines
3.9 KiB
Go
133 lines
3.9 KiB
Go
package webhooks
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/client-go/kubernetes"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
"sigs.k8s.io/controller-runtime/pkg/manager"
|
|
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
|
|
|
"github.com/snorwin/k8s-generic-webhook/pkg/webhook"
|
|
)
|
|
|
|
type Webhook struct {
|
|
webhook.MutatingWebhook
|
|
client.Client
|
|
clientSet *kubernetes.Clientset
|
|
Scheme *runtime.Scheme
|
|
|
|
SidecarImage string
|
|
}
|
|
|
|
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
|
|
//+kubebuilder:webhook:verbs=create;update,path=/mutate-entangle-kairos-x-io-v1alpha1-entanglement,mutating=true,failurePolicy=ignore,sideEffects=None,groups=core,resources=pods,versions=v1,name=mentanglement.kb.io,admissionReviewVersions={v1,v1alpha1}
|
|
|
|
var (
|
|
EntanglementNameLabel = "entanglement.kairos.io/name"
|
|
EntanglementServiceLabel = "entanglement.kairos.io/service"
|
|
EntanglementDirectionLabel = "entanglement.kairos.io/direction"
|
|
EntanglementPortLabel = "entanglement.kairos.io/target_port"
|
|
EntanglementHostLabel = "entanglement.kairos.io/host"
|
|
)
|
|
|
|
func (w *Webhook) SetupWebhookWithManager(mgr manager.Manager) error {
|
|
clientset, err := kubernetes.NewForConfig(mgr.GetConfig())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
w.clientSet = clientset
|
|
|
|
return webhook.NewGenericWebhookManagedBy(mgr).
|
|
For(&corev1.Pod{}).
|
|
WithMutatePath("/mutate-entangle-kairos-x-io-v1alpha1-entanglement").
|
|
Complete(w)
|
|
}
|
|
|
|
func (w *Webhook) Mutate(ctx context.Context, request admission.Request, object runtime.Object) admission.Response {
|
|
_ = log.FromContext(ctx)
|
|
|
|
pod := object.(*corev1.Pod)
|
|
entanglementName, exists := pod.Labels[EntanglementNameLabel]
|
|
if !exists {
|
|
return admission.Allowed("")
|
|
}
|
|
|
|
entanglementPort, exists := pod.Labels[EntanglementPortLabel]
|
|
if !exists {
|
|
return admission.Allowed("")
|
|
}
|
|
|
|
cmd := "service-connect"
|
|
entanglementDirection, exists := pod.Labels[EntanglementDirectionLabel]
|
|
if exists && entanglementDirection == "entangle" {
|
|
cmd = "service-add"
|
|
}
|
|
|
|
host := "127.0.0.1"
|
|
entanglementHost, exists := pod.Labels[EntanglementHostLabel]
|
|
if exists && entanglementHost != "" {
|
|
host = entanglementHost
|
|
}
|
|
|
|
entanglementService, exists := pod.Labels[EntanglementServiceLabel]
|
|
if !exists {
|
|
return admission.Allowed("")
|
|
}
|
|
|
|
podCopy := pod.DeepCopy()
|
|
secret, err := w.clientSet.CoreV1().Secrets(request.Namespace).Get(context.Background(), entanglementName, v1.GetOptions{})
|
|
if err != nil || secret == nil {
|
|
return admission.Denied("entanglement secret not found: " + entanglementName + err.Error())
|
|
}
|
|
|
|
privileged := false
|
|
|
|
for _, p := range podCopy.Spec.Containers {
|
|
if p.Name == "entanglement" {
|
|
return admission.Allowed("already entangled")
|
|
}
|
|
}
|
|
|
|
servingContainer := corev1.Container{
|
|
ImagePullPolicy: corev1.PullAlways,
|
|
Command: []string{"/usr/bin/edgevpn"},
|
|
Args: []string{cmd, entanglementService, fmt.Sprintf("%s:%s", host, entanglementPort)},
|
|
Env: []corev1.EnvVar{
|
|
{
|
|
Name: "EDGEVPNTOKEN",
|
|
ValueFrom: &corev1.EnvVarSource{
|
|
SecretKeyRef: &corev1.SecretKeySelector{
|
|
Key: "network_token",
|
|
LocalObjectReference: corev1.LocalObjectReference{
|
|
Name: entanglementName,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
SecurityContext: &corev1.SecurityContext{Privileged: &privileged},
|
|
Name: "entanglement",
|
|
Image: w.SidecarImage,
|
|
}
|
|
podCopy.Spec.Containers = append(podCopy.Spec.Containers, servingContainer)
|
|
|
|
return patchFromPod(request, podCopy)
|
|
}
|
|
|
|
func patchFromPod(req admission.Request, pod *corev1.Pod) admission.Response {
|
|
marshaledPod, err := json.Marshal(pod)
|
|
if err != nil {
|
|
return admission.Errored(http.StatusInternalServerError, err)
|
|
}
|
|
|
|
return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPod)
|
|
}
|