feat: detect namespace kubevpn installed by helm (#498)

This commit is contained in:
naison
2025-03-30 11:54:40 +08:00
committed by GitHub
parent d191c927f4
commit 116a1f1983
15 changed files with 77 additions and 48 deletions

View File

@@ -4,3 +4,5 @@ description: A Helm chart for KubeVPN
type: application
version: 0.1.0
appVersion: "1.16.0"
annotations:
app: kubevpn

View File

@@ -106,6 +106,11 @@ spec:
envFrom:
- secretRef:
name: {{ include "kubevpn.fullname" . }}
env:
- name: "POD_NAMESPACE"
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
name: webhook

View File

@@ -16,9 +16,7 @@ webhooks:
failurePolicy: Ignore
matchPolicy: Equivalent
name: {{ include "kubevpn.fullname" . }}.naison.io
namespaceSelector:
matchLabels:
ns: {{ .Release.Namespace }}
namespaceSelector: { }
objectSelector: { }
reinvocationPolicy: Never
rules:

View File

@@ -81,6 +81,10 @@ func CmdConnect(f cmdutil.Factory) *cobra.Command {
if err != nil {
return err
}
helmNs, _ := util.GetHelmInstalledNamespace(cmd.Context(), f)
if helmNs != "" {
ns = helmNs
}
if !sshConf.IsEmpty() {
if ip := util.GetAPIServerFromKubeConfigBytes(bytes); ip != nil {
extraRoute.ExtraCIDR = append(extraRoute.ExtraCIDR, ip.String())

View File

@@ -14,9 +14,6 @@ const (
// configmap name
ConfigMapPodTrafficManager = "kubevpn-traffic-manager"
// const namespace
KubevpnNamespace = "kubevpn-system"
// config map keys
KeyDHCP = "DHCP"
KeyDHCP6 = "DHCP6"

View File

@@ -71,6 +71,11 @@ func (svr *Server) Proxy(req *rpc.ProxyRequest, resp rpc.Daemon_ProxyServer) (e
if daemonClient == nil {
return fmt.Errorf("daemon is not avaliable")
}
helmNs, _ := util.GetHelmInstalledNamespace(ctx, connect.GetFactory())
if helmNs != "" {
connect.Namespace = helmNs
}
if svr.connect != nil {
isSameCluster, _ := util.IsSameCluster(
ctx,
@@ -107,7 +112,7 @@ func (svr *Server) Proxy(req *rpc.ProxyRequest, resp rpc.Daemon_ProxyServer) (e
if svr.connect == nil {
plog.G(ctx).Debugf("Connectting to cluster")
var connResp rpc.Daemon_ConnectClient
connResp, err = daemonClient.Connect(ctx, convert(req))
connResp, err = daemonClient.Connect(ctx, convert(req, helmNs))
if err != nil {
return err
}
@@ -140,10 +145,10 @@ func newProxyWarp(server rpc.Daemon_ProxyServer) io.Writer {
return &proxyWarp{server: server}
}
func convert(req *rpc.ProxyRequest) *rpc.ConnectRequest {
func convert(req *rpc.ProxyRequest, ns string) *rpc.ConnectRequest {
return &rpc.ConnectRequest{
KubeconfigBytes: req.KubeconfigBytes,
Namespace: req.Namespace,
Namespace: util.If(ns != "", ns, req.Namespace),
Engine: req.Engine,
ExtraRoute: req.ExtraRoute,
SshJump: req.SshJump,

View File

@@ -156,7 +156,7 @@ func (c *ConnectOptions) CreateRemoteInboundPod(ctx context.Context, namespace s
}
for _, workload := range workloads {
plog.G(ctx).Infof("Injecting inbound sidecar for %s", workload)
plog.G(ctx).Infof("Injecting inbound sidecar for %s in namespace %s", workload, namespace)
configInfo := util.PodRouteConfig{
LocalTunIPv4: c.localTunIPv4.IP.String(),
LocalTunIPv6: c.localTunIPv6.IP.String(),
@@ -182,7 +182,7 @@ func (c *ConnectOptions) CreateRemoteInboundPod(ctx context.Context, namespace s
err = inject.InjectVPNSidecar(ctx, c.factory, c.Namespace, object, configInfo)
}
if err != nil {
plog.G(ctx).Errorf("Injecting inbound sidecar for %s failed: %s", workload, err.Error())
plog.G(ctx).Errorf("Injecting inbound sidecar for %s in namespace %s failed: %s", workload, namespace, err.Error())
return err
}
c.proxyWorkloads.Add(c.Namespace, &Proxy{
@@ -286,7 +286,7 @@ func (c *ConnectOptions) portForward(ctx context.Context, portPair []string) err
defer firstCancelFunc()
var errChan = make(chan error, 1)
go func() {
runtime.ErrorHandlers = []func(error){}
runtime.ErrorHandlers = runtime.ErrorHandlers[0:0]
var first = pointer.Bool(true)
for ctx.Err() == nil {
func() {

View File

@@ -476,7 +476,14 @@ kubevpn serve -L "tcp://:10800" -L "tun://:8422?net=${TunIPv4}" -L "gtcp://:1080
},
},
}},
Env: []v1.EnvVar{},
Env: []v1.EnvVar{{
Name: config.EnvPodNamespace,
ValueFrom: &v1.EnvVarSource{
FieldRef: &v1.ObjectFieldSelector{
FieldPath: "metadata.namespace",
},
},
}},
ImagePullPolicy: v1.PullIfNotPresent,
Resources: resourcesSmall,
},

View File

@@ -60,13 +60,6 @@ iptables -t nat -A POSTROUTING ! -p icmp ! -s 127.0.0.1 ! -d ${CIDR4} -j MASQUER
ip6tables -t nat -A POSTROUTING ! -p icmp ! -s 0:0:0:0:0:0:0:1 ! -d ${CIDR6} -j MASQUERADE
kubevpn serve -L "tun:/localhost:8422?net=${TunIPv4}&route=${CIDR4}" -F "tcp://${TrafficManagerService}:10800"`,
},
EnvFrom: []v1.EnvFromSource{{
SecretRef: &v1.SecretEnvSource{
LocalObjectReference: v1.LocalObjectReference{
Name: config.ConfigMapPodTrafficManager,
},
},
}},
Env: []v1.EnvVar{
{
Name: "CIDR4",

View File

@@ -24,13 +24,6 @@ func AddContainer(spec *corev1.PodSpec, c util.PodRouteConfig) {
spec.Containers = append(spec.Containers, corev1.Container{
Name: config.ContainerSidecarVPN,
Image: config.Image,
EnvFrom: []corev1.EnvFromSource{{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: config.ConfigMapPodTrafficManager,
},
},
}},
Env: []corev1.EnvVar{
{
Name: "LocalTunIPv4",

37
pkg/util/helm.go Normal file
View File

@@ -0,0 +1,37 @@
package util
import (
"context"
"os"
"github.com/pkg/errors"
"helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v4/pkg/release/v1"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
)
// GetHelmInstalledNamespace
// 1. use helm to install kubevpn server, means cluster mode,
// all kubevpn client should connect to this namespace.
// 2. if any error occurs, just ignore and will use options `-n` or `--namespace`
func GetHelmInstalledNamespace(ctx context.Context, f cmdutil.Factory) (string, error) {
cfg := new(action.Configuration)
client := action.NewList(cfg)
var nothing = func(format string, v ...interface{}) {}
err := cfg.Init(f, "", os.Getenv("HELM_DRIVER"), nothing)
if err != nil {
return "", err
}
client.SetStateMask()
releases, err := client.Run()
if err != nil {
return "", err
}
for _, app := range releases {
if app.Name == "kubevpn" &&
app.Info != nil && app.Info.Status == v1.StatusDeployed {
return app.Namespace, nil
}
}
return "", errors.New("app kubevpn not found")
}

View File

@@ -39,11 +39,6 @@ func GetClusterIDByCM(cm *v1.ConfigMap) types.UID {
}
func IsSameCluster(ctx context.Context, client v12.CoreV1Interface, namespace string, clientB v12.CoreV1Interface, namespaceB string) (bool, error) {
if UseDefaultNs(ctx, client) {
namespace = config.KubevpnNamespace
namespaceB = config.KubevpnNamespace
}
if namespace != namespaceB {
return false, nil
}
@@ -59,11 +54,6 @@ func IsSameCluster(ctx context.Context, client v12.CoreV1Interface, namespace st
return clusterIDA == clusterIDB, nil
}
func UseDefaultNs(ctx context.Context, client v12.CoreV1Interface) bool {
_, err := client.Services(config.KubevpnNamespace).Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{})
return err == nil
}
func ConvertToKubeConfigBytes(factory cmdutil.Factory) ([]byte, string, error) {
loader := factory.ToRawKubeConfigLoader()
namespace, _, err := loader.Namespace()

View File

@@ -4,7 +4,6 @@ import (
"context"
"crypto/tls"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net/http"
"os"
@@ -29,12 +28,8 @@ func Main(f util.Factory) error {
if err != nil {
return err
}
var ns string
_, err = clientset.CoreV1().Services(config.KubevpnNamespace).Get(context.Background(), config.ConfigMapPodTrafficManager, metav1.GetOptions{})
if err == nil {
ns = config.KubevpnNamespace
}
ns := os.Getenv(config.EnvPodNamespace)
h := &admissionReviewHandler{f: f, clientset: clientset, ns: ns}
http.HandleFunc("/pods", func(w http.ResponseWriter, r *http.Request) {
serve(w, r, newDelegateToV1AdmitHandler(h.admitPods))

View File

@@ -71,12 +71,10 @@ func serve(w http.ResponseWriter, r *http.Request, admit admitHandler) {
return
}
plog.G(context.Background()).Infof("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)
msg := fmt.Sprintf("Request: %s could not be decoded: %v", string(body), err)
plog.G(context.Background()).Error(msg)
http.Error(w, msg, http.StatusBadRequest)
return

View File

@@ -23,8 +23,13 @@ import (
// create pod will rent ip and delete pod will release ip
func (h *admissionReviewHandler) admitPods(ar v1.AdmissionReview) *v1.AdmissionResponse {
r, _ := json.Marshal(ar)
plog.G(context.Background()).Infof("Admitting pods called, req: %v", string(r))
var name, ns string
accessor, _ := meta.Accessor(ar.Request.Object.Object)
if accessor != nil {
name = accessor.GetName()
ns = accessor.GetNamespace()
}
plog.G(context.Background()).Infof("Admitting %s pods called, name: %s, namespace: %s", ar.Request.Operation, name, ns)
podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
if ar.Request.Resource != podResource {
err := fmt.Errorf("expect resource to be %s but real %s", podResource, ar.Request.Resource)