From 4949df56ef051e9f8bd61473a1e52059a2c55892 Mon Sep 17 00:00:00 2001 From: naison <895703375@qq.com> Date: Thu, 12 Jun 2025 12:59:39 +0800 Subject: [PATCH] hotfix: fix dev/clone mode bug (#640) --- cmd/kubevpn/cmds/dev.go | 31 +++++++--------------- cmd/kubevpn/cmds/webhook.go | 2 +- pkg/daemon/action/clone.go | 2 +- pkg/daemon/action/disconnect.go | 8 ++---- pkg/dev/options.go | 16 ++++++------ pkg/dev/runconfig.go | 2 +- pkg/dhcp/dhcp.go | 28 ++++++++++---------- pkg/dhcp/server.go | 6 ++--- pkg/handler/clone.go | 12 +++------ pkg/handler/connect.go | 4 +-- pkg/util/dns.go | 7 ----- pkg/util/ns.go | 20 +++++--------- pkg/util/pod.go | 41 +---------------------------- pkg/util/unstructure.go | 46 ++++++++++++++++++++++++++++++--- 14 files changed, 95 insertions(+), 130 deletions(-) diff --git a/cmd/kubevpn/cmds/dev.go b/cmd/kubevpn/cmds/dev.go index 56b2fa9d..f384de8b 100644 --- a/cmd/kubevpn/cmds/dev.go +++ b/cmd/kubevpn/cmds/dev.go @@ -2,8 +2,6 @@ package cmds import ( "context" - "fmt" - "os" "github.com/docker/cli/cli/command" "github.com/spf13/cobra" @@ -75,18 +73,9 @@ func CmdDev(f cmdutil.Factory) *cobra.Command { kubevpn dev deployment/authors -n default --ssh-addr --ssh-username --gssapi-password --entrypoint /bin/bash `)), ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f), - Args: cobra.MatchAll(cobra.OnlyValidArgs), + Args: cobra.MatchAll(cobra.OnlyValidArgs, cobra.MinimumNArgs(1)), DisableFlagsInUseLine: true, PreRunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - _, _ = fmt.Fprintf(os.Stdout, "You must specify the type of resource to proxy. %s\n\n", cmdutil.SuggestAPIResources("kubevpn")) - fullCmdName := cmd.Parent().CommandPath() - usageString := "Required resource not specified." - if len(fullCmdName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "explain") { - usageString = fmt.Sprintf("%s\nUse \"%s explain \" for a detailed description of that resource (e.g. %[2]s explain pods).", usageString, fullCmdName) - } - return cmdutil.UsageErrorf(cmd, usageString) - } err := cmd.Flags().Parse(args[1:]) if err != nil { return err @@ -121,6 +110,15 @@ func CmdDev(f cmdutil.Factory) *cobra.Command { } } + if err := options.InitClient(f); err != nil { + return err + } + + conf, hostConfig, err := dev.Parse(cmd.Flags(), options.ContainerOptions) + if err != nil { + return err + } + defer func() { for _, function := range options.GetRollbackFuncList() { if function != nil { @@ -131,15 +129,6 @@ func CmdDev(f cmdutil.Factory) *cobra.Command { } }() - if err := options.InitClient(f); err != nil { - return err - } - - conf, hostConfig, err := dev.Parse(cmd.Flags(), options.ContainerOptions) - if err != nil { - return err - } - return options.Main(cmd.Context(), sshConf, conf, hostConfig, imagePullSecretName, managerNamespace) }, } diff --git a/cmd/kubevpn/cmds/webhook.go b/cmd/kubevpn/cmds/webhook.go index 2a99b14b..f52b3c1a 100644 --- a/cmd/kubevpn/cmds/webhook.go +++ b/cmd/kubevpn/cmds/webhook.go @@ -38,7 +38,7 @@ func CmdWebhook(f cmdutil.Factory) *cobra.Command { if err != nil { return err } - manager := dhcp.NewDHCPManager(clientset.CoreV1().ConfigMaps(ns), ns) + manager := dhcp.NewDHCPManager(clientset, ns) return webhook.Main(manager, clientset) }, } diff --git a/pkg/daemon/action/clone.go b/pkg/daemon/action/clone.go index ec692b72..1af84ecb 100644 --- a/pkg/daemon/action/clone.go +++ b/pkg/daemon/action/clone.go @@ -62,7 +62,7 @@ func (svr *Server) Clone(resp rpc.Daemon_CloneServer) (err error) { if err != nil { return err } - err = connResp.SendMsg(&connReq) + err = connResp.Send(connReq) if err != nil { return err } diff --git a/pkg/daemon/action/disconnect.go b/pkg/daemon/action/disconnect.go index 60502831..8955fea0 100644 --- a/pkg/daemon/action/disconnect.go +++ b/pkg/daemon/action/disconnect.go @@ -85,7 +85,7 @@ func (svr *Server) Disconnect(resp rpc.Daemon_DisconnectServer) error { plog.G(ctx).Errorf("Index %d out of range", req.GetID()) } case req.KubeconfigBytes != nil && req.Namespace != nil: - err = disconnectByKubeConfig( + err = disconnectByKubeconfig( resp.Context(), svr, req.GetKubeconfigBytes(), @@ -133,7 +133,7 @@ func (svr *Server) Disconnect(resp rpc.Daemon_DisconnectServer) error { return nil } -func disconnectByKubeConfig(ctx context.Context, svr *Server, kubeconfigBytes string, ns string, jump *rpc.SshJump) error { +func disconnectByKubeconfig(ctx context.Context, svr *Server, kubeconfigBytes string, ns string, jump *rpc.SshJump) error { file, err := util.ConvertToTempKubeconfigFile([]byte(kubeconfigBytes)) if err != nil { return err @@ -156,10 +156,6 @@ func disconnectByKubeConfig(ctx context.Context, svr *Server, kubeconfigBytes st } func disconnect(ctx context.Context, svr *Server, connect *handler.ConnectOptions) { - _, err := svr.GetClient(false) - if err != nil { - return - } if svr.connect != nil { isSameCluster, _ := util.IsSameCluster( ctx, diff --git a/pkg/dev/options.go b/pkg/dev/options.go index 6a11ce4f..5de18d3e 100644 --- a/pkg/dev/options.go +++ b/pkg/dev/options.go @@ -134,7 +134,7 @@ func (option *Options) Connect(ctx context.Context, sshConfig *pkgssh.SshConfig, if err != nil { return err } - _ = util.PrintGRPCStream[rpc.DisconnectResponse](ctx, resp) + _ = util.PrintGRPCStream[rpc.DisconnectResponse](nil, resp) return nil }) var resp rpc.Daemon_ProxyClient @@ -185,7 +185,7 @@ func (option *Options) Connect(ctx context.Context, sshConfig *pkgssh.SshConfig, } func (option *Options) Dev(ctx context.Context, config *Config, hostConfig *HostConfig) error { - templateSpec, err := option.GetPodTemplateSpec() + templateSpec, err := option.GetPodTemplateSpec(ctx) if err != nil { plog.G(ctx).Errorf("Failed to get unstructured object error: %v", err) return err @@ -237,7 +237,7 @@ func (option *Options) Dev(ctx context.Context, config *Config, hostConfig *Host } func (option *Options) CreateConnectContainer(ctx context.Context, portBindings nat.PortMap, managerNamespace string) (*string, error) { - portMap, portSet, err := option.GetExposePort(portBindings) + portMap, portSet, err := option.GetExposePort(ctx, portBindings) if err != nil { return nil, err } @@ -342,8 +342,8 @@ func (option *Options) GetRollbackFuncList() []func() error { return option.rollbackFuncList } -func (option *Options) GetExposePort(portBinds nat.PortMap) (nat.PortMap, nat.PortSet, error) { - templateSpec, err := option.GetPodTemplateSpec() +func (option *Options) GetExposePort(ctx context.Context, portBinds nat.PortMap) (nat.PortMap, nat.PortSet, error) { + templateSpec, err := option.GetPodTemplateSpec(ctx) if err != nil { plog.G(context.Background()).Errorf("Failed to get unstructured object error: %v", err) return nil, nil, err @@ -390,13 +390,13 @@ func (option *Options) InitClient(f cmdutil.Factory) (err error) { return } -func (option *Options) GetPodTemplateSpec() (*v1.PodTemplateSpec, error) { - object, err := util.GetUnstructuredObject(option.factory, option.Namespace, option.Workload) +func (option *Options) GetPodTemplateSpec(ctx context.Context) (*v1.PodTemplateSpec, error) { + _, controller, err := util.GetTopOwnerObject(ctx, option.factory, option.Namespace, option.Workload) if err != nil { return nil, err } - u := object.Object.(*unstructured.Unstructured) + u := controller.Object.(*unstructured.Unstructured) var templateSpec *v1.PodTemplateSpec templateSpec, _, err = util.GetPodTemplateSpecPath(u) return templateSpec, err diff --git a/pkg/dev/runconfig.go b/pkg/dev/runconfig.go index dc8d162b..2b856b14 100644 --- a/pkg/dev/runconfig.go +++ b/pkg/dev/runconfig.go @@ -71,7 +71,7 @@ func (l ConfigList) Run(ctx context.Context) error { } if index != 0 { - err := WaitDockerContainerRunning(ctx, conf.name) + err = WaitDockerContainerRunning(ctx, conf.name) if err != nil { return err } diff --git a/pkg/dhcp/dhcp.go b/pkg/dhcp/dhcp.go index 43a21336..8c72e0eb 100644 --- a/pkg/dhcp/dhcp.go +++ b/pkg/dhcp/dhcp.go @@ -12,7 +12,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - corev1 "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/util/retry" "github.com/wencaiwulue/kubevpn/v2/pkg/config" @@ -21,14 +21,14 @@ import ( ) type Manager struct { - client corev1.ConfigMapInterface + client *kubernetes.Clientset cidr *net.IPNet cidr6 *net.IPNet namespace string clusterID types.UID } -func NewDHCPManager(client corev1.ConfigMapInterface, namespace string) *Manager { +func NewDHCPManager(client *kubernetes.Clientset, namespace string) *Manager { return &Manager{ client: client, namespace: namespace, @@ -40,14 +40,14 @@ func NewDHCPManager(client corev1.ConfigMapInterface, namespace string) *Manager // InitDHCP // TODO optimize dhcp, using mac address, ip and deadline as unit func (m *Manager) InitDHCP(ctx context.Context) error { - cm, err := m.client.Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{}) + cm, err := m.client.CoreV1().ConfigMaps(m.namespace).Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{}) if err != nil && !apierrors.IsNotFound(err) { return fmt.Errorf("failed to get configmap %s, err: %v", config.ConfigMapPodTrafficManager, err) } if err == nil { - m.clusterID = util.GetClusterIDByCM(cm) - return nil + m.clusterID, err = util.GetClusterID(ctx, m.client.CoreV1().Namespaces(), m.namespace) + return err } cm = &v1.ConfigMap{ @@ -63,12 +63,12 @@ func (m *Manager) InitDHCP(ctx context.Context) error { config.KeyClusterIPv4POOLS: "", }, } - cm, err = m.client.Create(ctx, cm, metav1.CreateOptions{}) + cm, err = m.client.CoreV1().ConfigMaps(m.namespace).Create(ctx, cm, metav1.CreateOptions{}) if err != nil { return fmt.Errorf("failed to create configmap: %v", err) } - m.clusterID = util.GetClusterIDByCM(cm) - return nil + m.clusterID, err = util.GetClusterID(ctx, m.client.CoreV1().Namespaces(), m.namespace) + return err } func (m *Manager) RentIP(ctx context.Context) (*net.IPNet, *net.IPNet, error) { @@ -134,7 +134,7 @@ func (m *Manager) ReleaseIP(ctx context.Context, ips ...net.IP) error { } func (m *Manager) updateDHCPConfigMap(ctx context.Context, f func(ipv4 *ipallocator.Range, ipv6 *ipallocator.Range) error) error { - cm, err := m.client.Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{}) + cm, err := m.client.CoreV1().ConfigMaps(m.namespace).Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{}) if err != nil { return fmt.Errorf("failed to get configmap DHCP server, err: %v", err) } @@ -189,7 +189,7 @@ func (m *Manager) updateDHCPConfigMap(ctx context.Context, f func(ipv4 *ipalloca return err } cm.Data[config.KeyDHCP6] = base64.StdEncoding.EncodeToString(bytes) - _, err = m.client.Update(ctx, cm, metav1.UpdateOptions{}) + _, err = m.client.CoreV1().ConfigMaps(m.namespace).Update(ctx, cm, metav1.UpdateOptions{}) if err != nil { return fmt.Errorf("failed to update DHCP: %v", err) } @@ -201,7 +201,7 @@ func (m *Manager) Set(ctx context.Context, key, value string) error { retry.DefaultRetry, func() error { p := []byte(fmt.Sprintf(`[{"op": "replace", "path": "/data/%s", "value": "%s"}]`, key, value)) - _, err := m.client.Patch(ctx, config.ConfigMapPodTrafficManager, types.JSONPatchType, p, metav1.PatchOptions{}) + _, err := m.client.CoreV1().ConfigMaps(m.namespace).Patch(ctx, config.ConfigMapPodTrafficManager, types.JSONPatchType, p, metav1.PatchOptions{}) return err }) if err != nil { @@ -212,7 +212,7 @@ func (m *Manager) Set(ctx context.Context, key, value string) error { } func (m *Manager) Get(ctx context.Context, key string) (string, error) { - cm, err := m.client.Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{}) + cm, err := m.client.CoreV1().ConfigMaps(m.namespace).Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{}) if err != nil { return "", err } @@ -220,7 +220,7 @@ func (m *Manager) Get(ctx context.Context, key string) (string, error) { } func (m *Manager) ForEach(ctx context.Context, fnv4 func(net.IP), fnv6 func(net.IP)) error { - cm, err := m.client.Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{}) + cm, err := m.client.CoreV1().ConfigMaps(m.namespace).Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{}) if err != nil { return fmt.Errorf("failed to get cm DHCP server, err: %v", err) } diff --git a/pkg/dhcp/server.go b/pkg/dhcp/server.go index 8246901f..dfe2d92d 100644 --- a/pkg/dhcp/server.go +++ b/pkg/dhcp/server.go @@ -29,8 +29,7 @@ func (s *Server) RentIP(ctx context.Context, req *rpc.RentIPRequest) (*rpc.RentI defer s.Unlock() plog.G(ctx).Infof("Handling rent IP request, pod name: %s, ns: %s", req.PodName, req.PodNamespace) - mapInterface := s.clientset.CoreV1().ConfigMaps(req.PodNamespace) - manager := NewDHCPManager(mapInterface, req.PodNamespace) + manager := NewDHCPManager(s.clientset, req.PodNamespace) v4, v6, err := manager.RentIP(ctx) if err != nil { plog.G(ctx).Errorf("Failed to rent IP: %v", err) @@ -59,8 +58,7 @@ func (s *Server) ReleaseIP(ctx context.Context, req *rpc.ReleaseIPRequest) (*rpc ips = append(ips, ip) } - mapInterface := s.clientset.CoreV1().ConfigMaps(req.PodNamespace) - manager := NewDHCPManager(mapInterface, req.PodNamespace) + manager := NewDHCPManager(s.clientset, req.PodNamespace) if err := manager.ReleaseIP(ctx, ips...); err != nil { plog.G(ctx).Errorf("Failed to release IP: %v", err) return nil, err diff --git a/pkg/handler/clone.go b/pkg/handler/clone.go index 91cace09..7a14e233 100644 --- a/pkg/handler/clone.go +++ b/pkg/handler/clone.go @@ -97,11 +97,11 @@ func (d *CloneOptions) DoClone(ctx context.Context, kubeconfigJsonBytes []byte, } for _, workload := range d.Workloads { plog.G(ctx).Infof("Clone workload %s", workload) - object, err := util.GetUnstructuredObject(d.factory, d.Namespace, workload) + _, controller, err := util.GetTopOwnerObject(ctx, d.factory, d.Namespace, workload) if err != nil { return err } - u := object.Object.(*unstructured.Unstructured) + u := controller.Object.(*unstructured.Unstructured) if err = unstructured.SetNestedField(u.UnstructuredContent(), int64(1), "spec", "replicas"); err != nil { plog.G(ctx).Warnf("Failed to set repilcaset to 1: %v", err) } @@ -113,7 +113,7 @@ func (d *CloneOptions) DoClone(ctx context.Context, kubeconfigJsonBytes []byte, } originName := u.GetName() u.SetName(fmt.Sprintf("%s-clone-%s", u.GetName(), newUUID.String()[:5])) - d.TargetWorkloadNames[workload] = fmt.Sprintf("%s/%s", object.Mapping.Resource.GroupResource().Resource, u.GetName()) + d.TargetWorkloadNames[workload] = fmt.Sprintf("%s/%s", controller.Mapping.Resource.GroupResource().Resource, u.GetName()) labelsMap := map[string]string{ config.ManageBy: config.ConfigMapPodTrafficManager, "owner-ref": u.GetName(), @@ -242,15 +242,11 @@ func (d *CloneOptions) DoClone(ctx context.Context, kubeconfigJsonBytes []byte, if err != nil { return err } - //v := unstructured.Unstructured{} - //_, _, err = clientgoscheme.Codecs.UniversalDecoder(object.Mapping.GroupVersionKind.GroupVersion()).Decode(marshal, nil, &v) - //_, _, err = unstructured.UnstructuredJSONScheme.Decode(marshal, &object.Mapping.GroupVersionKind, &v) if err = unstructured.SetNestedField(u.Object, m, path...); err != nil { return err } - _, createErr := client.Resource(object.Mapping.Resource).Namespace(d.Namespace).Create(context.Background(), u, metav1.CreateOptions{}) - //_, createErr := runtimeresource.NewHelper(object.Client, object.Mapping).Create(d.TargetNamespace, true, u) + _, createErr := client.Resource(controller.Mapping.Resource).Namespace(d.Namespace).Create(context.Background(), u, metav1.CreateOptions{}) return createErr }) if retryErr != nil { diff --git a/pkg/handler/connect.go b/pkg/handler/connect.go index 4458bc8b..1b085cac 100644 --- a/pkg/handler/connect.go +++ b/pkg/handler/connect.go @@ -100,7 +100,7 @@ func (c *ConnectOptions) Context() context.Context { func (c *ConnectOptions) InitDHCP(ctx context.Context) error { if c.dhcp == nil { - c.dhcp = dhcp.NewDHCPManager(c.clientset.CoreV1().ConfigMaps(c.Namespace), c.Namespace) + c.dhcp = dhcp.NewDHCPManager(c.clientset, c.Namespace) return c.dhcp.InitDHCP(ctx) } return nil @@ -211,7 +211,7 @@ func (c *ConnectOptions) CreateRemoteInboundPod(ctx context.Context, namespace s func (c *ConnectOptions) DoConnect(ctx context.Context, isLite bool) (err error) { c.ctx, c.cancel = context.WithCancel(ctx) plog.G(ctx).Info("Starting connect to cluster") - m := dhcp.NewDHCPManager(c.clientset.CoreV1().ConfigMaps(c.Namespace), c.Namespace) + m := dhcp.NewDHCPManager(c.clientset, c.Namespace) if err = m.InitDHCP(c.ctx); err != nil { plog.G(ctx).Errorf("Init DHCP server failed: %v", err) return diff --git a/pkg/util/dns.go b/pkg/util/dns.go index fd2e48c2..355cc32b 100644 --- a/pkg/util/dns.go +++ b/pkg/util/dns.go @@ -13,8 +13,6 @@ import ( "k8s.io/apimachinery/pkg/fields" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - - "github.com/wencaiwulue/kubevpn/v2/pkg/config" ) func GetDNSServiceIPFromPod(ctx context.Context, clientset *kubernetes.Clientset, conf *rest.Config, podName, namespace string) (*dns.ClientConfig, error) { @@ -73,10 +71,5 @@ func GetDNS(ctx context.Context, clientSet *kubernetes.Clientset, restConfig *re if err != nil { return nil, err } - svc, err := clientSet.CoreV1().Services(ns).Get(ctx, config.ConfigMapPodTrafficManager, v12.GetOptions{}) - if err != nil { - return nil, err - } - clientConfig.Servers = []string{svc.Spec.ClusterIP} return clientConfig, nil } diff --git a/pkg/util/ns.go b/pkg/util/ns.go index 25869b84..9ed020f3 100644 --- a/pkg/util/ns.go +++ b/pkg/util/ns.go @@ -12,7 +12,6 @@ import ( "unsafe" errors2 "github.com/pkg/errors" - v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -32,28 +31,23 @@ import ( "github.com/wencaiwulue/kubevpn/v2/pkg/log" ) -func GetClusterID(ctx context.Context, client v12.ConfigMapInterface) (types.UID, error) { - configMap, err := client.Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{}) +func GetClusterID(ctx context.Context, client v12.NamespaceInterface, ns string) (types.UID, error) { + namespace, err := client.Get(ctx, ns, metav1.GetOptions{}) if err != nil { return "", err } - return configMap.UID, nil + return namespace.UID, nil } -func GetClusterIDByCM(cm *v1.ConfigMap) types.UID { - return cm.UID -} - -func IsSameCluster(ctx context.Context, client v12.CoreV1Interface, namespace string, clientB v12.CoreV1Interface, namespaceB string) (bool, error) { - if namespace != namespaceB { +func IsSameCluster(ctx context.Context, clientA v12.CoreV1Interface, namespaceA string, clientB v12.CoreV1Interface, namespaceB string) (bool, error) { + if namespaceA != namespaceB { return false, nil } - clusterIDA, err := GetClusterID(ctx, client.ConfigMaps(namespace)) + clusterIDA, err := GetClusterID(ctx, clientA.Namespaces(), namespaceA) if err != nil { return false, err } - var clusterIDB types.UID - clusterIDB, err = GetClusterID(ctx, clientB.ConfigMaps(namespaceB)) + clusterIDB, err := GetClusterID(ctx, clientB.Namespaces(), namespaceB) if err != nil { return false, err } diff --git a/pkg/util/pod.go b/pkg/util/pod.go index 8ba4de16..20b0c46c 100644 --- a/pkg/util/pod.go +++ b/pkg/util/pod.go @@ -19,7 +19,6 @@ import ( "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/util/httpstream" "k8s.io/apimachinery/pkg/util/sets" @@ -189,45 +188,7 @@ func PortForwardPod(config *rest.Config, clientset *rest.RESTClient, podName, na } } -func GetTopOwnerReference(factory util.Factory, ns, workload string) (object, controller *resource.Info, err error) { - object, err = GetUnstructuredObject(factory, ns, workload) - if err != nil { - return nil, nil, err - } - ownerRef := v1.GetControllerOf(object.Object.(*unstructured.Unstructured)) - if ownerRef == nil { - return object, object, err - } - var owner = fmt.Sprintf("%s/%s", ownerRef.Kind, ownerRef.Name) - for { - controller, err = GetUnstructuredObject(factory, ns, owner) - if err != nil { - return nil, nil, err - } - ownerRef = v1.GetControllerOf(controller.Object.(*unstructured.Unstructured)) - if ownerRef == nil { - return object, controller, nil - } - owner = fmt.Sprintf("%s/%s", ownerRef.Kind, ownerRef.Name) - } -} - -// GetTopOwnerReferenceBySelector assume pods, controller has same labels -func GetTopOwnerReferenceBySelector(factory util.Factory, ns, selector string) (object, controller *resource.Info, err error) { - objectList, err := GetUnstructuredObjectBySelector(factory, ns, selector) - if err != nil { - return nil, nil, err - } - for _, info := range objectList { - if IsK8sService(info) { - continue - } - return GetTopOwnerReference(factory, ns, fmt.Sprintf("%s/%s", info.Mapping.Resource.GroupResource().String(), info.Name)) - } - return nil, nil, fmt.Errorf("can not find controller for %s", selector) -} - -func Shell(_ context.Context, clientset *kubernetes.Clientset, config *rest.Config, podName, containerName, ns string, cmd []string) (string, error) { +func Shell(ctx context.Context, clientset *kubernetes.Clientset, config *rest.Config, podName, containerName, ns string, cmd []string) (string, error) { stdin, _, _ := term.StdStreams() buf := bytes.NewBuffer(nil) options := exec.ExecOptions{ diff --git a/pkg/util/unstructure.go b/pkg/util/unstructure.go index c6d42112..6a51113e 100644 --- a/pkg/util/unstructure.go +++ b/pkg/util/unstructure.go @@ -62,7 +62,7 @@ func GetUnstructuredObjectList(f util.Factory, ns string, workloads []string) ([ return infos, err } -func GetUnstructuredObjectBySelector(f util.Factory, ns string, selector string) ([]*resource.Info, error) { +func getUnstructuredObjectBySelector(f util.Factory, ns string, selector string) ([]*resource.Info, error) { do := f.NewBuilder(). Unstructured(). NamespaceParam(ns).DefaultNamespace().AllNamespaces(false). @@ -139,7 +139,7 @@ func NormalizedResource(f util.Factory, ns string, workloads []string) ([]string func GetTopOwnerObject(ctx context.Context, f util.Factory, ns string, workload string) (object, controller *resource.Info, err error) { // normal workload, like pod with controller, deployments, statefulset, replicaset etc... - object, controller, err = GetTopOwnerReference(f, ns, workload) + object, controller, err = getTopOwnerReference(f, ns, workload) if err != nil { return nil, nil, err } @@ -168,14 +168,52 @@ func GetTopOwnerObject(ctx context.Context, f util.Factory, ns string, workload } // if pod is not empty, using pods to find top controller if len(podList.Items) != 0 { - _, controller, err = GetTopOwnerReference(f, ns, fmt.Sprintf("%s/%s", "pods", podList.Items[0].Name)) + _, controller, err = getTopOwnerReference(f, ns, fmt.Sprintf("%s/%s", "pods", podList.Items[0].Name)) return object, controller, err } // if list is empty, means not create pods, just controllers - _, controller, err = GetTopOwnerReferenceBySelector(f, ns, selector.String()) + _, controller, err = getTopOwnerReferenceBySelector(f, ns, selector.String()) return object, controller, err } func IsK8sService(info *resource.Info) bool { return info.Mapping.Resource.Resource == "services" } + +func getTopOwnerReference(factory util.Factory, ns, workload string) (object, controller *resource.Info, err error) { + object, err = GetUnstructuredObject(factory, ns, workload) + if err != nil { + return nil, nil, err + } + ownerRef := v2.GetControllerOf(object.Object.(*unstructured.Unstructured)) + if ownerRef == nil { + return object, object, err + } + var owner = fmt.Sprintf("%s/%s", ownerRef.Kind, ownerRef.Name) + for { + controller, err = GetUnstructuredObject(factory, ns, owner) + if err != nil { + return nil, nil, err + } + ownerRef = v2.GetControllerOf(controller.Object.(*unstructured.Unstructured)) + if ownerRef == nil { + return object, controller, nil + } + owner = fmt.Sprintf("%s/%s", ownerRef.Kind, ownerRef.Name) + } +} + +// getTopOwnerReferenceBySelector assume pods, controller has same labels +func getTopOwnerReferenceBySelector(factory util.Factory, ns, selector string) (object, controller *resource.Info, err error) { + objectList, err := getUnstructuredObjectBySelector(factory, ns, selector) + if err != nil { + return nil, nil, err + } + for _, info := range objectList { + if IsK8sService(info) { + continue + } + return getTopOwnerReference(factory, ns, fmt.Sprintf("%s/%s", info.Mapping.Resource.GroupResource().String(), info.Name)) + } + return nil, nil, fmt.Errorf("can not find controller for %s", selector) +}