Files
kubevpn/pkg/handler/uninstall.go
2025-05-18 16:20:13 +08:00

123 lines
4.3 KiB
Go

package handler
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/utils/pointer"
"sigs.k8s.io/yaml"
"github.com/wencaiwulue/kubevpn/v2/pkg/config"
"github.com/wencaiwulue/kubevpn/v2/pkg/controlplane"
"github.com/wencaiwulue/kubevpn/v2/pkg/inject"
plog "github.com/wencaiwulue/kubevpn/v2/pkg/log"
"github.com/wencaiwulue/kubevpn/v2/pkg/util"
)
// Uninstall
// 1) quit daemon
// 2) get all proxy-resources from configmap
// 3) cleanup all containers
// 4) cleanup hosts
func (c *ConnectOptions) Uninstall(ctx context.Context) error {
err := c.LeaveAllProxyResources(ctx)
if err != nil {
plog.G(ctx).Errorf("Leave proxy resources error: %v", err)
} else {
plog.G(ctx).Debugf("Leave proxy resources successfully")
}
plog.G(ctx).Infof("Cleaning up resources")
ns := c.Namespace
name := config.ConfigMapPodTrafficManager
options := metav1.DeleteOptions{GracePeriodSeconds: pointer.Int64(0)}
_ = c.clientset.CoreV1().ConfigMaps(ns).Delete(ctx, name, options)
_ = c.clientset.CoreV1().Pods(ns).Delete(ctx, config.CniNetName, options)
_ = c.clientset.CoreV1().Secrets(ns).Delete(ctx, name, options)
_ = c.clientset.AdmissionregistrationV1().MutatingWebhookConfigurations().Delete(ctx, name+"."+ns, options)
_ = c.clientset.RbacV1().RoleBindings(ns).Delete(ctx, name, options)
_ = c.clientset.CoreV1().ServiceAccounts(ns).Delete(ctx, name, options)
_ = c.clientset.RbacV1().Roles(ns).Delete(ctx, name, options)
_ = c.clientset.CoreV1().Services(ns).Delete(ctx, name, options)
_ = c.clientset.AppsV1().Deployments(ns).Delete(ctx, name, options)
_ = c.clientset.BatchV1().Jobs(ns).Delete(ctx, name, options)
_ = c.CleanupLocalContainer(ctx)
plog.G(ctx).Info("Done")
return nil
}
func (c *ConnectOptions) CleanupLocalContainer(ctx context.Context) error {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return err
}
var networkResource types.NetworkResource
networkResource, err = cli.NetworkInspect(ctx, config.ConfigMapPodTrafficManager, types.NetworkInspectOptions{})
if err != nil {
return err
}
if len(networkResource.Containers) == 0 {
err = cli.NetworkRemove(ctx, config.ConfigMapPodTrafficManager)
}
return err
}
func (c *ConnectOptions) LeaveAllProxyResources(ctx context.Context) (err error) {
if c == nil || c.clientset == nil {
return
}
mapInterface := c.clientset.CoreV1().ConfigMaps(c.Namespace)
var cm *corev1.ConfigMap
cm, err = mapInterface.Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return
}
if cm == nil || cm.Data == nil || len(cm.Data[config.KeyEnvoy]) == 0 {
plog.G(ctx).Infof("No proxy resources found")
return nil
}
var v = make([]*controlplane.Virtual, 0)
str := cm.Data[config.KeyEnvoy]
if err = yaml.Unmarshal([]byte(str), &v); err != nil {
plog.G(ctx).Errorf("Unmarshal envoy config error: %v", err)
return
}
v4, _ := c.GetLocalTunIP()
for _, workload := range c.ProxyResources() {
// deployments.apps.ry-server --> deployments.apps/ry-server
object, err := util.GetUnstructuredObject(c.factory, workload.namespace, workload.workload)
if err != nil {
plog.G(ctx).Errorf("Failed to get unstructured object: %v", err)
return err
}
u := object.Object.(*unstructured.Unstructured)
templateSpec, _, err := util.GetPodTemplateSpecPath(u)
if err != nil {
plog.G(ctx).Errorf("Failed to get template spec path: %v", err)
return err
}
var empty bool
empty, err = inject.UnPatchContainer(ctx, c.factory, c.clientset.CoreV1().ConfigMaps(c.Namespace), object, func(isFargateMode bool, rule *controlplane.Rule) bool {
if isFargateMode {
return c.IsMe(workload.namespace, util.ConvertWorkloadToUid(workload.workload), rule.Headers)
}
return rule.LocalTunIPv4 == v4
})
if err != nil {
plog.G(ctx).Errorf("Failed to leave workload %s in namespace %s: %v", workload.workload, workload.namespace, err)
continue
}
if empty {
err = inject.ModifyServiceTargetPort(ctx, c.clientset, workload.namespace, templateSpec.Labels, map[int32]int32{})
}
c.LeavePortMap(workload.namespace, workload.workload)
}
return err
}