diff options
| author | 林鑫 <[email protected]> | 2024-08-14 09:27:16 +0000 |
|---|---|---|
| committer | linxin <[email protected]> | 2024-11-06 15:32:28 +0800 |
| commit | 2eb301a4e15139966dc121d4ce97374c9b2aea5b (patch) | |
| tree | a9a12a748c17468bb1956530002a900ee26b8b35 | |
| parent | 1b4daca45af82253934b9e5882ac76c8ca9bd546 (diff) | |
✨ feat:add feature:store excutable file of coredump
| -rw-r--r-- | .vscode/settings.json | 4 | ||||
| -rw-r--r-- | coredump-handler/coredump-handler.go | 100 | ||||
| -rw-r--r-- | coredump-handler/coredump-handler_test.go | 6 | ||||
| -rw-r--r-- | coredump-tool/coredump-tool.go | 278 | ||||
| -rw-r--r-- | types/types.go | 1 |
5 files changed, 252 insertions, 137 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..043dcf4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "DevChat.PythonForChat": "c:\\Users\\10126\\.vscode\\extensions\\merico.devchat-0.1.47\\tools\\python-3.11.6-embed-amd64\\python.exe", + "DevChat.PythonForCommands": "C:\\Users\\10126\\.chat\\mamba\\envs\\devchat-commands\\python.exe" +}
\ No newline at end of file diff --git a/coredump-handler/coredump-handler.go b/coredump-handler/coredump-handler.go index bbf072e..4711e72 100644 --- a/coredump-handler/coredump-handler.go +++ b/coredump-handler/coredump-handler.go @@ -8,6 +8,7 @@ import "C" import ( "archive/zip" + "bufio" "context" "coredump-tools/config" "coredump-tools/types" @@ -253,6 +254,103 @@ func compress(config types.Coredump_config) error { return nil } +func getLibrariesFromMaps(mapsFile string) ([]string, error) { + file, err := os.Open(mapsFile) + if err != nil { + return nil, err + } + defer file.Close() + + libSet := make(map[string]struct{}) + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + parts := strings.Fields(line) + if len(parts) > 5 && !strings.Contains(parts[5], "[") && strings.Contains(parts[1], "x") { + libSet[parts[5]] = struct{}{} + } + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + var libs []string + for lib := range libSet { + libs = append(libs, lib) + } + + return libs, nil +} + +func addFileToZip(zipWriter *zip.Writer, filename string, pid string, pipe_config types.Pipeconfig) error { + libabspath := fmt.Sprintf("/proc/%s/root%s", pid, filename) + fileToZip, err := os.Open(libabspath) + if err != nil { + return err + } + defer fileToZip.Close() + + info, err := fileToZip.Stat() + if err != nil { + return err + } + + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + header.Name = filename + header.Method = zip.Deflate + + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + + _, err = io.Copy(writer, fileToZip) + if err != nil { + return err + } + flag, _, err := isDiskSufficient(pipe_config) + if err != nil { + journal.Print(journal.PriErr, "Can't judge disk's space is sufficient or not. "+err.Error()) + return err + } + if !flag { + return errors.New("Disk space exceeds limit when writing coredump!") + } + return nil +} + +func writelibfile(pid string, pipe_config types.Pipeconfig) error { + mapsFile := fmt.Sprintf("/proc/%s/maps", pid) + libs, err := getLibrariesFromMaps(mapsFile) + if err != nil { + return err + } + // for _, lib := range libs { + // journal.Print(journal.PriDebug,lib) + // } + // journal.Print(journal.PriDebug,"lib's num:", len(libs)) + filePath := fmt.Sprintf("%s/Executable_file.gz", pipe_config.Storage) + zipFile, err := os.Create(filePath) + if err != nil { + return err + } + defer zipFile.Close() + + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + for _, file := range libs { + addFileToZip(zipWriter, file, pid, pipe_config) + } + + journal.Print(journal.PriInfo, "Tar file created successfully") + return nil +} + func init() { flag.StringVar(&coredump_config.Initial_ns_pid, "P", "", "initial ns pid") flag.StringVar(&coredump_config.Process_ns_pid, "p", "", "process ns pid") @@ -367,6 +465,8 @@ func start() { } coredump_config.Storage = fmt.Sprintf("%s/%s_%s_%d.coredump.zip", pipe_config.Storage, coredump_config.Initial_ns_pid, coredump_config.Process_ns_pid, coredump_config.Timestamp) } + writelibfile(coredump_config.Initial_ns_pid, pipe_config) + coredump_config.Executable_file = fmt.Sprintf("%s/Executable_file.gz", pipe_config.Storage) //write coredump info err = writeCoreConfig(coredump_config) if err != nil { diff --git a/coredump-handler/coredump-handler_test.go b/coredump-handler/coredump-handler_test.go index 70dea3d..b82989b 100644 --- a/coredump-handler/coredump-handler_test.go +++ b/coredump-handler/coredump-handler_test.go @@ -45,7 +45,7 @@ func TestIsDiskSufficient(t *testing.T) { pipe_config := types.Pipeconfig{ Total_file_mem_limit: "50%", } - res, err := isDiskSufficient(pipe_config) + res, _, err := isDiskSufficient(pipe_config) if err != nil || !res { t.Errorf("isDiskSufficient() error = %v; want res = true", err) } @@ -76,8 +76,8 @@ func TestGetContainerId(t *testing.T) { } func TestGetImageId(t *testing.T) { - image_id, err := getImageName("1234567890abcdef", "/var/run/containerd.sock") - if err != nil || len(image_id) == 0 { + image_id, pod_name, err := getContainerInfo("1234567890abcdef", "/var/run/containerd.sock") + if err != nil || len(image_id) == 0 || len(pod_name) == 0 { t.Errorf("getImageId() error = %v; want image_id != \"\"", err) } } diff --git a/coredump-tool/coredump-tool.go b/coredump-tool/coredump-tool.go index b659d1e..45dda30 100644 --- a/coredump-tool/coredump-tool.go +++ b/coredump-tool/coredump-tool.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "bytes" "context" "coredump-tools/types" @@ -123,22 +124,6 @@ func list(pid string) { } func info(pid string) { - table := simpletable.New() - - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Text: "PID"}, - {Text: "UID"}, - {Text: "GID"}, - {Text: "SIG"}, - {Text: "EXE"}, - {Text: "POD"}, - {Text: "IMAGE"}, - {Text: "HOSTNAME"}, - {Text: "STORAGE"}, - {Text: "TIMESTAMP"}, - }, - } total := 0 // output the config's info for _, c := range configs { @@ -146,25 +131,46 @@ func info(pid string) { continue } coreTime := time.Unix(c.Timestamp, 0).Format("2006-01-02 15:04:05") - r := []*simpletable.Cell{ - {Text: c.Initial_ns_pid}, - {Text: c.UID}, - {Text: c.GID}, - {Text: strconv.Itoa(c.Signal)}, - {Text: c.Process_exe_path}, - {Text: c.Pod_name}, - {Text: c.Image_name}, - {Text: c.Hostname}, - {Text: c.Storage}, - {Text: coreTime}, - } - table.Body.Cells = append(table.Body.Cells, r) + fmt.Println("PID: " + c.Initial_ns_pid) + fmt.Println("UID: " + c.UID) + fmt.Println("GID: " + c.GID) + fmt.Println("SIG: " + strconv.Itoa(c.Signal)) + fmt.Println("EXE: " + c.Process_exe_path) + fmt.Println("POD: " + c.Pod_name) + fmt.Println("IMAGE: " + c.Image_name) + fmt.Println("HOSTNAME: " + c.Hostname) + fmt.Println("STORAGE: " + c.Storage) + fmt.Println("TIMESTAMP: " + coreTime) + fmt.Println() + fmt.Println() total += 1 } - fmt.Println(table.String()) fmt.Println("Total", total, "coredumps") } +func getImageVersion() (string, error) { + file, err := os.Open("/etc/os-release") + if err != nil { + return "", err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "VERSION=") { + version := strings.TrimPrefix(line, "VERSION=") + version = strings.Trim(version, "\"") + imageVersion := strings.Split(version, " ") + fmt.Println("imageVersion:", imageVersion[0]) + if len(imageVersion[0]) > 0 { + return imageVersion[0], nil + } + break + } + } + return "", errors.New("get empty version info") +} + func debug(config types.Coredump_config, command, prestartPath string) error { if strings.HasSuffix(config.Storage, ".minidump") { corefile := strings.Replace(config.Storage, ".minidump", ".coredump", -1) @@ -178,43 +184,33 @@ func debug(config types.Coredump_config, command, prestartPath string) error { config.Storage = corefile defer os.Remove(corefile) } - if config.Image_name != "NULL" { - kubeconfig := os.Getenv("KUBECONFIG") - if kubeconfig == "" { - kubeconfig = os.Getenv("HOME") + "/.kube/config" - } + kubeconfig := os.Getenv("KUBECONFIG") + if kubeconfig == "" { + kubeconfig = os.Getenv("HOME") + "/.kube/config" + } - // Creates the kubernetes client using the specified kubeconfig - conf, err := clientcmd.BuildConfigFromFlags("", kubeconfig) - if err != nil { - return err - } + // Creates the kubernetes client using the specified kubeconfig + conf, err := clientcmd.BuildConfigFromFlags("", kubeconfig) + if err != nil { + return err + } - clientset, err := kubernetes.NewForConfig(conf) - if err != nil { - return err - } - podName, err := debugInpod(conf, clientset, config, command, prestartPath) - if err != nil { - fmt.Println(err) - } - // Delete the Pod + clientset, err := kubernetes.NewForConfig(conf) + if err != nil { + return err + } + podName, err := debugInpod(conf, clientset, config, command, prestartPath) + if err != nil { + fmt.Println(err) + } + // Delete the Pod + if podName != "" { fmt.Printf("Deleting Pod %q...\n", podName) err = clientset.CoreV1().Pods("default").Delete(context.Background(), podName, metav1.DeleteOptions{}) if err != nil { return err } fmt.Printf("Deleted Pod %q.\n", podName) - return nil - } else { // using gdb to debug the coredump file - cmd := exec.Command("gdb", config.Process_exe_path, config.Storage, "-cd", filepath.Dir(config.Process_exe_path)) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - fmt.Println(cmd.String()) - if err := cmd.Run(); err != nil { - return err - } } return nil } @@ -224,81 +220,71 @@ func debugInpod(conf *rest.Config, clientset *kubernetes.Clientset, config types fmt.Println(id.String()) podName := fmt.Sprintf("coredump-debug-%s", id.String()) containerName := "debug" - pod := &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: podName, - Namespace: "default", + imageversion, err := getImageVersion() + if err != nil { + return "", err + } + image := fmt.Sprintln("registry.gdnt-cloud.website/tsg-init:", imageversion) + volumeMounts := []v1.VolumeMount{ + { + Name: "host-dir", + MountPath: "/host", }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "debug", - Image: config.Image_name, - ImagePullPolicy: "IfNotPresent", - Command: []string{ - "tail", - "-f", - }, - VolumeMounts: []v1.VolumeMount{ - { - Name: "host-dir", - MountPath: "/host", - }, - { - Name: "lib-debuginfo-dir", - MountPath: "/usr/lib/debug", - }, - { - Name: "src-debuginfo-dir", - MountPath: "/usr/src/debug", - }, - { - Name: "mrzcpd", - MountPath: "/opt/tsg/mrzcpd", - }, - }, - SecurityContext: &v1.SecurityContext{ - Privileged: &[]bool{true}[0], - }, + { + Name: "lib-debuginfo-dir", + MountPath: "/usr/lib/debug", + }, + { + Name: "src-debuginfo-dir", + MountPath: "/usr/src/debug", + }, + { + Name: "mrzcpd", + MountPath: "/opt/tsg/mrzcpd", + }, + } + volumes := []v1.Volume{ + { + Name: "host-dir", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/", }, }, - Volumes: []v1.Volume{ - { - Name: "host-dir", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/", - }, - }, - }, - { - Name: "lib-debuginfo-dir", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/usr/lib/debug", - }, - }, + }, + { + Name: "lib-debuginfo-dir", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/usr/lib/debug", }, - { - Name: "src-debuginfo-dir", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/usr/src/debug", - }, - }, + }, + }, + { + Name: "src-debuginfo-dir", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/usr/src/debug", }, - { - Name: "mrzcpd", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/opt/tsg/mrzcpd", - }, - }, + }, + }, + { + Name: "mrzcpd", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/opt/tsg/mrzcpd", }, }, - RestartPolicy: v1.RestartPolicyNever, }, } + var containerCommands []string + var containerCommand string + if _, err := os.Stat(config.Executable_file); err != nil { + fmt.Println(err) + containerCommand = "tail -f" + } else { + containerCommand = fmt.Sprintf("unzip -o /host%s ; tail -f", config.Executable_file) + } if prestartPath != "" { prestartVolumeMount := v1.VolumeMount{ Name: "prestart-dir", @@ -312,20 +298,48 @@ func debugInpod(conf *rest.Config, clientset *kubernetes.Clientset, config types }, }, } - pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, prestartVolumeMount) - pod.Spec.Volumes = append(pod.Spec.Volumes, prestartVolume) - pod.Spec.Containers[0].Command = []string{ + volumeMounts = append(volumeMounts, prestartVolumeMount) + volumes = append(volumes, prestartVolume) + containerCommands = []string{ "sh", "-c", - "chmod +x /prestart.sh && /prestart.sh && tail -f", + "chmod +x /prestart.sh && /prestart.sh && " + containerCommand, + } + } else { + containerCommands = []string{ + "sh", + "-c", + containerCommand, } } + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: podName, + Namespace: "default", + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "debug", + Image: image, + ImagePullPolicy: "IfNotPresent", + Command: containerCommands, + VolumeMounts: volumeMounts, + SecurityContext: &v1.SecurityContext{ + Privileged: &[]bool{true}[0], + }, + }, + }, + Volumes: volumes, + RestartPolicy: v1.RestartPolicyNever, + }, + } // Create the Pod fmt.Println("Creating Pod...") fmt.Printf("Creating Pod %q...\n", podName) result, err := clientset.CoreV1().Pods("default").Create(context.Background(), pod, metav1.CreateOptions{}) if err != nil { - return podName, err + return "", err } fmt.Printf("Created Pod %q.\n", result.GetObjectMeta().GetName()) @@ -496,10 +510,6 @@ func command_init() cli.App { WalkDirectory(dirPath) for _, config := range configs { if strings.Compare(config.Initial_ns_pid, pid) == 0 || pid == "" { - if prestartPath != "" && config.Image_name == "NULL" { - fmt.Println("Coredump is not generate in Pod.Prestart just use in Pod's coredump debug!") - return nil - } err := debug(config, command, prestartPath) if err != nil { fmt.Println(err) diff --git a/types/types.go b/types/types.go index c2e11f9..9d77f9e 100644 --- a/types/types.go +++ b/types/types.go @@ -27,6 +27,7 @@ type Coredump_config struct { Signal int Hostname string Storage string + Executable_file string } type Coredump_cli_table struct { PID string |
