From 20aa2a1f299bf934ebac695471b1d061552bec2f Mon Sep 17 00:00:00 2001 From: googs1025 Date: Sat, 2 Dec 2023 19:00:30 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=96=B0=E5=A2=9E=E9=AA=8C=E8=AF=81=20p?= =?UTF-8?q?od=20container=20=E7=8A=B6=E6=80=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/example.go | 11 +++++ go.mod | 3 +- go.sum | 2 + pkg/pod_exec_command/pod_exec.go | 63 +++++++++++++++++++++------ pkg/pod_exec_command/pod_exec_test.go | 7 +-- 5 files changed, 68 insertions(+), 18 deletions(-) diff --git a/example/example.go b/example/example.go index fac9095..6482753 100644 --- a/example/example.go +++ b/example/example.go @@ -3,7 +3,9 @@ package main import ( "fmt" "github.com/practice/shell_extender/pkg/command" + "github.com/practice/shell_extender/pkg/pod_exec_command" "github.com/practice/shell_extender/pkg/remote_command" + "log" ) func main() { @@ -73,4 +75,13 @@ func main() { fmt.Println(err) } fmt.Println("===============================") + + fmt.Println("==============ExecPodContainerCmd=================") + cmd := pod_exec_command.NewExecPodContainerCmd("./pkg/pod_exec_command/config1", "test-pod", + "my-container", "default", true) + err = cmd.Run([]string{"sh", "-c", "ls -a"}) + if err != nil { + log.Fatal(err) + } + fmt.Println("===============================") } diff --git a/go.mod b/go.mod index a34e34f..275da4a 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,11 @@ go 1.18 require ( github.com/go-ping/ping v1.1.0 github.com/go-yaml/yaml v2.1.0+incompatible + github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.7.0 golang.org/x/crypto v0.11.0 k8s.io/api v0.27.4 + k8s.io/apimachinery v0.27.4 k8s.io/client-go v0.27.4 ) @@ -46,7 +48,6 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apimachinery v0.27.4 // indirect k8s.io/klog/v2 v2.90.1 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect diff --git a/go.sum b/go.sum index e30c59e..0bb957d 100644 --- a/go.sum +++ b/go.sum @@ -169,6 +169,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/pkg/pod_exec_command/pod_exec.go b/pkg/pod_exec_command/pod_exec.go index 80bda1d..85dfb7c 100644 --- a/pkg/pod_exec_command/pod_exec.go +++ b/pkg/pod_exec_command/pod_exec.go @@ -2,8 +2,11 @@ package pod_exec_command import ( "context" - "errors" - v1 "k8s.io/api/core/v1" + "fmt" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" @@ -12,20 +15,15 @@ import ( "os" ) -var ( - ErrParseKubeConfig = errors.New("parse kube config file error") - ErrPrepareClient = errors.New("prepare kube client error") - ErrSPDYExecutor = errors.New("SPDY Exec error") -) - type ExecPodContainerCmd struct { // kubeConfig kubeconfig目录地址,默认集群内.kube/config - kubeConfig string + kubeConfig string // insecure 是否跳过tls鉴权 insecure bool podName string containerName string namespace string + k8sClient kubernetes.Interface } func NewExecPodContainerCmd(kubeConfig string, podName string, containerName string, namespace string, insecure bool) *ExecPodContainerCmd { @@ -35,22 +33,53 @@ func NewExecPodContainerCmd(kubeConfig string, podName string, containerName str } // prepare 准备登入材料 -func (epc *ExecPodContainerCmd) prepare() (*rest.Config, *kubernetes.Clientset, error) { +func (epc *ExecPodContainerCmd) prepare() (*rest.Config, kubernetes.Interface, error) { config, err := clientcmd.BuildConfigFromFlags("", epc.kubeConfig) if err != nil { - return nil, nil, ErrParseKubeConfig + return nil, nil, errors.Wrapf(err, "parse kube config file error: %s", err) } config.Insecure = epc.insecure client, err := kubernetes.NewForConfig(config) if err != nil { - return nil, nil, ErrPrepareClient + return nil, nil, errors.Wrapf(err, "prepare kube client error: %s", err) } + epc.k8sClient = client return config, client, nil } +// validatePod 验证 pod container +func (epc *ExecPodContainerCmd) validatePod(ctx context.Context, podName, containerName, namespace string) error { + pod, err := epc.k8sClient.CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{}) + if err != nil && k8serrors.IsNotFound(err) { + return fmt.Errorf("pod %s/%s not found", namespace, podName) + } + + if err != nil { + return err + } + + if pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed { + return fmt.Errorf("cannot exec into container in a completed pod, current phase %s", pod.Status.Phase) + } + + for _, cc := range pod.Spec.InitContainers { + if containerName == cc.Name { + return fmt.Errorf("can't exec init container %s in pod %s/%s ", containerName, namespace, podName) + } + } + + for _, cs := range pod.Status.ContainerStatuses { + if containerName == cs.Name { + return nil + } + } + + return fmt.Errorf("pod has no container %s", containerName) +} + // Run 执行远程命令 func (epc *ExecPodContainerCmd) Run(command []string) error { - option := &v1.PodExecOptions{ + option := &corev1.PodExecOptions{ Container: epc.containerName, Command: command, Stdin: true, @@ -63,6 +92,12 @@ func (epc *ExecPodContainerCmd) Run(command []string) error { return err } + // 校验 pod container 是否存在 + err = epc.validatePod(context.Background(), epc.podName, epc.containerName, epc.namespace) + if err != nil { + return errors.Wrapf(err, "validate Pod error: %s", err) + } + // 执行pods中 特定container容器的命令 req := client.CoreV1().RESTClient().Post().Resource("pods"). Namespace(epc.namespace). @@ -76,7 +111,7 @@ func (epc *ExecPodContainerCmd) Run(command []string) error { exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL()) if err != nil { - return ErrSPDYExecutor + return errors.Wrapf(err, "SPDY Exec error: %s", err) } return exec.StreamWithContext(context.Background(), remotecommand.StreamOptions{ diff --git a/pkg/pod_exec_command/pod_exec_test.go b/pkg/pod_exec_command/pod_exec_test.go index 93a8e05..cbbe687 100644 --- a/pkg/pod_exec_command/pod_exec_test.go +++ b/pkg/pod_exec_command/pod_exec_test.go @@ -1,15 +1,16 @@ package pod_exec_command import ( + "log" "testing" ) func TestHandleCommand(t *testing.T) { - cmd := NewExecPodContainerCmd("./config", "myinspect-controller-69748dc6bf-84wdp", - "myinspect-controller", "default", true) + cmd := NewExecPodContainerCmd("./config1", "test-pod", + "my-container", "default", true) err := cmd.Run([]string{"sh", "-c", "ls -a"}) if err != nil { - return + log.Fatal(err) } }