From dfa75927cb65911dd0bb83e4136d7e91d7368602 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 2 Jul 2021 09:03:44 -0700 Subject: [PATCH 001/107] setup debug command scaffold --- cmd/src/debug.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 cmd/src/debug.go diff --git a/cmd/src/debug.go b/cmd/src/debug.go new file mode 100644 index 0000000000..a9a03d09ce --- /dev/null +++ b/cmd/src/debug.go @@ -0,0 +1,28 @@ +package main + +import ( + "flag" + "fmt" +) + +func init() { + flagSet := flag.NewFlagSet("debug", flag.ExitOnError) + usageFunc := func() { + fmt.Fprintf(flag.CommandLine.Output(), `'src debug' gathers and bundles debug data from a Sourcegraph deployment. + +USAGE + src [-v] debug +`) + } + + handler := func(args []string) error { + return flagSet.Parse(args) + } + // Register the command. + commands = append(commands, &command{ + aliases: []string{"debug-dump"}, + flagSet: flagSet, + handler: handler, + usageFunc: usageFunc, + }) +} From e729fa0291315d96acdc4a0bbb0c6647e697f969 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 2 Jul 2021 09:49:42 -0700 Subject: [PATCH 002/107] added test kubectl events logging --- cmd/src/debug.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index a9a03d09ce..5dd11f343a 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -3,6 +3,8 @@ package main import ( "flag" "fmt" + + "github.com/sourcegraph/src-cli/internal/exec" ) func init() { @@ -16,8 +18,19 @@ USAGE } handler := func(args []string) error { - return flagSet.Parse(args) + err := flagSet.Parse(args) + if err != nil { + return err + } + cmd := exec.Command("kubectl", "get", "events") + stdout, err := cmd.Output() + if err != nil { + return err + } + fmt.Print(string(stdout)) + return nil } + // Register the command. commands = append(commands, &command{ aliases: []string{"debug-dump"}, From eb9f057891cac151dd0f402e7a06d7dace2aba05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senart?= Date: Fri, 9 Jul 2021 17:52:18 +0200 Subject: [PATCH 003/107] debug: Create ZIP archive --- .gitignore | 4 +++- cmd/src/debug.go | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 5ba7905ce7..edb4ebb690 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -./src +src +cmd/src/src +cmd/src/*.zip release ./vendor .idea diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 5dd11f343a..04c46e1424 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -1,33 +1,61 @@ package main import ( + "archive/zip" "flag" "fmt" + "os" "github.com/sourcegraph/src-cli/internal/exec" ) func init() { flagSet := flag.NewFlagSet("debug", flag.ExitOnError) + usageFunc := func() { fmt.Fprintf(flag.CommandLine.Output(), `'src debug' gathers and bundles debug data from a Sourcegraph deployment. USAGE - src [-v] debug + src [-v] debug [-out=debug.zip] `) } + var ( + outFile = flagSet.String("out", "debug.zip", "The name of the output zip archive") + ) + handler := func(args []string) error { err := flagSet.Parse(args) if err != nil { return err } - cmd := exec.Command("kubectl", "get", "events") - stdout, err := cmd.Output() + + if *outFile == "" { + return fmt.Errorf("empty -out flag") + } + + out, err := os.OpenFile(*outFile, os.O_CREATE|os.O_RDWR, 0666) if err != nil { - return err + return fmt.Errorf("failed to open file: %w", err) + } + + defer out.Close() + zw := zip.NewWriter(out) + defer zw.Close() + + k8sEvents, err := zw.Create("k8s-events.txt") + if err != nil { + return fmt.Errorf("failed to create k8s-events.txt: %w", err) + } + + cmd := exec.Command("kubectl", "get", "events") + cmd.Stdout = k8sEvents + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + return fmt.Errorf("running kubectl get events failed: %w", err) } - fmt.Print(string(stdout)) + return nil } From b48f33282956889e72897214167fe73d71992543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senart?= Date: Fri, 9 Jul 2021 17:57:59 +0200 Subject: [PATCH 004/107] debug: Fail if zip file already exists --- cmd/src/debug.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 04c46e1424..9f06a8444d 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -34,7 +34,7 @@ USAGE return fmt.Errorf("empty -out flag") } - out, err := os.OpenFile(*outFile, os.O_CREATE|os.O_RDWR, 0666) + out, err := os.OpenFile(*outFile, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { return fmt.Errorf("failed to open file: %w", err) } From dabaacb84e4b7c3162e2101da1a9af5c19eea9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senart?= Date: Fri, 9 Jul 2021 18:12:35 +0200 Subject: [PATCH 005/107] debug: introduce directory structure in zip --- cmd/src/debug.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 9f06a8444d..45afb9bffd 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -39,11 +39,12 @@ USAGE return fmt.Errorf("failed to open file: %w", err) } + defer out.Close() zw := zip.NewWriter(out) defer zw.Close() - k8sEvents, err := zw.Create("k8s-events.txt") + k8sEvents, err := zw.Create("src-debug/kubectl/events.txt") if err != nil { return fmt.Errorf("failed to create k8s-events.txt: %w", err) } From 74a28c331270b5b0e16597bd5f47e1183019abd1 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 14 Jul 2021 00:32:02 -0700 Subject: [PATCH 006/107] added --all-naamespaces to get events command --- cmd/src/debug.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 45afb9bffd..285e5e48c8 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -39,7 +39,6 @@ USAGE return fmt.Errorf("failed to open file: %w", err) } - defer out.Close() zw := zip.NewWriter(out) defer zw.Close() @@ -49,7 +48,7 @@ USAGE return fmt.Errorf("failed to create k8s-events.txt: %w", err) } - cmd := exec.Command("kubectl", "get", "events") + cmd := exec.Command("kubectl", "get", "events", "--all-namespaces") cmd.Stdout = k8sEvents cmd.Stderr = os.Stderr From 77f06d2acfbf43d3aa3f26233d54fc446f7f9767 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 10 Aug 2021 01:19:12 -0700 Subject: [PATCH 007/107] populated with TODO tasks, add get pods output --- cmd/src/debug.go | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 285e5e48c8..dede85bc90 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -16,7 +16,7 @@ func init() { fmt.Fprintf(flag.CommandLine.Output(), `'src debug' gathers and bundles debug data from a Sourcegraph deployment. USAGE - src [-v] debug [-out=debug.zip] + src [-v] debug [-out=debug.zip] `) } @@ -34,6 +34,11 @@ USAGE return fmt.Errorf("empty -out flag") } + // TODO: ensures outFile ends in .zip + // if *outFile == !strings.HasSuffix(".zip") { + // return fmt.Errorf("-out flg must end in .zip") + // } + out, err := os.OpenFile(*outFile, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { return fmt.Errorf("failed to open file: %w", err) @@ -43,7 +48,8 @@ USAGE zw := zip.NewWriter(out) defer zw.Close() - k8sEvents, err := zw.Create("src-debug/kubectl/events.txt") + // TODO: make outFile the input from `-out=` flag stored in `outFile` + k8sEvents, err := zw.Create("outFile/kubectl/events.txt") if err != nil { return fmt.Errorf("failed to create k8s-events.txt: %w", err) } @@ -56,6 +62,26 @@ USAGE return fmt.Errorf("running kubectl get events failed: %w", err) } + // Store logs output in zip + k8sPods, err := zw.Create("outFile/kubectl/pods.txt") + if err != nil { + return fmt.Errorf("failed to create pods.txt: %w", err) + } + + // TODO process pods output into array of strings to run in loop as argument for writing as .txt in archive + // Get all pod names + zmd := exec.Command("kubectl", "get", "pods") + zmd.Stdout = k8sPods + zmd.Stderr = os.Stderr + fmt.Println(k8sPods) + + if err := zmd.Run(); err != nil { + return fmt.Errorf("running kubectl get pods failed: %w", err) + } + + // Sanity Check + fmt.Println("runnnnnnnnn") + return nil } From 746fce879e7a520b198f8c72cfea19c3d614ee72 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 10 Aug 2021 16:14:19 -0700 Subject: [PATCH 008/107] setting up k8s get pods to enable grabbing logs --- cmd/src/debug.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index dede85bc90..8e538d5a9c 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -2,6 +2,7 @@ package main import ( "archive/zip" + "bytes" "flag" "fmt" "os" @@ -48,7 +49,7 @@ USAGE zw := zip.NewWriter(out) defer zw.Close() - // TODO: make outFile the input from `-out=` flag stored in `outFile` + // TODO: make outFile the input from `-out=` flag stored in `outFile` but without the .zip k8sEvents, err := zw.Create("outFile/kubectl/events.txt") if err != nil { return fmt.Errorf("failed to create k8s-events.txt: %w", err) @@ -63,17 +64,19 @@ USAGE } // Store logs output in zip - k8sPods, err := zw.Create("outFile/kubectl/pods.txt") - if err != nil { - return fmt.Errorf("failed to create pods.txt: %w", err) - } + //k8sPods, err := zw.Create("outFile/kubectl/pods.txt") + //if err != nil { + // return fmt.Errorf("failed to create pods.txt: %w", err) + //} + + var k8sPods bytes.Buffer // TODO process pods output into array of strings to run in loop as argument for writing as .txt in archive // Get all pod names - zmd := exec.Command("kubectl", "get", "pods") - zmd.Stdout = k8sPods + zmd := exec.Command("kubectl", "get", "pods", "-o=json") + zmd.Stdout = &k8sPods zmd.Stderr = os.Stderr - fmt.Println(k8sPods) + // fmt.Printf("%T \n", k8sPods) if err := zmd.Run(); err != nil { return fmt.Errorf("running kubectl get pods failed: %w", err) @@ -81,6 +84,7 @@ USAGE // Sanity Check fmt.Println("runnnnnnnnn") + fmt.Printf("%s \n", k8sPods.String()) return nil } From 0dff03ba768f9eb05bc4359404510fe3f6cbb783 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 10 Aug 2021 21:38:09 -0700 Subject: [PATCH 009/107] got pod names parsed to slice --- cmd/src/debug.go | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 8e538d5a9c..ef34da504f 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -6,6 +6,7 @@ import ( "flag" "fmt" "os" + "strings" "github.com/sourcegraph/src-cli/internal/exec" ) @@ -69,22 +70,34 @@ USAGE // return fmt.Errorf("failed to create pods.txt: %w", err) //} - var k8sPods bytes.Buffer + var podsBuff bytes.Buffer // TODO process pods output into array of strings to run in loop as argument for writing as .txt in archive + // parse json output with json.decode to create slice of pod names // Get all pod names - zmd := exec.Command("kubectl", "get", "pods", "-o=json") - zmd.Stdout = &k8sPods - zmd.Stderr = os.Stderr - // fmt.Printf("%T \n", k8sPods) + getPods := exec.Command("kubectl", "get", "pods", "-o=jsonpath='{.items[*].metadata.name}'") + getPods.Stdout = &podsBuff + getPods.Stderr = os.Stderr - if err := zmd.Run(); err != nil { + if err := getPods.Run(); err != nil { return fmt.Errorf("running kubectl get pods failed: %w", err) } + pods := podsBuff.String() + podList := strings.Split(pods, " ") + + for i := range podList { + fmt.Println(i, podList[i]) + } + + //fmt.Printf("%T \n\n", podsBuff) + //fmt.Printf("%s \n\n", pods) + //fmt.Printf("%T \n\n", pods) + //fmt.Printf("%s \n\n", podList) + //fmt.Printf("%T \n\n", podList) + // Sanity Check - fmt.Println("runnnnnnnnn") - fmt.Printf("%s \n", k8sPods.String()) + fmt.Println(" zmd rannnnnnnnn") return nil } From b7c4625ec252efa7cf0fffea562029c1ed2ff037 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 12 Aug 2021 01:18:43 -0700 Subject: [PATCH 010/107] pulling logs from all pods, TODO: handle subcontainers --- cmd/src/debug.go | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index ef34da504f..a0f8569da9 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -50,32 +50,30 @@ USAGE zw := zip.NewWriter(out) defer zw.Close() - // TODO: make outFile the input from `-out=` flag stored in `outFile` but without the .zip + // TODO: make outFile the input from `-out=` flag stored in `outFile`, validate the .zip postpends `outFile` + //write events to archive k8sEvents, err := zw.Create("outFile/kubectl/events.txt") if err != nil { return fmt.Errorf("failed to create k8s-events.txt: %w", err) } + //define command to get events cmd := exec.Command("kubectl", "get", "events", "--all-namespaces") cmd.Stdout = k8sEvents cmd.Stderr = os.Stderr + //get events if err := cmd.Run(); err != nil { return fmt.Errorf("running kubectl get events failed: %w", err) } - // Store logs output in zip - //k8sPods, err := zw.Create("outFile/kubectl/pods.txt") - //if err != nil { - // return fmt.Errorf("failed to create pods.txt: %w", err) - //} - var podsBuff bytes.Buffer // TODO process pods output into array of strings to run in loop as argument for writing as .txt in archive // parse json output with json.decode to create slice of pod names // Get all pod names getPods := exec.Command("kubectl", "get", "pods", "-o=jsonpath='{.items[*].metadata.name}'") + //Output pointer to byte buffer getPods.Stdout = &podsBuff getPods.Stderr = os.Stderr @@ -83,13 +81,40 @@ USAGE return fmt.Errorf("running kubectl get pods failed: %w", err) } + //convert output to slice pods := podsBuff.String() podList := strings.Split(pods, " ") + //handle "'" in podList[0] and podList[len(podList) - 1) + podList[0] = strings.TrimLeft(podList[0], "'") + podList[len(podList)-1] = strings.TrimRight(podList[len(podList)-1], "'") + //fmt.Println("right: ", podList[len(podList)-1], "left: ", podList[0]) + // TODO: fix pods with sub containers + // exec kubectl get logs and write to archive for i := range podList { - fmt.Println(i, podList[i]) + fmt.Println(podList[i]) + podLogs, err := zw.Create("outFile/logs/" + podList[i]) + if err != nil { + return fmt.Errorf("failed to create podLogs.txt: %w", err) + } + + getLogs := exec.Command("kubectl", "logs", podList[i]) + getLogs.Stdout = podLogs + getLogs.Stderr = os.Stderr + + if err := getLogs.Run(); err != nil { + return fmt.Errorf("running kubectl get logs failed: %w", err) + } } + // Store logs output in zip + //k8sPods, err := zw.Create("outFile/kubectl/pods.txt") + //if err != nil { + // return fmt.Errorf("failed to create pods.txt: %w", err) + //} + + //fmt.Println(len(podList)) + //fmt.Println(podList[0]) //fmt.Printf("%T \n\n", podsBuff) //fmt.Printf("%s \n\n", pods) //fmt.Printf("%T \n\n", pods) @@ -97,7 +122,7 @@ USAGE //fmt.Printf("%T \n\n", podList) // Sanity Check - fmt.Println(" zmd rannnnnnnnn") + //fmt.Println(" zmd rannnnnnnnn") return nil } From d4821a0925fafb17eacf26bd0f4192eb3bea0a0c Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 12 Aug 2021 13:46:02 -0700 Subject: [PATCH 011/107] add missing .txt string to log archive names --- cmd/src/debug.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index a0f8569da9..3263ef06f2 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -93,7 +93,7 @@ USAGE // exec kubectl get logs and write to archive for i := range podList { fmt.Println(podList[i]) - podLogs, err := zw.Create("outFile/logs/" + podList[i]) + podLogs, err := zw.Create("outFile/logs/" + podList[i] + ".txt") if err != nil { return fmt.Errorf("failed to create podLogs.txt: %w", err) } @@ -103,6 +103,7 @@ USAGE getLogs.Stderr = os.Stderr if err := getLogs.Run(); err != nil { + return fmt.Errorf("running kubectl get logs failed: %w", err) } } From 3de8d878c4617cb39e04d3ca131136ddd58f34e2 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 13 Aug 2021 16:25:36 -0700 Subject: [PATCH 012/107] used json get pods out, refactored k8s logs into their own spot --- cmd/src/debug.go | 104 +++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 3263ef06f2..729e9a5c63 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -3,10 +3,10 @@ package main import ( "archive/zip" "bytes" + "encoding/json" "flag" "fmt" "os" - "strings" "github.com/sourcegraph/src-cli/internal/exec" ) @@ -67,72 +67,70 @@ USAGE return fmt.Errorf("running kubectl get events failed: %w", err) } - var podsBuff bytes.Buffer + return savek8sLogs(zw) + } - // TODO process pods output into array of strings to run in loop as argument for writing as .txt in archive - // parse json output with json.decode to create slice of pod names - // Get all pod names - getPods := exec.Command("kubectl", "get", "pods", "-o=jsonpath='{.items[*].metadata.name}'") - //Output pointer to byte buffer - getPods.Stdout = &podsBuff - getPods.Stderr = os.Stderr + // Register the command. + commands = append(commands, &command{ + aliases: []string{"debug-dump"}, + flagSet: flagSet, + handler: handler, + usageFunc: usageFunc, + }) +} + +func savek8sLogs(zw *zip.Writer) error { + var podsBuff bytes.Buffer - if err := getPods.Run(); err != nil { - return fmt.Errorf("running kubectl get pods failed: %w", err) + // TODO process pods output into array of strings to run in loop as argument for writing as .txt in archive + // parse json output with json.decode to create slice of pod names + // Get all pod names + getPods := exec.Command("kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") + //Output pointer to byte buffer + getPods.Stdout = &podsBuff + getPods.Stderr = os.Stderr + + if err := getPods.Run(); err != nil { + return fmt.Errorf("running kubectl get pods failed: %w", err) + } + + var podList struct { + Items []struct { + Metadata struct { + Name string + } + Spec struct { + Containers []struct { + Name string + } + } } + } + + err := json.NewDecoder(&podsBuff).Decode(&podList) + if err != nil { + return fmt.Errorf("failed to unmarshall pods json: %w", err) + } - //convert output to slice - pods := podsBuff.String() - podList := strings.Split(pods, " ") - //handle "'" in podList[0] and podList[len(podList) - 1) - podList[0] = strings.TrimLeft(podList[0], "'") - podList[len(podList)-1] = strings.TrimRight(podList[len(podList)-1], "'") - //fmt.Println("right: ", podList[len(podList)-1], "left: ", podList[0]) - - // TODO: fix pods with sub containers - // exec kubectl get logs and write to archive - for i := range podList { - fmt.Println(podList[i]) - podLogs, err := zw.Create("outFile/logs/" + podList[i] + ".txt") + // TODO: fix pods with sub containers + // exec kubectl get logs and write to archive + for _, pod := range podList.Items { + fmt.Printf("%+v\n", pod) + for _, container := range pod.Spec.Containers { + logs, err := zw.Create("outFile/logs/" + pod.Metadata.Name + "/" + container.Name + ".txt") if err != nil { return fmt.Errorf("failed to create podLogs.txt: %w", err) } - getLogs := exec.Command("kubectl", "logs", podList[i]) - getLogs.Stdout = podLogs + getLogs := exec.Command("kubectl", "logs", pod.Metadata.Name, "-c", container.Name) + getLogs.Stdout = logs getLogs.Stderr = os.Stderr if err := getLogs.Run(); err != nil { - return fmt.Errorf("running kubectl get logs failed: %w", err) } } - - // Store logs output in zip - //k8sPods, err := zw.Create("outFile/kubectl/pods.txt") - //if err != nil { - // return fmt.Errorf("failed to create pods.txt: %w", err) - //} - - //fmt.Println(len(podList)) - //fmt.Println(podList[0]) - //fmt.Printf("%T \n\n", podsBuff) - //fmt.Printf("%s \n\n", pods) - //fmt.Printf("%T \n\n", pods) - //fmt.Printf("%s \n\n", podList) - //fmt.Printf("%T \n\n", podList) - - // Sanity Check - //fmt.Println(" zmd rannnnnnnnn") - - return nil } - // Register the command. - commands = append(commands, &command{ - aliases: []string{"debug-dump"}, - flagSet: flagSet, - handler: handler, - usageFunc: usageFunc, - }) + return nil } From 53932e4e1dd82124382c5f656b2434a588136f7d Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 17 Aug 2021 23:58:56 -0700 Subject: [PATCH 013/107] refactor get logs into savek8sLogs --- cmd/src/debug.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 729e9a5c63..200a3f4257 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -82,18 +82,18 @@ USAGE func savek8sLogs(zw *zip.Writer) error { var podsBuff bytes.Buffer - // TODO process pods output into array of strings to run in loop as argument for writing as .txt in archive - // parse json output with json.decode to create slice of pod names - // Get all pod names + // Get all pod names as json getPods := exec.Command("kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") //Output pointer to byte buffer getPods.Stdout = &podsBuff getPods.Stderr = os.Stderr + // Run getPods if err := getPods.Run(); err != nil { return fmt.Errorf("running kubectl get pods failed: %w", err) } + //Declare struct to format decode from podList var podList struct { Items []struct { Metadata struct { @@ -107,17 +107,17 @@ func savek8sLogs(zw *zip.Writer) error { } } + //Decode json from podList err := json.NewDecoder(&podsBuff).Decode(&podList) if err != nil { return fmt.Errorf("failed to unmarshall pods json: %w", err) } - // TODO: fix pods with sub containers - // exec kubectl get logs and write to archive + // exec kubectl get logs and write to archive, accounts for containers in pod for _, pod := range podList.Items { fmt.Printf("%+v\n", pod) for _, container := range pod.Spec.Containers { - logs, err := zw.Create("outFile/logs/" + pod.Metadata.Name + "/" + container.Name + ".txt") + logs, err := zw.Create("outFile/kubectl/logs/" + pod.Metadata.Name + "/" + container.Name + ".txt") if err != nil { return fmt.Errorf("failed to create podLogs.txt: %w", err) } From fd4ad22b09b6d9955f50e4666e6702ffb25ec862 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 19 Aug 2021 16:59:38 -0700 Subject: [PATCH 014/107] working on logs for previous pods, need to only write when command returns without error --- cmd/src/debug.go | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 200a3f4257..8f071a5842 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -11,6 +11,7 @@ import ( "github.com/sourcegraph/src-cli/internal/exec" ) +// Init debug flag on src build func init() { flagSet := flag.NewFlagSet("debug", flag.ExitOnError) @@ -22,6 +23,7 @@ USAGE `) } + // store value passed to out flag var ( outFile = flagSet.String("out", "debug.zip", "The name of the output zip archive") ) @@ -36,11 +38,6 @@ USAGE return fmt.Errorf("empty -out flag") } - // TODO: ensures outFile ends in .zip - // if *outFile == !strings.HasSuffix(".zip") { - // return fmt.Errorf("-out flg must end in .zip") - // } - out, err := os.OpenFile(*outFile, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { return fmt.Errorf("failed to open file: %w", err) @@ -115,7 +112,7 @@ func savek8sLogs(zw *zip.Writer) error { // exec kubectl get logs and write to archive, accounts for containers in pod for _, pod := range podList.Items { - fmt.Printf("%+v\n", pod) + fmt.Println(pod.Metadata.Name, "containers:", pod.Spec.Containers) for _, container := range pod.Spec.Containers { logs, err := zw.Create("outFile/kubectl/logs/" + pod.Metadata.Name + "/" + container.Name + ".txt") if err != nil { @@ -132,5 +129,27 @@ func savek8sLogs(zw *zip.Writer) error { } } + // TODO: dont write a prev-container.txt if kubectl logs --previous returns no prev pod + for _, pod := range podList.Items { + fmt.Println(pod.Metadata.Name, "containers:", pod.Spec.Containers) + for _, container := range pod.Spec.Containers { + prevLogs, err := zw.Create("outFile/kubectl/logs/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".txt") + if err != nil { + return fmt.Errorf("failed to create podLogs.txt: %w", err) + } + + getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) + getPrevLogs.Stderr = os.Stderr + getPrevLogs.Stdout = prevLogs + + if err := getPrevLogs.Run(); err != nil { + fmt.Errorf("running kubectl get logs failed: %w", err) + // continue + } else { + fmt.Println("\nTHERE WAS A PREV!!!!") + } + } + } + return nil } From 9415d560ee222a20c4bfc57c9196610b5e8d6d36 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 19 Aug 2021 23:23:18 -0700 Subject: [PATCH 015/107] archives prev-logs if exists --- cmd/src/debug.go | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 8f071a5842..898c28ad23 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -110,9 +110,9 @@ func savek8sLogs(zw *zip.Writer) error { return fmt.Errorf("failed to unmarshall pods json: %w", err) } - // exec kubectl get logs and write to archive, accounts for containers in pod + // run kubectl logs and write to archive, accounts for containers in pod for _, pod := range podList.Items { - fmt.Println(pod.Metadata.Name, "containers:", pod.Spec.Containers) + fmt.Println("Archiving logs: ", pod.Metadata.Name, "Containers:", pod.Spec.Containers) for _, container := range pod.Spec.Containers { logs, err := zw.Create("outFile/kubectl/logs/" + pod.Metadata.Name + "/" + container.Name + ".txt") if err != nil { @@ -129,24 +129,17 @@ func savek8sLogs(zw *zip.Writer) error { } } - // TODO: dont write a prev-container.txt if kubectl logs --previous returns no prev pod + // run kubectl logs --previous and write to archive if return not err for _, pod := range podList.Items { - fmt.Println(pod.Metadata.Name, "containers:", pod.Spec.Containers) for _, container := range pod.Spec.Containers { - prevLogs, err := zw.Create("outFile/kubectl/logs/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".txt") - if err != nil { - return fmt.Errorf("failed to create podLogs.txt: %w", err) - } - getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) - getPrevLogs.Stderr = os.Stderr - getPrevLogs.Stdout = prevLogs - - if err := getPrevLogs.Run(); err != nil { - fmt.Errorf("running kubectl get logs failed: %w", err) - // continue - } else { - fmt.Println("\nTHERE WAS A PREV!!!!") + if err := getPrevLogs.Run(); err == nil { + fmt.Println("Archiving previous logs: ", pod.Metadata.Name, "Containers: ", pod.Spec.Containers) + prev, err := zw.Create("outFile/kubectl/logs/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".txt") + getPrevLogs.Stdout = prev + if err != nil { + return fmt.Errorf("failed to create podLogs.txt: %w", err) + } } } } From c216923a98025fc950c2e54d1b8bec986974d22a Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Sat, 21 Aug 2021 23:07:10 -0700 Subject: [PATCH 016/107] refactoring getPods to handler scope --- cmd/src/debug.go | 119 ++++++++++++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 43 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 898c28ad23..6de2c4b13c 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -11,6 +11,20 @@ import ( "github.com/sourcegraph/src-cli/internal/exec" ) +// package level +type podList struct { + Items []struct { + Metadata struct { + Name string + } + Spec struct { + Containers []struct { + Name string + } + } + } +} + // Init debug flag on src build func init() { flagSet := flag.NewFlagSet("debug", flag.ExitOnError) @@ -48,23 +62,32 @@ USAGE defer zw.Close() // TODO: make outFile the input from `-out=` flag stored in `outFile`, validate the .zip postpends `outFile` - //write events to archive - k8sEvents, err := zw.Create("outFile/kubectl/events.txt") - if err != nil { - return fmt.Errorf("failed to create k8s-events.txt: %w", err) + // Declare buffer type var for kubectl pipe + var podsBuff bytes.Buffer + + // Get all pod names as json + getPods := exec.Command("kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") + //Output pointer to byte buffer + getPods.Stdout = &podsBuff + getPods.Stderr = os.Stderr + + // Run getPods + if err := getPods.Run(); err != nil { + return fmt.Errorf("running kubectl get pods failed: %w", err) } - //define command to get events - cmd := exec.Command("kubectl", "get", "events", "--all-namespaces") - cmd.Stdout = k8sEvents - cmd.Stderr = os.Stderr + //Declare struct to format decode from podList + var pods podList - //get events - if err := cmd.Run(); err != nil { - return fmt.Errorf("running kubectl get events failed: %w", err) + //Decode json from podList + if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { + return fmt.Errorf("failed to unmarshall pods json: %w", err) } + fmt.Println(pods) - return savek8sLogs(zw) + archiveEvents(zw) + archiveLogs(zw, pods) + return nil } // Register the command. @@ -76,42 +99,52 @@ USAGE }) } -func savek8sLogs(zw *zip.Writer) error { - var podsBuff bytes.Buffer - - // Get all pod names as json - getPods := exec.Command("kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") - //Output pointer to byte buffer - getPods.Stdout = &podsBuff - getPods.Stderr = os.Stderr - - // Run getPods - if err := getPods.Run(); err != nil { - return fmt.Errorf("running kubectl get pods failed: %w", err) +//func getPods() error { +// // Declare buffer type var for kubectl pipe +// var podsBuff bytes.Buffer +// +// // Get all pod names as json +// getPods := exec.Command("kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") +// //Output pointer to byte buffer +// getPods.Stdout = &podsBuff +// getPods.Stderr = os.Stderr +// +// // Run getPods +// if err := getPods.Run(); err != nil { +// return fmt.Errorf("running kubectl get pods failed: %w", err) +// } +// +// //Decode json from podList +// err := json.NewDecoder(&podsBuff).Decode(&podList) +// if err != nil { +// return fmt.Errorf("failed to unmarshall pods json: %w", err) +// } +// return podList +//} + +func archiveEvents(zw *zip.Writer) error { + //write events to archive + k8sEvents, err := zw.Create("outFile/kubectl/events.txt") + if err != nil { + return fmt.Errorf("failed to create k8s-events.txt: %w", err) } - //Declare struct to format decode from podList - var podList struct { - Items []struct { - Metadata struct { - Name string - } - Spec struct { - Containers []struct { - Name string - } - } - } - } + //define command to get events + getEvents := exec.Command("kubectl", "get", "events", "--all-namespaces") + getEvents.Stdout = k8sEvents + getEvents.Stderr = os.Stderr - //Decode json from podList - err := json.NewDecoder(&podsBuff).Decode(&podList) - if err != nil { - return fmt.Errorf("failed to unmarshall pods json: %w", err) + //get events + if err := getEvents.Run(); err != nil { + return fmt.Errorf("running kubectl get events failed: %w", err) } + return nil +} + +func archiveLogs(zw *zip.Writer, pods podList) error { // run kubectl logs and write to archive, accounts for containers in pod - for _, pod := range podList.Items { + for _, pod := range pods.Items { fmt.Println("Archiving logs: ", pod.Metadata.Name, "Containers:", pod.Spec.Containers) for _, container := range pod.Spec.Containers { logs, err := zw.Create("outFile/kubectl/logs/" + pod.Metadata.Name + "/" + container.Name + ".txt") @@ -130,7 +163,7 @@ func savek8sLogs(zw *zip.Writer) error { } // run kubectl logs --previous and write to archive if return not err - for _, pod := range podList.Items { + for _, pod := range pods.Items { for _, container := range pod.Spec.Containers { getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) if err := getPrevLogs.Run(); err == nil { From e392fbb57b23f436cd65c1e9767dfd463b366b5b Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Sat, 21 Aug 2021 23:58:08 -0700 Subject: [PATCH 017/107] refactored all kubectl call functions to be declared outside of handler --- cmd/src/debug.go | 67 ++++++++++++++++-------------------------------- 1 file changed, 22 insertions(+), 45 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 6de2c4b13c..3875395402 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -61,29 +61,10 @@ USAGE zw := zip.NewWriter(out) defer zw.Close() - // TODO: make outFile the input from `-out=` flag stored in `outFile`, validate the .zip postpends `outFile` - // Declare buffer type var for kubectl pipe - var podsBuff bytes.Buffer - - // Get all pod names as json - getPods := exec.Command("kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") - //Output pointer to byte buffer - getPods.Stdout = &podsBuff - getPods.Stderr = os.Stderr - - // Run getPods - if err := getPods.Run(); err != nil { - return fmt.Errorf("running kubectl get pods failed: %w", err) - } - - //Declare struct to format decode from podList - var pods podList - - //Decode json from podList - if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { - return fmt.Errorf("failed to unmarshall pods json: %w", err) + pods, err := getPods() + if err != nil { + return fmt.Errorf("failed to get pods: %w", err) } - fmt.Println(pods) archiveEvents(zw) archiveLogs(zw, pods) @@ -99,29 +80,26 @@ USAGE }) } -//func getPods() error { -// // Declare buffer type var for kubectl pipe -// var podsBuff bytes.Buffer -// -// // Get all pod names as json -// getPods := exec.Command("kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") -// //Output pointer to byte buffer -// getPods.Stdout = &podsBuff -// getPods.Stderr = os.Stderr -// -// // Run getPods -// if err := getPods.Run(); err != nil { -// return fmt.Errorf("running kubectl get pods failed: %w", err) -// } -// -// //Decode json from podList -// err := json.NewDecoder(&podsBuff).Decode(&podList) -// if err != nil { -// return fmt.Errorf("failed to unmarshall pods json: %w", err) -// } -// return podList -//} +// TODO: make outFile the input from `-out=` flag stored in `outFile`, validate the .zip postpends `outFile` +func getPods() (podList, error) { + // Declare buffer type var for kubectl pipe + var podsBuff bytes.Buffer + + // Get all pod names as json + getPods := exec.Command("kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") + getPods.Stdout = &podsBuff + getPods.Stderr = os.Stderr + err := getPods.Run() + //Declare struct to format decode from podList + var pods podList + + //Decode json from podList + err = json.NewDecoder(&podsBuff).Decode(&pods) + + fmt.Println(pods) + return pods, err +} func archiveEvents(zw *zip.Writer) error { //write events to archive k8sEvents, err := zw.Create("outFile/kubectl/events.txt") @@ -140,7 +118,6 @@ func archiveEvents(zw *zip.Writer) error { } return nil } - func archiveLogs(zw *zip.Writer, pods podList) error { // run kubectl logs and write to archive, accounts for containers in pod From 9ef80364767d4caa14e7499ed10b7f6e5071a755 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Sun, 22 Aug 2021 01:15:43 -0700 Subject: [PATCH 018/107] added pod manifests and describes --- cmd/src/debug.go | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 3875395402..177d1f7fc8 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -68,6 +68,8 @@ USAGE archiveEvents(zw) archiveLogs(zw, pods) + archiveDescribes(zw, pods) + archiveManifests(zw, pods) return nil } @@ -81,6 +83,9 @@ USAGE } // TODO: make outFile the input from `-out=` flag stored in `outFile`, validate the .zip postpends `outFile` +// TODO: improve logging as kubectl calls run (Desc, Mani) +// TODO: refactor dir structure to be by pod +// TODO: improve error handling func getPods() (podList, error) { // Declare buffer type var for kubectl pipe var podsBuff bytes.Buffer @@ -156,3 +161,37 @@ func archiveLogs(zw *zip.Writer, pods podList) error { return nil } +func archiveDescribes(zw *zip.Writer, pods podList) error { + for _, pod := range pods.Items { + describes, err := zw.Create("outFile/kubectl/describe/" + pod.Metadata.Name + ".txt") + if err != nil { + return fmt.Errorf("failed to create podLogs.txt: %w", err) + } + + describePod := exec.Command("kubectl", "describe", "pod", pod.Metadata.Name) + describePod.Stdout = describes + describePod.Stderr = os.Stderr + + if err := describePod.Run(); err != nil { + return fmt.Errorf("failer to run describe pod: %w", err) + } + } + return nil +} +func archiveManifests(zw *zip.Writer, pods podList) error { + for _, pod := range pods.Items { + manifests, err := zw.Create("outFile/kubectl/manifest/" + pod.Metadata.Name + ".yaml") + if err != nil { + return fmt.Errorf("failed to create manifest.yaml: %w", err) + } + + getManifest := exec.Command("kubectl", "get", "pod", pod.Metadata.Name, "-o", "yaml") + getManifest.Stdout = manifests + getManifest.Stderr = os.Stderr + + if err := getManifest.Run(); err != nil { + fmt.Errorf("failed to get pod yaml: %w", err) + } + } + return nil +} From ae4c2409367446b532d2a1e6b1daca9274a31d2c Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Sun, 22 Aug 2021 01:33:45 -0700 Subject: [PATCH 019/107] added some more TODOs --- cmd/src/debug.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 177d1f7fc8..b67265340c 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -11,7 +11,6 @@ import ( "github.com/sourcegraph/src-cli/internal/exec" ) -// package level type podList struct { Items []struct { Metadata struct { @@ -82,10 +81,11 @@ USAGE }) } -// TODO: make outFile the input from `-out=` flag stored in `outFile`, validate the .zip postpends `outFile` +// TODO: make outFile the input from `-out=` flag stored in `outFile`, validate that .zip postpends `outFile` // TODO: improve logging as kubectl calls run (Desc, Mani) -// TODO: refactor dir structure to be by pod +// TODO: refactor dir structure to be by pod, change logs to .log filetype // TODO: improve error handling +// TODO: refactor archiveLLogs so that both logs and logs --past are collected in the same loop func getPods() (podList, error) { // Declare buffer type var for kubectl pipe var podsBuff bytes.Buffer @@ -105,6 +105,7 @@ func getPods() (podList, error) { fmt.Println(pods) return pods, err } + func archiveEvents(zw *zip.Writer) error { //write events to archive k8sEvents, err := zw.Create("outFile/kubectl/events.txt") @@ -123,6 +124,8 @@ func archiveEvents(zw *zip.Writer) error { } return nil } + +// gets current pod logs and logs from past containers func archiveLogs(zw *zip.Writer, pods podList) error { // run kubectl logs and write to archive, accounts for containers in pod @@ -161,6 +164,7 @@ func archiveLogs(zw *zip.Writer, pods podList) error { return nil } + func archiveDescribes(zw *zip.Writer, pods podList) error { for _, pod := range pods.Items { describes, err := zw.Create("outFile/kubectl/describe/" + pod.Metadata.Name + ".txt") @@ -178,6 +182,7 @@ func archiveDescribes(zw *zip.Writer, pods podList) error { } return nil } + func archiveManifests(zw *zip.Writer, pods podList) error { for _, pod := range pods.Items { manifests, err := zw.Create("outFile/kubectl/manifest/" + pod.Metadata.Name + ".yaml") From 9d09cb2ce11af127a7a652dae7f2dd24c11ebbd8 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Sun, 22 Aug 2021 21:22:40 -0700 Subject: [PATCH 020/107] added a little error handling on archives --- cmd/src/debug.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index b67265340c..62e47dcc20 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -65,10 +65,22 @@ USAGE return fmt.Errorf("failed to get pods: %w", err) } - archiveEvents(zw) - archiveLogs(zw, pods) - archiveDescribes(zw, pods) - archiveManifests(zw, pods) + err = archiveEvents(zw) + if err != nil { + return fmt.Errorf("running archiveEvents failed: %w", err) + } + err = archiveLogs(zw, pods) + if err != nil { + return fmt.Errorf("running archiveLogs failed: %w", err) + } + err = archiveDescribes(zw, pods) + if err != nil { + return fmt.Errorf("running archiveDescribes failed: %w", err) + } + err = archiveManifests(zw, pods) + if err != nil { + return fmt.Errorf("running archiveManifests failed: %w", err) + } return nil } From 247d0a3000cb429d9dbf6b66aa619088e5e78be8 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 23 Aug 2021 23:32:01 -0700 Subject: [PATCH 021/107] corrected some error handling --- cmd/src/debug.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 62e47dcc20..d9e59233bf 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -42,8 +42,7 @@ USAGE ) handler := func(args []string) error { - err := flagSet.Parse(args) - if err != nil { + if err := flagSet.Parse(args); err != nil { return err } @@ -65,20 +64,18 @@ USAGE return fmt.Errorf("failed to get pods: %w", err) } - err = archiveEvents(zw) - if err != nil { + // TODO error group, create function type and run as goroutines + // Runs all kubectl based functions + if err := archiveEvents(zw); err != nil { return fmt.Errorf("running archiveEvents failed: %w", err) } - err = archiveLogs(zw, pods) - if err != nil { + if err := archiveLogs(zw, pods); err != nil { return fmt.Errorf("running archiveLogs failed: %w", err) } - err = archiveDescribes(zw, pods) - if err != nil { + if err := archiveDescribes(zw, pods); err != nil { return fmt.Errorf("running archiveDescribes failed: %w", err) } - err = archiveManifests(zw, pods) - if err != nil { + if err := archiveManifests(zw, pods); err != nil { return fmt.Errorf("running archiveManifests failed: %w", err) } return nil @@ -98,6 +95,7 @@ USAGE // TODO: refactor dir structure to be by pod, change logs to .log filetype // TODO: improve error handling // TODO: refactor archiveLLogs so that both logs and logs --past are collected in the same loop + func getPods() (podList, error) { // Declare buffer type var for kubectl pipe var podsBuff bytes.Buffer @@ -112,7 +110,9 @@ func getPods() (podList, error) { var pods podList //Decode json from podList - err = json.NewDecoder(&podsBuff).Decode(&pods) + if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { + fmt.Errorf("feailed to unmarshall get pods json: %w", err) + } fmt.Println(pods) return pods, err @@ -134,6 +134,7 @@ func archiveEvents(zw *zip.Writer) error { if err := getEvents.Run(); err != nil { return fmt.Errorf("running kubectl get events failed: %w", err) } + return nil } From 8115b72c3eb9569997d4004ea5efdd856f94b8b4 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 24 Aug 2021 00:18:36 -0700 Subject: [PATCH 022/107] added validation on out flag, and setup for deployment flag --- cmd/src/debug.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index d9e59233bf..fad138accb 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -7,6 +7,7 @@ import ( "flag" "fmt" "os" + "strings" "github.com/sourcegraph/src-cli/internal/exec" ) @@ -29,6 +30,7 @@ func init() { flagSet := flag.NewFlagSet("debug", flag.ExitOnError) usageFunc := func() { + fmt.Fprintf(flag.CommandLine.Output(), `'src debug' gathers and bundles debug data from a Sourcegraph deployment. USAGE @@ -38,7 +40,9 @@ USAGE // store value passed to out flag var ( - outFile = flagSet.String("out", "debug.zip", "The name of the output zip archive") + //TODO add deployment type selector + deployment = flagSet.String("d", "", "deployment type") + outfile = flagSet.String("out", "debug.zip", "The name of the output zip archive") ) handler := func(args []string) error { @@ -46,15 +50,25 @@ USAGE return err } - if *outFile == "" { + //validate out flag + if *outfile == "" { return fmt.Errorf("empty -out flag") } + if strings.HasSuffix(*outfile, ".zip") != true { + *outfile = *outfile + ".zip" + } + // handle deployment flag + if *deployment == "" { + return fmt.Errorf("must declare -d=") + } - out, err := os.OpenFile(*outFile, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) + // open pipe to output file + out, err := os.OpenFile(*outfile, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { return fmt.Errorf("failed to open file: %w", err) } + // open zip writer defer out.Close() zw := zip.NewWriter(out) defer zw.Close() From 3631b8a2fc755339aa93adcefeda0acbe56103ea Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 24 Aug 2021 23:45:34 -0700 Subject: [PATCH 023/107] improved logic for deployment flag --- cmd/src/debug.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index fad138accb..d066009abd 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -34,11 +34,11 @@ func init() { fmt.Fprintf(flag.CommandLine.Output(), `'src debug' gathers and bundles debug data from a Sourcegraph deployment. USAGE - src [-v] debug [-out=debug.zip] + src [-v] debug -d= [-out=debug.zip] `) } - // store value passed to out flag + // store value passed to flags var ( //TODO add deployment type selector deployment = flagSet.String("d", "", "deployment type") @@ -58,10 +58,22 @@ USAGE *outfile = *outfile + ".zip" } // handle deployment flag - if *deployment == "" { - return fmt.Errorf("must declare -d=") + if !((*deployment == "server") || (*deployment == "compose") || (*deployment == "kubernetes")) { + return fmt.Errorf("must declare -d=, as server, compose, or kubernetes") } + // handle deployment flag + //switch *deployment { + //case "server": + // fmt.Println("its a single container") + //case "compose": + // fmt.Println("its a docker-compose instance") + //case "kubernetes": + // fmt.Println("its a kubernetes deployment") + //default: + // return fmt.Errorf("must declare -d=, as server, compose, or kubernetes") + //} + // open pipe to output file out, err := os.OpenFile(*outfile, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { From 5db3a39bb3bb27cb2678c70244c2d9c2f589a445 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 24 Aug 2021 23:51:23 -0700 Subject: [PATCH 024/107] refactored deployment script --- cmd/src/debug.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index d066009abd..15b3fd9ebc 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -62,18 +62,6 @@ USAGE return fmt.Errorf("must declare -d=, as server, compose, or kubernetes") } - // handle deployment flag - //switch *deployment { - //case "server": - // fmt.Println("its a single container") - //case "compose": - // fmt.Println("its a docker-compose instance") - //case "kubernetes": - // fmt.Println("its a kubernetes deployment") - //default: - // return fmt.Errorf("must declare -d=, as server, compose, or kubernetes") - //} - // open pipe to output file out, err := os.OpenFile(*outfile, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { @@ -85,6 +73,18 @@ USAGE zw := zip.NewWriter(out) defer zw.Close() + // TODO write functions for sourcegraph server and docker-compose instances + //switch *deployment { + //case "server": + // fmt.Println("its a single container") + //case "compose": + // fmt.Println("its a docker-compose instance") + //case "kubernetes": + // fmt.Println("its a kubernetes deployment") + //default: + // return fmt.Errorf("must declare -d=, as server, compose, or kubernetes") + //} + pods, err := getPods() if err != nil { return fmt.Errorf("failed to get pods: %w", err) From dd52bf3457877fe8b295be2f8176ba0f67a86703 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 25 Aug 2021 23:26:07 -0700 Subject: [PATCH 025/107] added get PV and PVC, used out flag as baseDir for archive filestructure --- cmd/src/debug.go | 89 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 18 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 15b3fd9ebc..2d4fb1ffe7 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -42,7 +42,7 @@ USAGE var ( //TODO add deployment type selector deployment = flagSet.String("d", "", "deployment type") - outfile = flagSet.String("out", "debug.zip", "The name of the output zip archive") + base = flagSet.String("out", "debug.zip", "The name of the output zip archive") ) handler := func(args []string) error { @@ -51,11 +51,16 @@ USAGE } //validate out flag - if *outfile == "" { + if *base == "" { return fmt.Errorf("empty -out flag") } - if strings.HasSuffix(*outfile, ".zip") != true { - *outfile = *outfile + ".zip" + // declare basedir for archive file structure + var baseDir string + if strings.HasSuffix(*base, ".zip") == false { + baseDir = *base + *base = *base + ".zip" + } else { + baseDir = strings.TrimSuffix(*base, ".zip") } // handle deployment flag if !((*deployment == "server") || (*deployment == "compose") || (*deployment == "kubernetes")) { @@ -63,7 +68,7 @@ USAGE } // open pipe to output file - out, err := os.OpenFile(*outfile, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) + out, err := os.OpenFile(*base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { return fmt.Errorf("failed to open file: %w", err) } @@ -92,16 +97,22 @@ USAGE // TODO error group, create function type and run as goroutines // Runs all kubectl based functions - if err := archiveEvents(zw); err != nil { + if err := archiveEvents(zw, baseDir); err != nil { return fmt.Errorf("running archiveEvents failed: %w", err) } - if err := archiveLogs(zw, pods); err != nil { + if err := archivePV(zw, baseDir); err != nil { + return fmt.Errorf("running archivePV failed: %w", err) + } + if err := archivePVC(zw, baseDir); err != nil { + return fmt.Errorf("running archivePV failed: %w", err) + } + if err := archiveLogs(zw, pods, baseDir); err != nil { return fmt.Errorf("running archiveLogs failed: %w", err) } - if err := archiveDescribes(zw, pods); err != nil { + if err := archiveDescribes(zw, pods, baseDir); err != nil { return fmt.Errorf("running archiveDescribes failed: %w", err) } - if err := archiveManifests(zw, pods); err != nil { + if err := archiveManifests(zw, pods, baseDir); err != nil { return fmt.Errorf("running archiveManifests failed: %w", err) } return nil @@ -144,9 +155,9 @@ func getPods() (podList, error) { return pods, err } -func archiveEvents(zw *zip.Writer) error { +func archiveEvents(zw *zip.Writer, baseDir string) error { //write events to archive - k8sEvents, err := zw.Create("outFile/kubectl/events.txt") + k8sEvents, err := zw.Create(baseDir + "/kubectl/events.txt") if err != nil { return fmt.Errorf("failed to create k8s-events.txt: %w", err) } @@ -164,14 +175,56 @@ func archiveEvents(zw *zip.Writer) error { return nil } +func archivePV(zw *zip.Writer, baseDir string) error { + fmt.Println("Archiving persistent volumes") + //write persistent volumes to archive + PV, err := zw.Create(baseDir + "/kubectl/persistent-volumes.txt") + if err != nil { + return fmt.Errorf("failed to create k8s-events.txt: %w", err) + } + + //define command to get persistent volumes + getPV := exec.Command("kubectl", "get", "pv") + getPV.Stdout = PV + getPV.Stderr = os.Stderr + + //get persistent volumes + if err := getPV.Run(); err != nil { + return fmt.Errorf("running kubectl get pv failed: %w", err) + } + + return nil +} + +func archivePVC(zw *zip.Writer, baseDir string) error { + fmt.Println("Archiving persistent volume claims") + //write persistent volume claims to archive + PVC, err := zw.Create(baseDir + "/kubectl/persistent-volume-claims.txt") + if err != nil { + return fmt.Errorf("failed to create k8s-events.txt: %w", err) + } + + //define command to get persistent volume claims + getPVC := exec.Command("kubectl", "get", "pvc") + getPVC.Stdout = PVC + getPVC.Stderr = os.Stderr + + //get persistent volumes + if err := getPVC.Run(); err != nil { + return fmt.Errorf("running kubectl get pvc failed: %w", err) + } + + return nil +} + // gets current pod logs and logs from past containers -func archiveLogs(zw *zip.Writer, pods podList) error { +func archiveLogs(zw *zip.Writer, pods podList, baseDir string) error { // run kubectl logs and write to archive, accounts for containers in pod for _, pod := range pods.Items { fmt.Println("Archiving logs: ", pod.Metadata.Name, "Containers:", pod.Spec.Containers) for _, container := range pod.Spec.Containers { - logs, err := zw.Create("outFile/kubectl/logs/" + pod.Metadata.Name + "/" + container.Name + ".txt") + logs, err := zw.Create(baseDir + "/kubectl/logs/" + pod.Metadata.Name + "/" + container.Name + ".txt") if err != nil { return fmt.Errorf("failed to create podLogs.txt: %w", err) } @@ -192,7 +245,7 @@ func archiveLogs(zw *zip.Writer, pods podList) error { getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) if err := getPrevLogs.Run(); err == nil { fmt.Println("Archiving previous logs: ", pod.Metadata.Name, "Containers: ", pod.Spec.Containers) - prev, err := zw.Create("outFile/kubectl/logs/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".txt") + prev, err := zw.Create(baseDir + "/kubectl/logs/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".txt") getPrevLogs.Stdout = prev if err != nil { return fmt.Errorf("failed to create podLogs.txt: %w", err) @@ -204,9 +257,9 @@ func archiveLogs(zw *zip.Writer, pods podList) error { return nil } -func archiveDescribes(zw *zip.Writer, pods podList) error { +func archiveDescribes(zw *zip.Writer, pods podList, baseDir string) error { for _, pod := range pods.Items { - describes, err := zw.Create("outFile/kubectl/describe/" + pod.Metadata.Name + ".txt") + describes, err := zw.Create(baseDir + "/kubectl/describe/" + pod.Metadata.Name + ".txt") if err != nil { return fmt.Errorf("failed to create podLogs.txt: %w", err) } @@ -222,9 +275,9 @@ func archiveDescribes(zw *zip.Writer, pods podList) error { return nil } -func archiveManifests(zw *zip.Writer, pods podList) error { +func archiveManifests(zw *zip.Writer, pods podList, baseDir string) error { for _, pod := range pods.Items { - manifests, err := zw.Create("outFile/kubectl/manifest/" + pod.Metadata.Name + ".yaml") + manifests, err := zw.Create(baseDir + "/kubectl/manifest/" + pod.Metadata.Name + ".yaml") if err != nil { return fmt.Errorf("failed to create manifest.yaml: %w", err) } From 5c6987ca522a68ea442572000fdfcebedd2ec201 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 25 Aug 2021 23:46:53 -0700 Subject: [PATCH 026/107] changed archive filestructure to be oriented around pod directories containing logs, past logs, and manifests --- cmd/src/debug.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 2d4fb1ffe7..20ccadc0ea 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -224,7 +224,7 @@ func archiveLogs(zw *zip.Writer, pods podList, baseDir string) error { for _, pod := range pods.Items { fmt.Println("Archiving logs: ", pod.Metadata.Name, "Containers:", pod.Spec.Containers) for _, container := range pod.Spec.Containers { - logs, err := zw.Create(baseDir + "/kubectl/logs/" + pod.Metadata.Name + "/" + container.Name + ".txt") + logs, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + container.Name + ".log") if err != nil { return fmt.Errorf("failed to create podLogs.txt: %w", err) } @@ -245,7 +245,7 @@ func archiveLogs(zw *zip.Writer, pods podList, baseDir string) error { getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) if err := getPrevLogs.Run(); err == nil { fmt.Println("Archiving previous logs: ", pod.Metadata.Name, "Containers: ", pod.Spec.Containers) - prev, err := zw.Create(baseDir + "/kubectl/logs/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".txt") + prev, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".log") getPrevLogs.Stdout = prev if err != nil { return fmt.Errorf("failed to create podLogs.txt: %w", err) @@ -259,7 +259,7 @@ func archiveLogs(zw *zip.Writer, pods podList, baseDir string) error { func archiveDescribes(zw *zip.Writer, pods podList, baseDir string) error { for _, pod := range pods.Items { - describes, err := zw.Create(baseDir + "/kubectl/describe/" + pod.Metadata.Name + ".txt") + describes, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/describe-" + pod.Metadata.Name + ".txt") if err != nil { return fmt.Errorf("failed to create podLogs.txt: %w", err) } @@ -277,7 +277,7 @@ func archiveDescribes(zw *zip.Writer, pods podList, baseDir string) error { func archiveManifests(zw *zip.Writer, pods podList, baseDir string) error { for _, pod := range pods.Items { - manifests, err := zw.Create(baseDir + "/kubectl/manifest/" + pod.Metadata.Name + ".yaml") + manifests, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/manifest-" + pod.Metadata.Name + ".yaml") if err != nil { return fmt.Errorf("failed to create manifest.yaml: %w", err) } From dc32e6f909d6e167c57bee7d144d9fe08faae366 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 25 Aug 2021 23:53:41 -0700 Subject: [PATCH 027/107] cleaned up some finished TODOs, shortened selector values for -d flag --- cmd/src/debug.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 20ccadc0ea..1108c2c878 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -40,7 +40,6 @@ USAGE // store value passed to flags var ( - //TODO add deployment type selector deployment = flagSet.String("d", "", "deployment type") base = flagSet.String("out", "debug.zip", "The name of the output zip archive") ) @@ -63,8 +62,8 @@ USAGE baseDir = strings.TrimSuffix(*base, ".zip") } // handle deployment flag - if !((*deployment == "server") || (*deployment == "compose") || (*deployment == "kubernetes")) { - return fmt.Errorf("must declare -d=, as server, compose, or kubernetes") + if !((*deployment == "serv") || (*deployment == "comp") || (*deployment == "kube")) { + return fmt.Errorf("must declare -d=, as serv, comp, or kube") } // open pipe to output file @@ -127,10 +126,7 @@ USAGE }) } -// TODO: make outFile the input from `-out=` flag stored in `outFile`, validate that .zip postpends `outFile` // TODO: improve logging as kubectl calls run (Desc, Mani) -// TODO: refactor dir structure to be by pod, change logs to .log filetype -// TODO: improve error handling // TODO: refactor archiveLLogs so that both logs and logs --past are collected in the same loop func getPods() (podList, error) { From 26ebd7848805f777409ce07deec279e58cff6ad9 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 26 Aug 2021 22:27:39 -0700 Subject: [PATCH 028/107] refactored kubectl archiving into -d flag switch --- cmd/src/debug.go | 86 ++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 1108c2c878..55679d96d9 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -78,42 +78,19 @@ USAGE defer zw.Close() // TODO write functions for sourcegraph server and docker-compose instances - //switch *deployment { - //case "server": - // fmt.Println("its a single container") - //case "compose": - // fmt.Println("its a docker-compose instance") - //case "kubernetes": - // fmt.Println("its a kubernetes deployment") - //default: - // return fmt.Errorf("must declare -d=, as server, compose, or kubernetes") - //} - - pods, err := getPods() - if err != nil { - return fmt.Errorf("failed to get pods: %w", err) + switch *deployment { + case "serv": + fmt.Println("its a single container") + case "comp": + fmt.Println("its a docker-compose instance") + case "kube": + if err := archiveKube(zw, baseDir); err != nil { + return fmt.Errorf("archiveKube failed with err: %w", err) + } + default: + return fmt.Errorf("must declare -d=, as server, compose, or kubernetes") } - // TODO error group, create function type and run as goroutines - // Runs all kubectl based functions - if err := archiveEvents(zw, baseDir); err != nil { - return fmt.Errorf("running archiveEvents failed: %w", err) - } - if err := archivePV(zw, baseDir); err != nil { - return fmt.Errorf("running archivePV failed: %w", err) - } - if err := archivePVC(zw, baseDir); err != nil { - return fmt.Errorf("running archivePV failed: %w", err) - } - if err := archiveLogs(zw, pods, baseDir); err != nil { - return fmt.Errorf("running archiveLogs failed: %w", err) - } - if err := archiveDescribes(zw, pods, baseDir); err != nil { - return fmt.Errorf("running archiveDescribes failed: %w", err) - } - if err := archiveManifests(zw, pods, baseDir); err != nil { - return fmt.Errorf("running archiveManifests failed: %w", err) - } return nil } @@ -126,8 +103,39 @@ USAGE }) } -// TODO: improve logging as kubectl calls run (Desc, Mani) -// TODO: refactor archiveLLogs so that both logs and logs --past are collected in the same loop +/* +Kubernetes functions +TODO: improve logging as kubectl calls run (Desc, Mani) +TODO: refactor archiveLLogs so that both logs and logs --past are collected in the same loop +*/ + +func archiveKube(zw *zip.Writer, baseDir string) error { + pods, err := getPods() + if err != nil { + return fmt.Errorf("failed to get pods: %w", err) + } + // TODO error group, create function type and run as goroutines + // Runs all kubectl based functions + if err := archiveEvents(zw, baseDir); err != nil { + return fmt.Errorf("running archiveEvents failed: %w", err) + } + if err := archivePV(zw, baseDir); err != nil { + return fmt.Errorf("running archivePV failed: %w", err) + } + if err := archivePVC(zw, baseDir); err != nil { + return fmt.Errorf("running archivePV failed: %w", err) + } + if err := archiveLogs(zw, pods, baseDir); err != nil { + return fmt.Errorf("running archiveLogs failed: %w", err) + } + if err := archiveDescribes(zw, pods, baseDir); err != nil { + return fmt.Errorf("running archiveDescribes failed: %w", err) + } + if err := archiveManifests(zw, pods, baseDir); err != nil { + return fmt.Errorf("running archiveManifests failed: %w", err) + } + return nil +} func getPods() (podList, error) { // Declare buffer type var for kubectl pipe @@ -288,3 +296,9 @@ func archiveManifests(zw *zip.Writer, pods podList, baseDir string) error { } return nil } + +/* +Docker functions + + +*/ From 53e8eccdc068341d46a803ed0facd78f81c43acf Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 27 Aug 2021 08:21:40 -0700 Subject: [PATCH 029/107] working get containers --- cmd/src/debug.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 55679d96d9..41dc553d22 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -61,10 +61,10 @@ USAGE } else { baseDir = strings.TrimSuffix(*base, ".zip") } - // handle deployment flag - if !((*deployment == "serv") || (*deployment == "comp") || (*deployment == "kube")) { - return fmt.Errorf("must declare -d=, as serv, comp, or kube") - } + //// handle deployment flag + //if !((*deployment == "serv") || (*deployment == "comp") || (*deployment == "kube")) { + // return fmt.Errorf("must declare -d=, as serv, comp, or kube") + //} // open pipe to output file out, err := os.OpenFile(*base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) @@ -80,9 +80,9 @@ USAGE // TODO write functions for sourcegraph server and docker-compose instances switch *deployment { case "serv": - fmt.Println("its a single container") + getContainers() case "comp": - fmt.Println("its a docker-compose instance") + getContainers() case "kube": if err := archiveKube(zw, baseDir); err != nil { return fmt.Errorf("archiveKube failed with err: %w", err) @@ -302,3 +302,14 @@ Docker functions */ + +func getContainers() (string, error) { + + containers, err := exec.Command("docker", "container", "ls", "--format", "{{.Names}}").Output() + if err != nil { + fmt.Errorf("failed to get container names with error: %w", err) + } + contStr := string(containers) + fmt.Println(contStr) + return contStr, err +} From 928d61fc9a949fe1ac63efafdba2e2971e097ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senart?= Date: Fri, 27 Aug 2021 18:00:43 +0200 Subject: [PATCH 030/107] Concurrency!! --- cmd/src/debug.go | 96 ++++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 35 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 41dc553d22..d267e1178d 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -4,10 +4,13 @@ import ( "archive/zip" "bytes" "encoding/json" + "errors" "flag" "fmt" + "io" "os" "strings" + "sync" "github.com/sourcegraph/src-cli/internal/exec" ) @@ -109,31 +112,66 @@ TODO: improve logging as kubectl calls run (Desc, Mani) TODO: refactor archiveLLogs so that both logs and logs --past are collected in the same loop */ +type archiveFile struct { + name string + data []byte + err error +} + func archiveKube(zw *zip.Writer, baseDir string) error { pods, err := getPods() if err != nil { return fmt.Errorf("failed to get pods: %w", err) } - // TODO error group, create function type and run as goroutines - // Runs all kubectl based functions - if err := archiveEvents(zw, baseDir); err != nil { - return fmt.Errorf("running archiveEvents failed: %w", err) - } - if err := archivePV(zw, baseDir); err != nil { - return fmt.Errorf("running archivePV failed: %w", err) - } - if err := archivePVC(zw, baseDir); err != nil { - return fmt.Errorf("running archivePV failed: %w", err) - } - if err := archiveLogs(zw, pods, baseDir); err != nil { - return fmt.Errorf("running archiveLogs failed: %w", err) - } - if err := archiveDescribes(zw, pods, baseDir); err != nil { - return fmt.Errorf("running archiveDescribes failed: %w", err) - } - if err := archiveManifests(zw, pods, baseDir); err != nil { - return fmt.Errorf("running archiveManifests failed: %w", err) + + ch := make(chan []archiveFile) + wg := sync.WaitGroup{} + + wg.Add(1) + go func() { + defer wg.Done() + fs := archiveEvents(baseDir) + ch <- fs + }() + + //if err := archiveEvents(zw, baseDir); err != nil { + // return fmt.Errorf("running archiveEvents failed: %w", err) + //} + //if err := archivePV(zw, baseDir); err != nil { + // return fmt.Errorf("running archivePV failed: %w", err) + //} + //if err := archivePVC(zw, baseDir); err != nil { + // return fmt.Errorf("running archivePV failed: %w", err) + //} + //if err := archiveLogs(zw, pods, baseDir); err != nil { + // return fmt.Errorf("running archiveLogs failed: %w", err) + //} + //if err := archiveDescribes(zw, pods, baseDir); err != nil { + // return fmt.Errorf("running archiveDescribes failed: %w", err) + //} + //if err := archiveManifests(zw, pods, baseDir); err != nil { + // return fmt.Errorf("running archiveManifests failed: %w", err) + //} + + go func() { + wg.Wait() + close(ch) + }() + + for files := range ch { + for _, f := range files { + zf, err := zw.Create(f.name) + if err != nil { + return fmt.Errorf("failed to create %s: %w", f.name, err) + } + + _, err = zf.Write(f.data) + if err != nil { + return fmt.Errorf("failed to write to %s: %w", f.name, err) + } + } } + return nil } @@ -159,24 +197,12 @@ func getPods() (podList, error) { return pods, err } -func archiveEvents(zw *zip.Writer, baseDir string) error { - //write events to archive - k8sEvents, err := zw.Create(baseDir + "/kubectl/events.txt") - if err != nil { - return fmt.Errorf("failed to create k8s-events.txt: %w", err) - } - - //define command to get events - getEvents := exec.Command("kubectl", "get", "events", "--all-namespaces") - getEvents.Stdout = k8sEvents - getEvents.Stderr = os.Stderr +func archiveEvents(baseDir string) (fs []archiveFile) { + f := archiveFile{name: baseDir + "/kubectl/events.txt"} - //get events - if err := getEvents.Run(); err != nil { - return fmt.Errorf("running kubectl get events failed: %w", err) - } + f.data, f.err = exec.Command("kubectl", "get", "events", "--all-namespaces").CombinedOutput() - return nil + return []archiveFile{f} } func archivePV(zw *zip.Writer, baseDir string) error { From 1a655d918f35cf4636688a648c3358751c39a221 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Sun, 29 Aug 2021 22:27:33 -0700 Subject: [PATCH 031/107] made deploy level kubectl functions concurrent --- cmd/src/debug.go | 122 +++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index d267e1178d..2f5cb5c38a 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -4,10 +4,8 @@ import ( "archive/zip" "bytes" "encoding/json" - "errors" "flag" "fmt" - "io" "os" "strings" "sync" @@ -28,6 +26,12 @@ type podList struct { } } +type archiveFile struct { + name string + data []byte + err error +} + // Init debug flag on src build func init() { flagSet := flag.NewFlagSet("debug", flag.ExitOnError) @@ -110,56 +114,53 @@ USAGE Kubernetes functions TODO: improve logging as kubectl calls run (Desc, Mani) TODO: refactor archiveLLogs so that both logs and logs --past are collected in the same loop +TODO: refactor archive functions to run concurrently as goroutines */ -type archiveFile struct { - name string - data []byte - err error -} - +// Run kubectl functions concurrently and archive results to zip file func archiveKube(zw *zip.Writer, baseDir string) error { pods, err := getPods() if err != nil { return fmt.Errorf("failed to get pods: %w", err) } + fmt.Println(pods) + // setup channel for slice of archive function outputs ch := make(chan []archiveFile) wg := sync.WaitGroup{} + // create goroutine to get kubectl events wg.Add(1) go func() { defer wg.Done() - fs := archiveEvents(baseDir) + fs := getEvents(baseDir) ch <- fs }() - //if err := archiveEvents(zw, baseDir); err != nil { - // return fmt.Errorf("running archiveEvents failed: %w", err) - //} - //if err := archivePV(zw, baseDir); err != nil { - // return fmt.Errorf("running archivePV failed: %w", err) - //} - //if err := archivePVC(zw, baseDir); err != nil { - // return fmt.Errorf("running archivePV failed: %w", err) - //} - //if err := archiveLogs(zw, pods, baseDir); err != nil { - // return fmt.Errorf("running archiveLogs failed: %w", err) - //} - //if err := archiveDescribes(zw, pods, baseDir); err != nil { - // return fmt.Errorf("running archiveDescribes failed: %w", err) - //} - //if err := archiveManifests(zw, pods, baseDir); err != nil { - // return fmt.Errorf("running archiveManifests failed: %w", err) - //} + wg.Add(1) + go func() { + defer wg.Done() + fs := getPV(baseDir) + ch <- fs + }() + + wg.Add(1) + go func() { + defer wg.Done() + fs := getPVC(baseDir) + ch <- fs + }() + // close channel when wait group goroutines have completed go func() { wg.Wait() close(ch) }() + // write to archive all the outputs from kubectl call functions passed to buffer channel for files := range ch { for _, f := range files { + // write file path zf, err := zw.Create(f.name) if err != nil { return fmt.Errorf("failed to create %s: %w", f.name, err) @@ -197,7 +198,7 @@ func getPods() (podList, error) { return pods, err } -func archiveEvents(baseDir string) (fs []archiveFile) { +func getEvents(baseDir string) (fs []archiveFile) { f := archiveFile{name: baseDir + "/kubectl/events.txt"} f.data, f.err = exec.Command("kubectl", "get", "events", "--all-namespaces").CombinedOutput() @@ -205,46 +206,21 @@ func archiveEvents(baseDir string) (fs []archiveFile) { return []archiveFile{f} } -func archivePV(zw *zip.Writer, baseDir string) error { - fmt.Println("Archiving persistent volumes") - //write persistent volumes to archive - PV, err := zw.Create(baseDir + "/kubectl/persistent-volumes.txt") - if err != nil { - return fmt.Errorf("failed to create k8s-events.txt: %w", err) - } - - //define command to get persistent volumes - getPV := exec.Command("kubectl", "get", "pv") - getPV.Stdout = PV - getPV.Stderr = os.Stderr +func getPV(baseDir string) (fs []archiveFile) { + f := archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} - //get persistent volumes - if err := getPV.Run(); err != nil { - return fmt.Errorf("running kubectl get pv failed: %w", err) - } + f.data, f.err = exec.Command("kubectl", "get", "pv").CombinedOutput() - return nil + return []archiveFile{f} } -func archivePVC(zw *zip.Writer, baseDir string) error { - fmt.Println("Archiving persistent volume claims") +func getPVC(baseDir string) (fs []archiveFile) { //write persistent volume claims to archive - PVC, err := zw.Create(baseDir + "/kubectl/persistent-volume-claims.txt") - if err != nil { - return fmt.Errorf("failed to create k8s-events.txt: %w", err) - } - - //define command to get persistent volume claims - getPVC := exec.Command("kubectl", "get", "pvc") - getPVC.Stdout = PVC - getPVC.Stderr = os.Stderr + f := archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} - //get persistent volumes - if err := getPVC.Run(); err != nil { - return fmt.Errorf("running kubectl get pvc failed: %w", err) - } + f.data, f.err = exec.Command("kubectl", "get", "pvc").CombinedOutput() - return nil + return []archiveFile{f} } // gets current pod logs and logs from past containers @@ -339,3 +315,27 @@ func getContainers() (string, error) { fmt.Println(contStr) return contStr, err } + +/* +Graveyard +----------- +*/ + +//if err := archiveEvents(zw, baseDir); err != nil { +// return fmt.Errorf("running archiveEvents failed: %w", err) +//} +//if err := archivePV(zw, baseDir); err != nil { +// return fmt.Errorf("running archivePV failed: %w", err) +//} +//if err := archivePVC(zw, baseDir); err != nil { +// return fmt.Errorf("running archivePV failed: %w", err) +//} +//if err := archiveLogs(zw, pods, baseDir); err != nil { +// return fmt.Errorf("running archiveLogs failed: %w", err) +//} +//if err := archiveDescribes(zw, pods, baseDir); err != nil { +// return fmt.Errorf("running archiveDescribes failed: %w", err) +//} +//if err := archiveManifests(zw, pods, baseDir); err != nil { +// return fmt.Errorf("running archiveManifests failed: %w", err) +//} From 572218e07334e117efc1e626a6cc62620884bcc0 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 30 Aug 2021 15:31:43 -0700 Subject: [PATCH 032/107] figured out bug in getLogs caused by immediately invoked function and variable scope in for loop --- cmd/src/debug.go | 118 +++++++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 45 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 2f5cb5c38a..1130425b57 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -151,6 +151,18 @@ func archiveKube(zw *zip.Writer, baseDir string) error { ch <- fs }() + // start goroutine for each pods containers + for _, pod := range pods.Items { + for _, container := range pod.Spec.Containers { + wg.Add(1) + go func(pod string, container string) { + defer wg.Done() + fs := getContainerLogs(pod, container, baseDir) + ch <- fs + }(pod.Metadata.Name, container.Name) + } + } + // close channel when wait group goroutines have completed go func() { wg.Wait() @@ -165,7 +177,6 @@ func archiveKube(zw *zip.Writer, baseDir string) error { if err != nil { return fmt.Errorf("failed to create %s: %w", f.name, err) } - _, err = zf.Write(f.data) if err != nil { return fmt.Errorf("failed to write to %s: %w", f.name, err) @@ -200,69 +211,46 @@ func getPods() (podList, error) { func getEvents(baseDir string) (fs []archiveFile) { f := archiveFile{name: baseDir + "/kubectl/events.txt"} - f.data, f.err = exec.Command("kubectl", "get", "events", "--all-namespaces").CombinedOutput() - return []archiveFile{f} } func getPV(baseDir string) (fs []archiveFile) { f := archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} - f.data, f.err = exec.Command("kubectl", "get", "pv").CombinedOutput() - return []archiveFile{f} } func getPVC(baseDir string) (fs []archiveFile) { //write persistent volume claims to archive f := archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} - f.data, f.err = exec.Command("kubectl", "get", "pvc").CombinedOutput() - return []archiveFile{f} } -// gets current pod logs and logs from past containers -func archiveLogs(zw *zip.Writer, pods podList, baseDir string) error { - - // run kubectl logs and write to archive, accounts for containers in pod - for _, pod := range pods.Items { - fmt.Println("Archiving logs: ", pod.Metadata.Name, "Containers:", pod.Spec.Containers) - for _, container := range pod.Spec.Containers { - logs, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + container.Name + ".log") - if err != nil { - return fmt.Errorf("failed to create podLogs.txt: %w", err) - } - - getLogs := exec.Command("kubectl", "logs", pod.Metadata.Name, "-c", container.Name) - getLogs.Stdout = logs - getLogs.Stderr = os.Stderr - - if err := getLogs.Run(); err != nil { - return fmt.Errorf("running kubectl get logs failed: %w", err) - } - } - } - - // run kubectl logs --previous and write to archive if return not err - for _, pod := range pods.Items { - for _, container := range pod.Spec.Containers { - getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) - if err := getPrevLogs.Run(); err == nil { - fmt.Println("Archiving previous logs: ", pod.Metadata.Name, "Containers: ", pod.Spec.Containers) - prev, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".log") - getPrevLogs.Stdout = prev - if err != nil { - return fmt.Errorf("failed to create podLogs.txt: %w", err) - } - } - } - } - - return nil +// get kubectl logs for pod containers +func getContainerLogs(podName string, containerName string, baseDir string) (fs []archiveFile) { + fmt.Println("func Name:", podName, "Container:", containerName) + f := archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} + f.data, f.err = exec.Command("kubectl", "logs", podName, "-c", containerName).CombinedOutput() + return []archiveFile{f} } +//// get kubectl logs --previous for pod containers +//for _, pod := range pods.Items { +// for _, container := range pod.Spec.Containers { +// getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) +// if err := getPrevLogs.Run(); err == nil { +// fmt.Println("Archiving previous logs: ", pod.Metadata.Name, "Containers: ", pod.Spec.Containers) +// prev, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".log") +// getPrevLogs.Stdout = prev +// if err != nil { +// return fmt.Errorf("failed to create podLogs.txt: %w", err) +// } +// } +// } +//} + func archiveDescribes(zw *zip.Writer, pods podList, baseDir string) error { for _, pod := range pods.Items { describes, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/describe-" + pod.Metadata.Name + ".txt") @@ -339,3 +327,43 @@ Graveyard //if err := archiveManifests(zw, pods, baseDir); err != nil { // return fmt.Errorf("running archiveManifests failed: %w", err) //} + +//// gets current pod logs and logs from past containers +//func getLogs(pods podList, baseDir string) (fs []archiveFile) { +// +// // run kubectl logs and write to archive, accounts for containers in pod +// for _, pod := range pods.Items { +// fmt.Println("Archiving logs: ", pod.Metadata.Name, "Containers:", pod.Spec.Containers) +// for _, container := range pod.Spec.Containers { +// logs, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + container.Name + ".log") +// if err != nil { +// return fmt.Errorf("failed to create podLogs.txt: %w", err) +// } +// +// getLogs := exec.Command("kubectl", "logs", pod.Metadata.Name, "-c", container.Name) +// getLogs.Stdout = logs +// getLogs.Stderr = os.Stderr +// +// if err := getLogs.Run(); err != nil { +// return fmt.Errorf("running kubectl get logs failed: %w", err) +// } +// } +// } +// +// // run kubectl logs --previous and write to archive if return not err +// for _, pod := range pods.Items { +// for _, container := range pod.Spec.Containers { +// getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) +// if err := getPrevLogs.Run(); err == nil { +// fmt.Println("Archiving previous logs: ", pod.Metadata.Name, "Containers: ", pod.Spec.Containers) +// prev, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".log") +// getPrevLogs.Stdout = prev +// if err != nil { +// return fmt.Errorf("failed to create podLogs.txt: %w", err) +// } +// } +// } +// } +// +// return nil +//} From 62d915c3c96556d51e6d19a2bd51d3fcc44a449b Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 30 Aug 2021 23:11:58 -0700 Subject: [PATCH 033/107] all kubectl functions refactored to run as goroutines, bug present causing some zip writes to write empty files --- cmd/src/debug.go | 125 +++++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 52 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 1130425b57..9d7b4d77a4 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -119,11 +119,11 @@ TODO: refactor archive functions to run concurrently as goroutines // Run kubectl functions concurrently and archive results to zip file func archiveKube(zw *zip.Writer, baseDir string) error { + fmt.Println("getting kubectl data...") pods, err := getPods() if err != nil { return fmt.Errorf("failed to get pods: %w", err) } - fmt.Println(pods) // setup channel for slice of archive function outputs ch := make(chan []archiveFile) @@ -137,6 +137,7 @@ func archiveKube(zw *zip.Writer, baseDir string) error { ch <- fs }() + // create goroutine to get persistent volumes wg.Add(1) go func() { defer wg.Done() @@ -144,6 +145,7 @@ func archiveKube(zw *zip.Writer, baseDir string) error { ch <- fs }() + // create goroutine to get persistent volumes claim wg.Add(1) go func() { defer wg.Done() @@ -151,7 +153,7 @@ func archiveKube(zw *zip.Writer, baseDir string) error { ch <- fs }() - // start goroutine for each pods containers + // start goroutine to run kubectl logs for each pod's container's for _, pod := range pods.Items { for _, container := range pod.Spec.Containers { wg.Add(1) @@ -163,6 +165,42 @@ func archiveKube(zw *zip.Writer, baseDir string) error { } } + // start goroutine to run kubectl logs --previous for each pod's container's + // won't write to zip on err, only passes bytes to channel if err not nil + for _, pod := range pods.Items { + for _, container := range pod.Spec.Containers { + wg.Add(1) + go func(pod string, container string) { + defer wg.Done() + fs := getPastContainerLogs(pod, container, baseDir) + if fs[0].err == nil { + fmt.Println("got past logs for:", pod) + ch <- fs + } + }(pod.Metadata.Name, container.Name) + } + } + + // start goroutine for each pod to run kubectl describe pod + for _, pod := range pods.Items { + wg.Add(1) + go func(pod string) { + defer wg.Done() + fs := getDescribes(pod, baseDir) + ch <- fs + }(pod.Metadata.Name) + } + + // start goroutine for each pod to run kubectl get pod -o yaml + for _, pod := range pods.Items { + wg.Add(1) + go func(pod string) { + defer wg.Done() + fs := getManifests(pod, baseDir) + ch <- fs + }(pod.Metadata.Name) + } + // close channel when wait group goroutines have completed go func() { wg.Wait() @@ -202,10 +240,9 @@ func getPods() (podList, error) { //Decode json from podList if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { - fmt.Errorf("feailed to unmarshall get pods json: %w", err) + fmt.Errorf("failed to unmarshall get pods json: %w", err) } - fmt.Println(pods) return pods, err } @@ -222,7 +259,6 @@ func getPV(baseDir string) (fs []archiveFile) { } func getPVC(baseDir string) (fs []archiveFile) { - //write persistent volume claims to archive f := archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} f.data, f.err = exec.Command("kubectl", "get", "pvc").CombinedOutput() return []archiveFile{f} @@ -230,61 +266,28 @@ func getPVC(baseDir string) (fs []archiveFile) { // get kubectl logs for pod containers func getContainerLogs(podName string, containerName string, baseDir string) (fs []archiveFile) { - fmt.Println("func Name:", podName, "Container:", containerName) f := archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} f.data, f.err = exec.Command("kubectl", "logs", podName, "-c", containerName).CombinedOutput() return []archiveFile{f} } -//// get kubectl logs --previous for pod containers -//for _, pod := range pods.Items { -// for _, container := range pod.Spec.Containers { -// getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) -// if err := getPrevLogs.Run(); err == nil { -// fmt.Println("Archiving previous logs: ", pod.Metadata.Name, "Containers: ", pod.Spec.Containers) -// prev, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".log") -// getPrevLogs.Stdout = prev -// if err != nil { -// return fmt.Errorf("failed to create podLogs.txt: %w", err) -// } -// } -// } -//} - -func archiveDescribes(zw *zip.Writer, pods podList, baseDir string) error { - for _, pod := range pods.Items { - describes, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/describe-" + pod.Metadata.Name + ".txt") - if err != nil { - return fmt.Errorf("failed to create podLogs.txt: %w", err) - } - - describePod := exec.Command("kubectl", "describe", "pod", pod.Metadata.Name) - describePod.Stdout = describes - describePod.Stderr = os.Stderr - - if err := describePod.Run(); err != nil { - return fmt.Errorf("failer to run describe pod: %w", err) - } - } - return nil +// get kubectl logs for past container +func getPastContainerLogs(podName string, containerName string, baseDir string) (fs []archiveFile) { + f := archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} + f.data, f.err = exec.Command("kubectl", "logs", "--previous", podName, "-c", containerName).CombinedOutput() + return []archiveFile{f} } -func archiveManifests(zw *zip.Writer, pods podList, baseDir string) error { - for _, pod := range pods.Items { - manifests, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/manifest-" + pod.Metadata.Name + ".yaml") - if err != nil { - return fmt.Errorf("failed to create manifest.yaml: %w", err) - } - - getManifest := exec.Command("kubectl", "get", "pod", pod.Metadata.Name, "-o", "yaml") - getManifest.Stdout = manifests - getManifest.Stderr = os.Stderr +func getDescribes(podName string, baseDir string) (fs []archiveFile) { + f := archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} + f.data, f.err = exec.Command("kubectl", "describe", "pod", podName).CombinedOutput() + return []archiveFile{f} +} - if err := getManifest.Run(); err != nil { - fmt.Errorf("failed to get pod yaml: %w", err) - } - } - return nil +func getManifests(podName string, baseDir string) (fs []archiveFile) { + f := archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} + f.data, f.err = exec.Command("kubectl", "get", "pod", podName, "-o", "yaml").CombinedOutput() + return []archiveFile{f} } /* @@ -367,3 +370,21 @@ Graveyard // // return nil //} + +//func archiveManifests(zw *zip.Writer, pods podList, baseDir string) error { +// for _, pod := range pods.Items { +// manifests, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/manifest-" + pod.Metadata.Name + ".yaml") +// if err != nil { +// return fmt.Errorf("failed to create manifest.yaml: %w", err) +// } +// +// getManifest := exec.Command("kubectl", "get", "pod", pod.Metadata.Name, "-o", "yaml") +// getManifest.Stdout = manifests +// getManifest.Stderr = os.Stderr +// +// if err := getManifest.Run(); err != nil { +// fmt.Errorf("failed to get pod yaml: %w", err) +// } +// } +// return nil +//} From 6943f528b1e0604e0ff508c756b94e30affece13 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 30 Aug 2021 23:29:24 -0700 Subject: [PATCH 034/107] added some prints for debugging --- cmd/src/debug.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 9d7b4d77a4..a593e59c3c 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -119,11 +119,11 @@ TODO: refactor archive functions to run concurrently as goroutines // Run kubectl functions concurrently and archive results to zip file func archiveKube(zw *zip.Writer, baseDir string) error { - fmt.Println("getting kubectl data...") pods, err := getPods() if err != nil { return fmt.Errorf("failed to get pods: %w", err) } + fmt.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) // setup channel for slice of archive function outputs ch := make(chan []archiveFile) From 03366684e0c5093ff3478c786cb3a2954c70bddf Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 30 Aug 2021 23:48:57 -0700 Subject: [PATCH 035/107] clean up some flag validating prints and comments --- cmd/src/debug.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index a593e59c3c..3fc47b127e 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -68,10 +68,6 @@ USAGE } else { baseDir = strings.TrimSuffix(*base, ".zip") } - //// handle deployment flag - //if !((*deployment == "serv") || (*deployment == "comp") || (*deployment == "kube")) { - // return fmt.Errorf("must declare -d=, as serv, comp, or kube") - //} // open pipe to output file out, err := os.OpenFile(*base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) @@ -95,7 +91,7 @@ USAGE return fmt.Errorf("archiveKube failed with err: %w", err) } default: - return fmt.Errorf("must declare -d=, as server, compose, or kubernetes") + return fmt.Errorf("must declare -d=, as serv, comp, or kube") } return nil From f26f592f109870679cb5d263dd9c004e73396cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senart?= Date: Tue, 31 Aug 2021 14:27:06 +0200 Subject: [PATCH 036/107] A bunch of improvements 1. Set open file limits in process to support this much concurrency. This could also be done in the shell with `ulimits -n 99999`. 2. Pass in `context.Context` so we cancel any pending go-routines when returning early. 3. Change getXXX signatures from returning a slice to a single *archiveFile (since we were never actually returning more than one file) 4. Check for error in the file archiving loop and abort if there's any. 5. Verbose logging support. --- cmd/src/debug.go | 173 ++++++++++++++++++++++++++++------------------- 1 file changed, 102 insertions(+), 71 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 3fc47b127e..d69060d615 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -3,12 +3,15 @@ package main import ( "archive/zip" "bytes" + "context" "encoding/json" "flag" "fmt" + "log" "os" "strings" "sync" + "syscall" "github.com/sourcegraph/src-cli/internal/exec" ) @@ -75,19 +78,24 @@ USAGE return fmt.Errorf("failed to open file: %w", err) } + if err := setOpenFileLimits(99999); err != nil { + return fmt.Errorf("failed to set open file limits: %w", err) + } + // open zip writer defer out.Close() zw := zip.NewWriter(out) defer zw.Close() + ctx := context.Background() // TODO write functions for sourcegraph server and docker-compose instances switch *deployment { case "serv": - getContainers() + getContainers(ctx) case "comp": - getContainers() + getContainers(ctx) case "kube": - if err := archiveKube(zw, baseDir); err != nil { + if err := archiveKube(ctx, zw, *verbose, baseDir); err != nil { return fmt.Errorf("archiveKube failed with err: %w", err) } default: @@ -114,49 +122,54 @@ TODO: refactor archive functions to run concurrently as goroutines */ // Run kubectl functions concurrently and archive results to zip file -func archiveKube(zw *zip.Writer, baseDir string) error { - pods, err := getPods() +func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir string) error { + // Create a context with a cancel function that we call when returning + // from archiveKube. This ensures we close all pending go-routines when returning + // early because of an error. + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + pods, err := getPods(ctx) if err != nil { return fmt.Errorf("failed to get pods: %w", err) } - fmt.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) + + if verbose { + log.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) + } // setup channel for slice of archive function outputs - ch := make(chan []archiveFile) + ch := make(chan *archiveFile) wg := sync.WaitGroup{} // create goroutine to get kubectl events wg.Add(1) go func() { defer wg.Done() - fs := getEvents(baseDir) - ch <- fs + ch <- getEvents(ctx, baseDir) }() // create goroutine to get persistent volumes wg.Add(1) go func() { defer wg.Done() - fs := getPV(baseDir) - ch <- fs + ch <- getPV(ctx, baseDir) }() // create goroutine to get persistent volumes claim wg.Add(1) go func() { defer wg.Done() - fs := getPVC(baseDir) - ch <- fs + ch <- getPVC(ctx, baseDir) }() // start goroutine to run kubectl logs for each pod's container's for _, pod := range pods.Items { for _, container := range pod.Spec.Containers { wg.Add(1) - go func(pod string, container string) { + go func(pod, container string) { defer wg.Done() - fs := getContainerLogs(pod, container, baseDir) - ch <- fs + ch <- getContainerLogs(ctx, pod, container, baseDir) }(pod.Metadata.Name, container.Name) } } @@ -166,12 +179,11 @@ func archiveKube(zw *zip.Writer, baseDir string) error { for _, pod := range pods.Items { for _, container := range pod.Spec.Containers { wg.Add(1) - go func(pod string, container string) { + go func(pod, container string) { defer wg.Done() - fs := getPastContainerLogs(pod, container, baseDir) - if fs[0].err == nil { - fmt.Println("got past logs for:", pod) - ch <- fs + f := getPastContainerLogs(ctx, pod, container, baseDir) + if f.err == nil { + ch <- f } }(pod.Metadata.Name, container.Name) } @@ -182,8 +194,7 @@ func archiveKube(zw *zip.Writer, baseDir string) error { wg.Add(1) go func(pod string) { defer wg.Done() - fs := getDescribes(pod, baseDir) - ch <- fs + ch <- getDescribes(ctx, pod, baseDir) }(pod.Metadata.Name) } @@ -192,8 +203,7 @@ func archiveKube(zw *zip.Writer, baseDir string) error { wg.Add(1) go func(pod string) { defer wg.Done() - fs := getManifests(pod, baseDir) - ch <- fs + ch <- getManifests(ctx, pod, baseDir) }(pod.Metadata.Name) } @@ -204,29 +214,35 @@ func archiveKube(zw *zip.Writer, baseDir string) error { }() // write to archive all the outputs from kubectl call functions passed to buffer channel - for files := range ch { - for _, f := range files { - // write file path - zf, err := zw.Create(f.name) - if err != nil { - return fmt.Errorf("failed to create %s: %w", f.name, err) - } - _, err = zf.Write(f.data) - if err != nil { - return fmt.Errorf("failed to write to %s: %w", f.name, err) - } + for f := range ch { + if f.err != nil { + return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) + } + + if verbose { + log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) + } + + zf, err := zw.Create(f.name) + if err != nil { + return fmt.Errorf("failed to create %s: %w", f.name, err) + } + + _, err = zf.Write(f.data) + if err != nil { + return fmt.Errorf("failed to write to %s: %w", f.name, err) } } return nil } -func getPods() (podList, error) { +func getPods(ctx context.Context) (podList, error) { // Declare buffer type var for kubectl pipe var podsBuff bytes.Buffer // Get all pod names as json - getPods := exec.Command("kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") + getPods := exec.CommandContext(ctx, "kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") getPods.Stdout = &podsBuff getPods.Stderr = os.Stderr err := getPods.Run() @@ -242,48 +258,63 @@ func getPods() (podList, error) { return pods, err } -func getEvents(baseDir string) (fs []archiveFile) { - f := archiveFile{name: baseDir + "/kubectl/events.txt"} - f.data, f.err = exec.Command("kubectl", "get", "events", "--all-namespaces").CombinedOutput() - return []archiveFile{f} +func getEvents(ctx context.Context, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/events.txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "events", "--all-namespaces").CombinedOutput() + return f } -func getPV(baseDir string) (fs []archiveFile) { - f := archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} - f.data, f.err = exec.Command("kubectl", "get", "pv").CombinedOutput() - return []archiveFile{f} +func getPV(ctx context.Context, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pv").CombinedOutput() + return f } -func getPVC(baseDir string) (fs []archiveFile) { - f := archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} - f.data, f.err = exec.Command("kubectl", "get", "pvc").CombinedOutput() - return []archiveFile{f} +func getPVC(ctx context.Context, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pvc").CombinedOutput() + return f } // get kubectl logs for pod containers -func getContainerLogs(podName string, containerName string, baseDir string) (fs []archiveFile) { - f := archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} - f.data, f.err = exec.Command("kubectl", "logs", podName, "-c", containerName).CombinedOutput() - return []archiveFile{f} +func getContainerLogs(ctx context.Context, podName, containerName, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", podName, "-c", containerName).CombinedOutput() + return f } // get kubectl logs for past container -func getPastContainerLogs(podName string, containerName string, baseDir string) (fs []archiveFile) { - f := archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} - f.data, f.err = exec.Command("kubectl", "logs", "--previous", podName, "-c", containerName).CombinedOutput() - return []archiveFile{f} +func getPastContainerLogs(ctx context.Context, podName, containerName, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", "--previous", podName, "-c", containerName).CombinedOutput() + return f +} + +func getDescribes(ctx context.Context, podName, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "describe", "pod", podName).CombinedOutput() + return f } -func getDescribes(podName string, baseDir string) (fs []archiveFile) { - f := archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} - f.data, f.err = exec.Command("kubectl", "describe", "pod", podName).CombinedOutput() - return []archiveFile{f} +func getManifests(ctx context.Context, podName, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pod", podName, "-o", "yaml").CombinedOutput() + return f } -func getManifests(podName string, baseDir string) (fs []archiveFile) { - f := archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} - f.data, f.err = exec.Command("kubectl", "get", "pod", podName, "-o", "yaml").CombinedOutput() - return []archiveFile{f} +// setOpenFileLimits increases the limit of open files to the given number. This is needed +// when doings lots of concurrent network requests which establish open sockets. +func setOpenFileLimits(n int) error { + var rlimit syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) + if err != nil { + return err + } + + rlimit.Max = 999999 + rlimit.Cur = 999999 + + return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) } /* @@ -292,9 +323,9 @@ Docker functions */ -func getContainers() (string, error) { +func getContainers(ctx context.Context) (string, error) { - containers, err := exec.Command("docker", "container", "ls", "--format", "{{.Names}}").Output() + containers, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}}").Output() if err != nil { fmt.Errorf("failed to get container names with error: %w", err) } @@ -339,7 +370,7 @@ Graveyard // return fmt.Errorf("failed to create podLogs.txt: %w", err) // } // -// getLogs := exec.Command("kubectl", "logs", pod.Metadata.Name, "-c", container.Name) +// getLogs := exec.CommandContext(ctx, "kubectl", "logs", pod.Metadata.Name, "-c", container.Name) // getLogs.Stdout = logs // getLogs.Stderr = os.Stderr // @@ -352,7 +383,7 @@ Graveyard // // run kubectl logs --previous and write to archive if return not err // for _, pod := range pods.Items { // for _, container := range pod.Spec.Containers { -// getPrevLogs := exec.Command("kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) +// getPrevLogs := exec.CommandContext(ctx, "kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) // if err := getPrevLogs.Run(); err == nil { // fmt.Println("Archiving previous logs: ", pod.Metadata.Name, "Containers: ", pod.Spec.Containers) // prev, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".log") @@ -374,7 +405,7 @@ Graveyard // return fmt.Errorf("failed to create manifest.yaml: %w", err) // } // -// getManifest := exec.Command("kubectl", "get", "pod", pod.Metadata.Name, "-o", "yaml") +// getManifest := exec.CommandContext(ctx, "kubectl", "get", "pod", pod.Metadata.Name, "-o", "yaml") // getManifest.Stdout = manifests // getManifest.Stderr = os.Stderr // From 533c545ff7418a7844cdfb18b1f52881f4ce7c44 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 31 Aug 2021 08:58:10 -0700 Subject: [PATCH 037/107] add todo for logging --- cmd/src/debug.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 3fc47b127e..698514ee63 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -108,9 +108,7 @@ USAGE /* Kubernetes functions -TODO: improve logging as kubectl calls run (Desc, Mani) -TODO: refactor archiveLLogs so that both logs and logs --past are collected in the same loop -TODO: refactor archive functions to run concurrently as goroutines +TODO: improve logging as kubectl calls run */ // Run kubectl functions concurrently and archive results to zip file From 2d91a3537bd3f32e40e4583e018c69f14a122159 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 31 Aug 2021 11:05:19 -0700 Subject: [PATCH 038/107] fixed hardcoding 999999 in setOpenFileLimits --- cmd/src/debug.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 321d12059d..fa17ab0425 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -78,7 +78,7 @@ USAGE return fmt.Errorf("failed to open file: %w", err) } - if err := setOpenFileLimits(99999); err != nil { + if err := setOpenFileLimits(64000); err != nil { return fmt.Errorf("failed to set open file limits: %w", err) } @@ -302,15 +302,15 @@ func getManifests(ctx context.Context, podName, baseDir string) *archiveFile { // setOpenFileLimits increases the limit of open files to the given number. This is needed // when doings lots of concurrent network requests which establish open sockets. -func setOpenFileLimits(n int) error { +func setOpenFileLimits(n uint64) error { var rlimit syscall.Rlimit err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) if err != nil { return err } - rlimit.Max = 999999 - rlimit.Cur = 999999 + rlimit.Max = n + rlimit.Cur = n return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) } From a3c997702f65d6ad0d0c18868cd01b61118ab2a0 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 1 Sep 2021 23:31:47 -0700 Subject: [PATCH 039/107] removed plural k8s func names, started work on docker commands --- cmd/src/debug.go | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index fa17ab0425..970263c98b 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -167,7 +167,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri wg.Add(1) go func(pod, container string) { defer wg.Done() - ch <- getContainerLogs(ctx, pod, container, baseDir) + ch <- getContainerLog(ctx, pod, container, baseDir) }(pod.Metadata.Name, container.Name) } } @@ -179,7 +179,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri wg.Add(1) go func(pod, container string) { defer wg.Done() - f := getPastContainerLogs(ctx, pod, container, baseDir) + f := getPastContainerLog(ctx, pod, container, baseDir) if f.err == nil { ch <- f } @@ -192,7 +192,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri wg.Add(1) go func(pod string) { defer wg.Done() - ch <- getDescribes(ctx, pod, baseDir) + ch <- getDescribe(ctx, pod, baseDir) }(pod.Metadata.Name) } @@ -201,7 +201,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri wg.Add(1) go func(pod string) { defer wg.Done() - ch <- getManifests(ctx, pod, baseDir) + ch <- getManifest(ctx, pod, baseDir) }(pod.Metadata.Name) } @@ -275,26 +275,26 @@ func getPVC(ctx context.Context, baseDir string) *archiveFile { } // get kubectl logs for pod containers -func getContainerLogs(ctx context.Context, podName, containerName, baseDir string) *archiveFile { +func getContainerLog(ctx context.Context, podName, containerName, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", podName, "-c", containerName).CombinedOutput() return f } // get kubectl logs for past container -func getPastContainerLogs(ctx context.Context, podName, containerName, baseDir string) *archiveFile { +func getPastContainerLog(ctx context.Context, podName, containerName, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", "--previous", podName, "-c", containerName).CombinedOutput() return f } -func getDescribes(ctx context.Context, podName, baseDir string) *archiveFile { +func getDescribe(ctx context.Context, podName, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} f.data, f.err = exec.CommandContext(ctx, "kubectl", "describe", "pod", podName).CombinedOutput() return f } -func getManifests(ctx context.Context, podName, baseDir string) *archiveFile { +func getManifest(ctx context.Context, podName, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pod", podName, "-o", "yaml").CombinedOutput() return f @@ -318,18 +318,28 @@ func setOpenFileLimits(n uint64) error { /* Docker functions - */ -func getContainers(ctx context.Context) (string, error) { +func archiveDocker() { + fmt.Println("This will execute all docker cli commands as goroutines and ") +} + +func getContainers(ctx context.Context) ([]string, error) { - containers, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}}").Output() + c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}}").Output() if err != nil { fmt.Errorf("failed to get container names with error: %w", err) } - contStr := string(containers) - fmt.Println(contStr) - return contStr, err + s := string(c) + containers := strings.Split(s, "\n") + fmt.Println(containers) + return containers, err +} + +func getLog(ctx context.Context, container, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/" + container + ".log"} + f.data, f.err = exec.CommandContext(ctx, "docker", "container", "logs", container).CombinedOutput() + return f } /* From 709817cca19e25ac8a26cbc21bd108c0a675b9e5 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 2 Sep 2021 00:11:46 -0700 Subject: [PATCH 040/107] working log archival for docker containers --- cmd/src/debug.go | 91 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 18 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 970263c98b..3e6ed1f0da 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -91,9 +91,13 @@ USAGE // TODO write functions for sourcegraph server and docker-compose instances switch *deployment { case "serv": - getContainers(ctx) + if err := archiveDocker(ctx, zw, *verbose, baseDir); err != nil { + return fmt.Errorf("archiveDocker failed with err: %w", err) + } case "comp": - getContainers(ctx) + if err := archiveDocker(ctx, zw, *verbose, baseDir); err != nil { + return fmt.Errorf("archiveDocker failed with err: %w", err) + } case "kube": if err := archiveKube(ctx, zw, *verbose, baseDir); err != nil { return fmt.Errorf("archiveKube failed with err: %w", err) @@ -114,9 +118,24 @@ USAGE }) } +// setOpenFileLimits increases the limit of open files to the given number. This is needed +// when doings lots of concurrent network requests which establish open sockets. +func setOpenFileLimits(n uint64) error { + var rlimit syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) + if err != nil { + return err + } + + rlimit.Max = n + rlimit.Cur = n + + return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) +} + /* Kubernetes functions -TODO: improve logging as kubectl calls run +TODO: handle namespaces */ // Run kubectl functions concurrently and archive results to zip file @@ -300,28 +319,63 @@ func getManifest(ctx context.Context, podName, baseDir string) *archiveFile { return f } -// setOpenFileLimits increases the limit of open files to the given number. This is needed -// when doings lots of concurrent network requests which establish open sockets. -func setOpenFileLimits(n uint64) error { - var rlimit syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) +/* +Docker functions + +*/ + +func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir string) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + containers, err := getContainers(ctx) if err != nil { - return err + return fmt.Errorf("failed to get docker containers: %w", err) } - rlimit.Max = n - rlimit.Cur = n + if verbose { + log.Printf("getting docker data for %d containers...\n", len(containers)) + } - return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) -} + // setup channel for slice of archive function outputs + ch := make(chan *archiveFile) + wg := sync.WaitGroup{} -/* -Docker functions + for _, container := range containers { + wg.Add(1) + go func(container string) { + defer wg.Done() + ch <- getLog(ctx, container, baseDir) + }(container) + } -*/ + // close channel when wait group goroutines have completed + go func() { + wg.Wait() + close(ch) + }() + + for f := range ch { + if f.err != nil { + return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) + } + + if verbose { + log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) + } + + zf, err := zw.Create(f.name) + if err != nil { + return fmt.Errorf("failed to create %s: %w", f.name, err) + } -func archiveDocker() { - fmt.Println("This will execute all docker cli commands as goroutines and ") + _, err = zf.Write(f.data) + if err != nil { + return fmt.Errorf("failed to write to %s: %w", f.name, err) + } + } + + return nil } func getContainers(ctx context.Context) ([]string, error) { @@ -332,6 +386,7 @@ func getContainers(ctx context.Context) ([]string, error) { } s := string(c) containers := strings.Split(s, "\n") + containers = containers[:len(containers)-1] fmt.Println(containers) return containers, err } From edbe9532a18e9e87ca6b9e32d9d09ab196810f13 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 2 Sep 2021 21:44:30 -0700 Subject: [PATCH 041/107] added docker inspect --- cmd/src/debug.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 3e6ed1f0da..37d23de692 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -341,6 +341,7 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir st ch := make(chan *archiveFile) wg := sync.WaitGroup{} + // start goroutine to run docker container logs for _, container := range containers { wg.Add(1) go func(container string) { @@ -349,6 +350,15 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir st }(container) } + // start goroutine to run docker container inspect + for _, container := range containers { + wg.Add(1) + go func(container string) { + defer wg.Done() + ch <- getInspect(ctx, container, baseDir) + }(container) + } + // close channel when wait group goroutines have completed go func() { wg.Wait() @@ -397,6 +407,12 @@ func getLog(ctx context.Context, container, baseDir string) *archiveFile { return f } +func getInspect(ctx context.Context, container, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/inspect-" + container + ".txt"} + f.data, f.err = exec.CommandContext(ctx, "docker", "container", "inspect", container).CombinedOutput() + return f +} + /* Graveyard ----------- From 419d194cf49e75bafe049d3f53fd02ea626f36f7 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 2 Sep 2021 21:57:13 -0700 Subject: [PATCH 042/107] added docker container stats --- cmd/src/debug.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 37d23de692..53c5c31d1b 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -341,6 +341,13 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir st ch := make(chan *archiveFile) wg := sync.WaitGroup{} + // start goroutine to run docker container stats --no-stream + wg.Add(1) + go func() { + defer wg.Done() + ch <- getStats(ctx, baseDir) + }() + // start goroutine to run docker container logs for _, container := range containers { wg.Add(1) @@ -413,6 +420,12 @@ func getInspect(ctx context.Context, container, baseDir string) *archiveFile { return f } +func getStats(ctx context.Context, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/docker/stats.txt"} + f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() + return f +} + /* Graveyard ----------- From 8a6aa2a3c301dc049d3684718d715809c15bbd49 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 7 Sep 2021 14:34:29 -0700 Subject: [PATCH 043/107] improved logic for get containers --- cmd/src/debug.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 53c5c31d1b..919149ff54 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -396,14 +396,12 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir st } func getContainers(ctx context.Context) ([]string, error) { - c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}}").Output() if err != nil { fmt.Errorf("failed to get container names with error: %w", err) } s := string(c) - containers := strings.Split(s, "\n") - containers = containers[:len(containers)-1] + containers := strings.Split(strings.TrimSpace(s), "\n") fmt.Println(containers) return containers, err } From e2cdff3f83a3f65095cfb36bf37ab0662ab55e35 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 30 Sep 2021 00:56:08 -0700 Subject: [PATCH 044/107] cleanup --- cmd/src/debug.go | 89 ++---------------------------------------------- 1 file changed, 3 insertions(+), 86 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 919149ff54..45ad72c77a 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -43,7 +43,7 @@ func init() { fmt.Fprintf(flag.CommandLine.Output(), `'src debug' gathers and bundles debug data from a Sourcegraph deployment. -USAGE +Usage: src [-v] debug -d= [-out=debug.zip] `) } @@ -88,7 +88,6 @@ USAGE defer zw.Close() ctx := context.Background() - // TODO write functions for sourcegraph server and docker-compose instances switch *deployment { case "serv": if err := archiveDocker(ctx, zw, *verbose, baseDir); err != nil { @@ -103,7 +102,7 @@ USAGE return fmt.Errorf("archiveKube failed with err: %w", err) } default: - return fmt.Errorf("must declare -d=, as serv, comp, or kube") + return fmt.Errorf("please declare -d=, as serv, comp, or kube") } return nil @@ -321,7 +320,7 @@ func getManifest(ctx context.Context, podName, baseDir string) *archiveFile { /* Docker functions - +TODO: handle for single container instance */ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir string) error { @@ -423,85 +422,3 @@ func getStats(ctx context.Context, baseDir string) *archiveFile { f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() return f } - -/* -Graveyard ------------ -*/ - -//if err := archiveEvents(zw, baseDir); err != nil { -// return fmt.Errorf("running archiveEvents failed: %w", err) -//} -//if err := archivePV(zw, baseDir); err != nil { -// return fmt.Errorf("running archivePV failed: %w", err) -//} -//if err := archivePVC(zw, baseDir); err != nil { -// return fmt.Errorf("running archivePV failed: %w", err) -//} -//if err := archiveLogs(zw, pods, baseDir); err != nil { -// return fmt.Errorf("running archiveLogs failed: %w", err) -//} -//if err := archiveDescribes(zw, pods, baseDir); err != nil { -// return fmt.Errorf("running archiveDescribes failed: %w", err) -//} -//if err := archiveManifests(zw, pods, baseDir); err != nil { -// return fmt.Errorf("running archiveManifests failed: %w", err) -//} - -//// gets current pod logs and logs from past containers -//func getLogs(pods podList, baseDir string) (fs []archiveFile) { -// -// // run kubectl logs and write to archive, accounts for containers in pod -// for _, pod := range pods.Items { -// fmt.Println("Archiving logs: ", pod.Metadata.Name, "Containers:", pod.Spec.Containers) -// for _, container := range pod.Spec.Containers { -// logs, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + container.Name + ".log") -// if err != nil { -// return fmt.Errorf("failed to create podLogs.txt: %w", err) -// } -// -// getLogs := exec.CommandContext(ctx, "kubectl", "logs", pod.Metadata.Name, "-c", container.Name) -// getLogs.Stdout = logs -// getLogs.Stderr = os.Stderr -// -// if err := getLogs.Run(); err != nil { -// return fmt.Errorf("running kubectl get logs failed: %w", err) -// } -// } -// } -// -// // run kubectl logs --previous and write to archive if return not err -// for _, pod := range pods.Items { -// for _, container := range pod.Spec.Containers { -// getPrevLogs := exec.CommandContext(ctx, "kubectl", "logs", "--previous", pod.Metadata.Name, "-c", container.Name) -// if err := getPrevLogs.Run(); err == nil { -// fmt.Println("Archiving previous logs: ", pod.Metadata.Name, "Containers: ", pod.Spec.Containers) -// prev, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/" + "prev-" + container.Name + ".log") -// getPrevLogs.Stdout = prev -// if err != nil { -// return fmt.Errorf("failed to create podLogs.txt: %w", err) -// } -// } -// } -// } -// -// return nil -//} - -//func archiveManifests(zw *zip.Writer, pods podList, baseDir string) error { -// for _, pod := range pods.Items { -// manifests, err := zw.Create(baseDir + "/kubectl/pods/" + pod.Metadata.Name + "/manifest-" + pod.Metadata.Name + ".yaml") -// if err != nil { -// return fmt.Errorf("failed to create manifest.yaml: %w", err) -// } -// -// getManifest := exec.CommandContext(ctx, "kubectl", "get", "pod", pod.Metadata.Name, "-o", "yaml") -// getManifest.Stdout = manifests -// getManifest.Stderr = os.Stderr -// -// if err := getManifest.Run(); err != nil { -// fmt.Errorf("failed to get pod yaml: %w", err) -// } -// } -// return nil -//} From 877fedc9514214b24e410ca966de28950b6eec0a Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 30 Sep 2021 01:14:04 -0700 Subject: [PATCH 045/107] clarify assumptions --- cmd/src/debug.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 45ad72c77a..9f9c90a5b1 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -42,6 +42,9 @@ func init() { usageFunc := func() { fmt.Fprintf(flag.CommandLine.Output(), `'src debug' gathers and bundles debug data from a Sourcegraph deployment. +The debug flag requires the specification of a deployment via the -d flag. '-d' accepts serv, comp, and kube as arguments. + +'debug' assumes that sourcegraph is being run in a single tenant cluster, and that containers running on the host machine are all associated with Sourcegraph. Usage: src [-v] debug -d= [-out=debug.zip] @@ -134,7 +137,7 @@ func setOpenFileLimits(n uint64) error { /* Kubernetes functions -TODO: handle namespaces +TODO: handle namespaces, remove --all-namespaces from get events */ // Run kubectl functions concurrently and archive results to zip file From 662c14244d5bc1823206c68958240553743ca81b Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Sun, 21 Nov 2021 23:27:56 -0800 Subject: [PATCH 046/107] introduced debug sub commands kube, comp, and serv -- Ex: src debug kube -out=test --- cmd/src/debug.go | 421 +++-------------------------------------------- 1 file changed, 19 insertions(+), 402 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 9f9c90a5b1..8442a93e37 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -1,427 +1,44 @@ package main import ( - "archive/zip" - "bytes" - "context" - "encoding/json" "flag" "fmt" - "log" - "os" - "strings" - "sync" - "syscall" - - "github.com/sourcegraph/src-cli/internal/exec" ) -type podList struct { - Items []struct { - Metadata struct { - Name string - } - Spec struct { - Containers []struct { - Name string - } - } - } -} - -type archiveFile struct { - name string - data []byte - err error -} +var debugCommands commander -// Init debug flag on src build func init() { - flagSet := flag.NewFlagSet("debug", flag.ExitOnError) - - usageFunc := func() { - - fmt.Fprintf(flag.CommandLine.Output(), `'src debug' gathers and bundles debug data from a Sourcegraph deployment. -The debug flag requires the specification of a deployment via the -d flag. '-d' accepts serv, comp, and kube as arguments. - -'debug' assumes that sourcegraph is being run in a single tenant cluster, and that containers running on the host machine are all associated with Sourcegraph. + usage := `'src debug' gathers and bundles debug data from a Sourcegraph deployment for troubleshooting. Usage: - src [-v] debug -d= [-out=debug.zip] -`) - } - - // store value passed to flags - var ( - deployment = flagSet.String("d", "", "deployment type") - base = flagSet.String("out", "debug.zip", "The name of the output zip archive") - ) - - handler := func(args []string) error { - if err := flagSet.Parse(args); err != nil { - return err - } - //validate out flag - if *base == "" { - return fmt.Errorf("empty -out flag") - } - // declare basedir for archive file structure - var baseDir string - if strings.HasSuffix(*base, ".zip") == false { - baseDir = *base - *base = *base + ".zip" - } else { - baseDir = strings.TrimSuffix(*base, ".zip") - } + src debug command [command options] - // open pipe to output file - out, err := os.OpenFile(*base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) - if err != nil { - return fmt.Errorf("failed to open file: %w", err) - } +The commands are: - if err := setOpenFileLimits(64000); err != nil { - return fmt.Errorf("failed to set open file limits: %w", err) - } + kube generates kubectl outputs + comp generates docker outputs + serv generates docker outputs + - // open zip writer - defer out.Close() - zw := zip.NewWriter(out) - defer zw.Close() +Use "src debug [command] -h" for more information about a command. - ctx := context.Background() - switch *deployment { - case "serv": - if err := archiveDocker(ctx, zw, *verbose, baseDir); err != nil { - return fmt.Errorf("archiveDocker failed with err: %w", err) - } - case "comp": - if err := archiveDocker(ctx, zw, *verbose, baseDir); err != nil { - return fmt.Errorf("archiveDocker failed with err: %w", err) - } - case "kube": - if err := archiveKube(ctx, zw, *verbose, baseDir); err != nil { - return fmt.Errorf("archiveKube failed with err: %w", err) - } - default: - return fmt.Errorf("please declare -d=, as serv, comp, or kube") - } +` + flagSet := flag.NewFlagSet("debug", flag.ExitOnError) + handler := func(args []string) error { + debugCommands.run(flagSet, "src debug", usage, args) return nil } // Register the command. commands = append(commands, &command{ - aliases: []string{"debug-dump"}, - flagSet: flagSet, + flagSet: flagSet, + aliases: []string{ + "debug-dump", + "debugger", + }, handler: handler, - usageFunc: usageFunc, + usageFunc: func() { fmt.Println(usage) }, }) } - -// setOpenFileLimits increases the limit of open files to the given number. This is needed -// when doings lots of concurrent network requests which establish open sockets. -func setOpenFileLimits(n uint64) error { - var rlimit syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) - if err != nil { - return err - } - - rlimit.Max = n - rlimit.Cur = n - - return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) -} - -/* -Kubernetes functions -TODO: handle namespaces, remove --all-namespaces from get events -*/ - -// Run kubectl functions concurrently and archive results to zip file -func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir string) error { - // Create a context with a cancel function that we call when returning - // from archiveKube. This ensures we close all pending go-routines when returning - // early because of an error. - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - pods, err := getPods(ctx) - if err != nil { - return fmt.Errorf("failed to get pods: %w", err) - } - - if verbose { - log.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) - } - - // setup channel for slice of archive function outputs - ch := make(chan *archiveFile) - wg := sync.WaitGroup{} - - // create goroutine to get kubectl events - wg.Add(1) - go func() { - defer wg.Done() - ch <- getEvents(ctx, baseDir) - }() - - // create goroutine to get persistent volumes - wg.Add(1) - go func() { - defer wg.Done() - ch <- getPV(ctx, baseDir) - }() - - // create goroutine to get persistent volumes claim - wg.Add(1) - go func() { - defer wg.Done() - ch <- getPVC(ctx, baseDir) - }() - - // start goroutine to run kubectl logs for each pod's container's - for _, pod := range pods.Items { - for _, container := range pod.Spec.Containers { - wg.Add(1) - go func(pod, container string) { - defer wg.Done() - ch <- getContainerLog(ctx, pod, container, baseDir) - }(pod.Metadata.Name, container.Name) - } - } - - // start goroutine to run kubectl logs --previous for each pod's container's - // won't write to zip on err, only passes bytes to channel if err not nil - for _, pod := range pods.Items { - for _, container := range pod.Spec.Containers { - wg.Add(1) - go func(pod, container string) { - defer wg.Done() - f := getPastContainerLog(ctx, pod, container, baseDir) - if f.err == nil { - ch <- f - } - }(pod.Metadata.Name, container.Name) - } - } - - // start goroutine for each pod to run kubectl describe pod - for _, pod := range pods.Items { - wg.Add(1) - go func(pod string) { - defer wg.Done() - ch <- getDescribe(ctx, pod, baseDir) - }(pod.Metadata.Name) - } - - // start goroutine for each pod to run kubectl get pod -o yaml - for _, pod := range pods.Items { - wg.Add(1) - go func(pod string) { - defer wg.Done() - ch <- getManifest(ctx, pod, baseDir) - }(pod.Metadata.Name) - } - - // close channel when wait group goroutines have completed - go func() { - wg.Wait() - close(ch) - }() - - // write to archive all the outputs from kubectl call functions passed to buffer channel - for f := range ch { - if f.err != nil { - return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) - } - - if verbose { - log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) - } - - zf, err := zw.Create(f.name) - if err != nil { - return fmt.Errorf("failed to create %s: %w", f.name, err) - } - - _, err = zf.Write(f.data) - if err != nil { - return fmt.Errorf("failed to write to %s: %w", f.name, err) - } - } - - return nil -} - -func getPods(ctx context.Context) (podList, error) { - // Declare buffer type var for kubectl pipe - var podsBuff bytes.Buffer - - // Get all pod names as json - getPods := exec.CommandContext(ctx, "kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") - getPods.Stdout = &podsBuff - getPods.Stderr = os.Stderr - err := getPods.Run() - - //Declare struct to format decode from podList - var pods podList - - //Decode json from podList - if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { - fmt.Errorf("failed to unmarshall get pods json: %w", err) - } - - return pods, err -} - -func getEvents(ctx context.Context, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/events.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "events", "--all-namespaces").CombinedOutput() - return f -} - -func getPV(ctx context.Context, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pv").CombinedOutput() - return f -} - -func getPVC(ctx context.Context, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pvc").CombinedOutput() - return f -} - -// get kubectl logs for pod containers -func getContainerLog(ctx context.Context, podName, containerName, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", podName, "-c", containerName).CombinedOutput() - return f -} - -// get kubectl logs for past container -func getPastContainerLog(ctx context.Context, podName, containerName, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", "--previous", podName, "-c", containerName).CombinedOutput() - return f -} - -func getDescribe(ctx context.Context, podName, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "describe", "pod", podName).CombinedOutput() - return f -} - -func getManifest(ctx context.Context, podName, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pod", podName, "-o", "yaml").CombinedOutput() - return f -} - -/* -Docker functions -TODO: handle for single container instance -*/ - -func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir string) error { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - containers, err := getContainers(ctx) - if err != nil { - return fmt.Errorf("failed to get docker containers: %w", err) - } - - if verbose { - log.Printf("getting docker data for %d containers...\n", len(containers)) - } - - // setup channel for slice of archive function outputs - ch := make(chan *archiveFile) - wg := sync.WaitGroup{} - - // start goroutine to run docker container stats --no-stream - wg.Add(1) - go func() { - defer wg.Done() - ch <- getStats(ctx, baseDir) - }() - - // start goroutine to run docker container logs - for _, container := range containers { - wg.Add(1) - go func(container string) { - defer wg.Done() - ch <- getLog(ctx, container, baseDir) - }(container) - } - - // start goroutine to run docker container inspect - for _, container := range containers { - wg.Add(1) - go func(container string) { - defer wg.Done() - ch <- getInspect(ctx, container, baseDir) - }(container) - } - - // close channel when wait group goroutines have completed - go func() { - wg.Wait() - close(ch) - }() - - for f := range ch { - if f.err != nil { - return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) - } - - if verbose { - log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) - } - - zf, err := zw.Create(f.name) - if err != nil { - return fmt.Errorf("failed to create %s: %w", f.name, err) - } - - _, err = zf.Write(f.data) - if err != nil { - return fmt.Errorf("failed to write to %s: %w", f.name, err) - } - } - - return nil -} - -func getContainers(ctx context.Context) ([]string, error) { - c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}}").Output() - if err != nil { - fmt.Errorf("failed to get container names with error: %w", err) - } - s := string(c) - containers := strings.Split(strings.TrimSpace(s), "\n") - fmt.Println(containers) - return containers, err -} - -func getLog(ctx context.Context, container, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/" + container + ".log"} - f.data, f.err = exec.CommandContext(ctx, "docker", "container", "logs", container).CombinedOutput() - return f -} - -func getInspect(ctx context.Context, container, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/inspect-" + container + ".txt"} - f.data, f.err = exec.CommandContext(ctx, "docker", "container", "inspect", container).CombinedOutput() - return f -} - -func getStats(ctx context.Context, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/docker/stats.txt"} - f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() - return f -} From b96532ad5c184510cca4d680765d3132facde817 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Sun, 21 Nov 2021 23:35:24 -0800 Subject: [PATCH 047/107] for some reason my .gitignore was ignoring these new files --- cmd/src/debug_common.go | 357 ++++++++++++++++++++++++++++++++++++++++ cmd/src/debug_comp.go | 71 ++++++++ cmd/src/debug_kube.go | 71 ++++++++ cmd/src/debug_serv.go | 71 ++++++++ 4 files changed, 570 insertions(+) create mode 100644 cmd/src/debug_common.go create mode 100644 cmd/src/debug_comp.go create mode 100644 cmd/src/debug_kube.go create mode 100644 cmd/src/debug_serv.go diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go new file mode 100644 index 0000000000..d53c0a8402 --- /dev/null +++ b/cmd/src/debug_common.go @@ -0,0 +1,357 @@ +package main + +import ( + "archive/zip" + "bytes" + "context" + "encoding/json" + "fmt" + "log" + "os" + "strings" + "sync" + "syscall" + + "github.com/sourcegraph/src-cli/internal/exec" +) + +type archiveFile struct { + name string + data []byte + err error +} + +// setOpenFileLimits increases the limit of open files to the given number. This is needed +// when doings lots of concurrent network requests which establish open sockets. +func setOpenFileLimits(n uint64) error { + var rlimit syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) + if err != nil { + return err + } + + rlimit.Max = n + rlimit.Cur = n + + return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) +} + +// setupDebug takes the name of a base directory and returns the file pipe, zip writer, +// and context needed for later archive functions. Don't forget to defer close on these +// after calling setupDebug! +func setupDebug(base string) (*os.File, *zip.Writer, context.Context, error) { + // open pipe to output file + out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) + // increase limit of open files + err = setOpenFileLimits(64000) + // init zip writer + zw := zip.NewWriter(out) + // init context + ctx := context.Background() + + return out, zw, ctx, err +} + +/* +Kubernetes stuff +TODO: handle namespaces, remove --all-namespaces from get events +*/ + +type podList struct { + Items []struct { + Metadata struct { + Name string + } + Spec struct { + Containers []struct { + Name string + } + } + } +} + +// Run kubectl functions concurrently and archive results to zip file +func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir string) error { + // Create a context with a cancel function that we call when returning + // from archiveKube. This ensures we close all pending go-routines when returning + // early because of an error. + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + pods, err := getPods(ctx) + if err != nil { + return fmt.Errorf("failed to get pods: %w", err) + } + + if verbose { + log.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) + } + + // setup channel for slice of archive function outputs + ch := make(chan *archiveFile) + wg := sync.WaitGroup{} + + // create goroutine to get kubectl events + wg.Add(1) + go func() { + defer wg.Done() + ch <- getEvents(ctx, baseDir) + }() + + // create goroutine to get persistent volumes + wg.Add(1) + go func() { + defer wg.Done() + ch <- getPV(ctx, baseDir) + }() + + // create goroutine to get persistent volumes claim + wg.Add(1) + go func() { + defer wg.Done() + ch <- getPVC(ctx, baseDir) + }() + + // start goroutine to run kubectl logs for each pod's container's + for _, pod := range pods.Items { + for _, container := range pod.Spec.Containers { + wg.Add(1) + go func(pod, container string) { + defer wg.Done() + ch <- getContainerLog(ctx, pod, container, baseDir) + }(pod.Metadata.Name, container.Name) + } + } + + // start goroutine to run kubectl logs --previous for each pod's container's + // won't write to zip on err, only passes bytes to channel if err not nil + for _, pod := range pods.Items { + for _, container := range pod.Spec.Containers { + wg.Add(1) + go func(pod, container string) { + defer wg.Done() + f := getPastContainerLog(ctx, pod, container, baseDir) + if f.err == nil { + ch <- f + } + }(pod.Metadata.Name, container.Name) + } + } + + // start goroutine for each pod to run kubectl describe pod + for _, pod := range pods.Items { + wg.Add(1) + go func(pod string) { + defer wg.Done() + ch <- getDescribe(ctx, pod, baseDir) + }(pod.Metadata.Name) + } + + // start goroutine for each pod to run kubectl get pod -o yaml + for _, pod := range pods.Items { + wg.Add(1) + go func(pod string) { + defer wg.Done() + ch <- getManifest(ctx, pod, baseDir) + }(pod.Metadata.Name) + } + + // close channel when wait group goroutines have completed + go func() { + wg.Wait() + close(ch) + }() + + // write to archive all the outputs from kubectl call functions passed to buffer channel + for f := range ch { + if f.err != nil { + return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) + } + + if verbose { + log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) + } + + zf, err := zw.Create(f.name) + if err != nil { + return fmt.Errorf("failed to create %s: %w", f.name, err) + } + + _, err = zf.Write(f.data) + if err != nil { + return fmt.Errorf("failed to write to %s: %w", f.name, err) + } + } + + return nil +} + +func getPods(ctx context.Context) (podList, error) { + // Declare buffer type var for kubectl pipe + var podsBuff bytes.Buffer + + // Get all pod names as json + getPods := exec.CommandContext(ctx, "kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") + getPods.Stdout = &podsBuff + getPods.Stderr = os.Stderr + err := getPods.Run() + + //Declare struct to format decode from podList + var pods podList + + //Decode json from podList + if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { + fmt.Errorf("failed to unmarshall get pods json: %w", err) + } + + return pods, err +} + +func getEvents(ctx context.Context, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/events.txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "events", "--all-namespaces").CombinedOutput() + return f +} + +func getPV(ctx context.Context, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pv").CombinedOutput() + return f +} + +func getPVC(ctx context.Context, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pvc").CombinedOutput() + return f +} + +// get kubectl logs for pod containers +func getContainerLog(ctx context.Context, podName, containerName, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", podName, "-c", containerName).CombinedOutput() + return f +} + +// get kubectl logs for past container +func getPastContainerLog(ctx context.Context, podName, containerName, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", "--previous", podName, "-c", containerName).CombinedOutput() + return f +} + +func getDescribe(ctx context.Context, podName, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "describe", "pod", podName).CombinedOutput() + return f +} + +func getManifest(ctx context.Context, podName, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pod", podName, "-o", "yaml").CombinedOutput() + return f +} + +/* +Docker functions +TODO: handle for single container instance +*/ + +func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir string) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + containers, err := getContainers(ctx) + if err != nil { + return fmt.Errorf("failed to get docker containers: %w", err) + } + + if verbose { + log.Printf("getting docker data for %d containers...\n", len(containers)) + } + + // setup channel for slice of archive function outputs + ch := make(chan *archiveFile) + wg := sync.WaitGroup{} + + // start goroutine to run docker container stats --no-stream + wg.Add(1) + go func() { + defer wg.Done() + ch <- getStats(ctx, baseDir) + }() + + // start goroutine to run docker container logs + for _, container := range containers { + wg.Add(1) + go func(container string) { + defer wg.Done() + ch <- getLog(ctx, container, baseDir) + }(container) + } + + // start goroutine to run docker container inspect + for _, container := range containers { + wg.Add(1) + go func(container string) { + defer wg.Done() + ch <- getInspect(ctx, container, baseDir) + }(container) + } + + // close channel when wait group goroutines have completed + go func() { + wg.Wait() + close(ch) + }() + + for f := range ch { + if f.err != nil { + return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) + } + + if verbose { + log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) + } + + zf, err := zw.Create(f.name) + if err != nil { + return fmt.Errorf("failed to create %s: %w", f.name, err) + } + + _, err = zf.Write(f.data) + if err != nil { + return fmt.Errorf("failed to write to %s: %w", f.name, err) + } + } + + return nil +} + +func getContainers(ctx context.Context) ([]string, error) { + c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}}").Output() + if err != nil { + fmt.Errorf("failed to get container names with error: %w", err) + } + s := string(c) + containers := strings.Split(strings.TrimSpace(s), "\n") + fmt.Println(containers) + return containers, err +} + +func getLog(ctx context.Context, container, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/" + container + ".log"} + f.data, f.err = exec.CommandContext(ctx, "docker", "container", "logs", container).CombinedOutput() + return f +} + +func getInspect(ctx context.Context, container, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/inspect-" + container + ".txt"} + f.data, f.err = exec.CommandContext(ctx, "docker", "container", "inspect", container).CombinedOutput() + return f +} + +func getStats(ctx context.Context, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/docker/stats.txt"} + f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() + return f +} diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go new file mode 100644 index 0000000000..71fc9214d2 --- /dev/null +++ b/cmd/src/debug_comp.go @@ -0,0 +1,71 @@ +package main + +import ( + "flag" + "fmt" + "strings" + + "github.com/sourcegraph/src-cli/internal/cmderrors" +) + +func init() { + usage := ` +'src debug comp' mocks docker cli commands to gather information about a docker-compose Sourcegraph instance. + +Usage: + + src debug kube -o FILE [command options] + +Examples: + + $ src debug kube -o debug.zip + +` + + flagSet := flag.NewFlagSet("kube", flag.ExitOnError) + var ( + base = flagSet.String("out", "debug.zip", "The name of the output zip archive") + ) + + handler := func(args []string) error { + if err := flagSet.Parse(args); err != nil { + return err + } + + //validate out flag + if *base == "" { + return fmt.Errorf("empty -out flag") + } + // declare basedir for archive file structure + var baseDir string + if strings.HasSuffix(*base, ".zip") == false { + baseDir = *base + *base = *base + ".zip" + } else { + baseDir = strings.TrimSuffix(*base, ".zip") + } + + out, zw, ctx, err := setupDebug(*base) + if err != nil { + return fmt.Errorf("failed to open file: %w", err) + } + defer out.Close() + defer zw.Close() + + err = archiveDocker(ctx, zw, *verbose, baseDir) + if err != nil { + return cmderrors.ExitCode(1, nil) + } + return nil + } + + debugCommands = append(debugCommands, &command{ + flagSet: flagSet, + handler: handler, + usageFunc: func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src debug %s':\n", flagSet.Name()) + flagSet.PrintDefaults() + fmt.Println(usage) + }, + }) +} diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go new file mode 100644 index 0000000000..96e8d78e4f --- /dev/null +++ b/cmd/src/debug_kube.go @@ -0,0 +1,71 @@ +package main + +import ( + "flag" + "fmt" + "strings" + + "github.com/sourcegraph/src-cli/internal/cmderrors" +) + +func init() { + usage := ` +'src debug kube' mocks kubectl commands to gather information about a kubernetes sourcegraph instance. + +Usage: + + src debug kube -o FILE [command options] + +Examples: + + $ src debug kube -o debug.zip + +` + + flagSet := flag.NewFlagSet("kube", flag.ExitOnError) + var ( + base = flagSet.String("out", "debug.zip", "The name of the output zip archive") + ) + + handler := func(args []string) error { + if err := flagSet.Parse(args); err != nil { + return err + } + + //validate out flag + if *base == "" { + return fmt.Errorf("empty -out flag") + } + // declare basedir for archive file structure + var baseDir string + if strings.HasSuffix(*base, ".zip") == false { + baseDir = *base + *base = *base + ".zip" + } else { + baseDir = strings.TrimSuffix(*base, ".zip") + } + + out, zw, ctx, err := setupDebug(*base) + if err != nil { + return fmt.Errorf("failed to open file: %w", err) + } + defer out.Close() + defer zw.Close() + + err = archiveKube(ctx, zw, *verbose, baseDir) + if err != nil { + return cmderrors.ExitCode(1, nil) + } + return nil + } + + debugCommands = append(batchCommands, &command{ + flagSet: flagSet, + handler: handler, + usageFunc: func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src debug %s':\n", flagSet.Name()) + flagSet.PrintDefaults() + fmt.Println(usage) + }, + }) +} diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go new file mode 100644 index 0000000000..206b163943 --- /dev/null +++ b/cmd/src/debug_serv.go @@ -0,0 +1,71 @@ +package main + +import ( + "flag" + "fmt" + "strings" + + "github.com/sourcegraph/src-cli/internal/cmderrors" +) + +func init() { + usage := ` +'src debug serv' mocks docker cli commands to gather information about a Sourcegraph server instance. + +Usage: + + src debug kube -o FILE [command options] + +Examples: + + $ src debug kube -o debug.zip + +` + + flagSet := flag.NewFlagSet("kube", flag.ExitOnError) + var ( + base = flagSet.String("out", "debug.zip", "The name of the output zip archive") + ) + + handler := func(args []string) error { + if err := flagSet.Parse(args); err != nil { + return err + } + + //validate out flag + if *base == "" { + return fmt.Errorf("empty -out flag") + } + // declare basedir for archive file structure + var baseDir string + if strings.HasSuffix(*base, ".zip") == false { + baseDir = *base + *base = *base + ".zip" + } else { + baseDir = strings.TrimSuffix(*base, ".zip") + } + + out, zw, ctx, err := setupDebug(*base) + if err != nil { + return fmt.Errorf("failed to open file: %w", err) + } + defer out.Close() + defer zw.Close() + + err = archiveDocker(ctx, zw, *verbose, baseDir) + if err != nil { + return cmderrors.ExitCode(1, nil) + } + return nil + } + + debugCommands = append(debugCommands, &command{ + flagSet: flagSet, + handler: handler, + usageFunc: func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src debug %s':\n", flagSet.Name()) + flagSet.PrintDefaults() + fmt.Println(usage) + }, + }) +} From 7981e898f4c257e83a78428244ee3b8038f18fe2 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 6 Jan 2022 00:24:33 -0800 Subject: [PATCH 048/107] changed flagset to use .StringVar rather than .String in flagSet package --- cmd/src/debug_common.go | 13 +++++++++++++ cmd/src/debug_comp.go | 21 ++++++++++----------- cmd/src/debug_kube.go | 19 +++++++++---------- cmd/src/debug_serv.go | 21 ++++++++++----------- 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index d53c0a8402..e4060ab00f 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -42,8 +42,14 @@ func setOpenFileLimits(n uint64) error { func setupDebug(base string) (*os.File, *zip.Writer, context.Context, error) { // open pipe to output file out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to open file: %w", err) + } // increase limit of open files err = setOpenFileLimits(64000) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to set open file limits: %w", err) + } // init zip writer zw := zip.NewWriter(out) // init context @@ -355,3 +361,10 @@ func getStats(ctx context.Context, baseDir string) *archiveFile { f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() return f } + +// TODO api brainstorm +// Perform the request. +/* var result interface{} +if ok, err := cfg.apiClient(apiFlags, flagSet.Output()).NewRequest(query, vars).DoRaw(context.Background(), &result); err != nil || !ok { +return err +} */ diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 71fc9214d2..c06f103ea9 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -14,18 +14,17 @@ func init() { Usage: - src debug kube -o FILE [command options] + src debug comp -o FILE [command options] Examples: - $ src debug kube -o debug.zip + $ src debug comp -o debug.zip ` flagSet := flag.NewFlagSet("kube", flag.ExitOnError) - var ( - base = flagSet.String("out", "debug.zip", "The name of the output zip archive") - ) + var base string + flagSet.StringVar(&base, "out", "debug.zip", "The name of the output zip archive") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -33,19 +32,19 @@ Examples: } //validate out flag - if *base == "" { + if base == "" { return fmt.Errorf("empty -out flag") } // declare basedir for archive file structure var baseDir string - if strings.HasSuffix(*base, ".zip") == false { - baseDir = *base - *base = *base + ".zip" + if strings.HasSuffix(base, ".zip") == false { + baseDir = base + base = base + ".zip" } else { - baseDir = strings.TrimSuffix(*base, ".zip") + baseDir = strings.TrimSuffix(base, ".zip") } - out, zw, ctx, err := setupDebug(*base) + out, zw, ctx, err := setupDebug(base) if err != nil { return fmt.Errorf("failed to open file: %w", err) } diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 96e8d78e4f..ad9129bed9 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -23,9 +23,8 @@ Examples: ` flagSet := flag.NewFlagSet("kube", flag.ExitOnError) - var ( - base = flagSet.String("out", "debug.zip", "The name of the output zip archive") - ) + var base string + flagSet.StringVar(&base, "out", "debug.zip", "The name of the output zip archive") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -33,21 +32,21 @@ Examples: } //validate out flag - if *base == "" { + if base == "" { return fmt.Errorf("empty -out flag") } // declare basedir for archive file structure var baseDir string - if strings.HasSuffix(*base, ".zip") == false { - baseDir = *base - *base = *base + ".zip" + if strings.HasSuffix(base, ".zip") == false { + baseDir = base + base = base + ".zip" } else { - baseDir = strings.TrimSuffix(*base, ".zip") + baseDir = strings.TrimSuffix(base, ".zip") } - out, zw, ctx, err := setupDebug(*base) + out, zw, ctx, err := setupDebug(base) if err != nil { - return fmt.Errorf("failed to open file: %w", err) + return err } defer out.Close() defer zw.Close() diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index 206b163943..a3a894d8e6 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -14,18 +14,17 @@ func init() { Usage: - src debug kube -o FILE [command options] + src debug serv -o FILE [command options] Examples: - $ src debug kube -o debug.zip + $ src debug serv -o debug.zip ` flagSet := flag.NewFlagSet("kube", flag.ExitOnError) - var ( - base = flagSet.String("out", "debug.zip", "The name of the output zip archive") - ) + var base string + flagSet.StringVar(&base, "out", "debug.zip", "The name of the output zip archive") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -33,19 +32,19 @@ Examples: } //validate out flag - if *base == "" { + if base == "" { return fmt.Errorf("empty -out flag") } // declare basedir for archive file structure var baseDir string - if strings.HasSuffix(*base, ".zip") == false { - baseDir = *base - *base = *base + ".zip" + if strings.HasSuffix(base, ".zip") == false { + baseDir = base + base = base + ".zip" } else { - baseDir = strings.TrimSuffix(*base, ".zip") + baseDir = strings.TrimSuffix(base, ".zip") } - out, zw, ctx, err := setupDebug(*base) + out, zw, ctx, err := setupDebug(base) if err != nil { return fmt.Errorf("failed to open file: %w", err) } From b54a1afbea8810dc1bd6199982fda3fb8eb15bf2 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 1 Feb 2022 23:49:02 -0800 Subject: [PATCH 049/107] correct flag typo in serv --- cmd/src/debug_serv.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index a3a894d8e6..741b1ed757 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -22,7 +22,7 @@ Examples: ` - flagSet := flag.NewFlagSet("kube", flag.ExitOnError) + flagSet := flag.NewFlagSet("serv", flag.ExitOnError) var base string flagSet.StringVar(&base, "out", "debug.zip", "The name of the output zip archive") From 2d46ea8181d5896017eae07bfcf43242a4a72579 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 2 Feb 2022 01:48:21 -0800 Subject: [PATCH 050/107] fixed verbose output in kube command, changed -out flag to -o --- cmd/src/debug_comp.go | 6 +++--- cmd/src/debug_kube.go | 7 ++++--- cmd/src/debug_serv.go | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index c06f103ea9..4b30bd17ae 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -22,9 +22,9 @@ Examples: ` - flagSet := flag.NewFlagSet("kube", flag.ExitOnError) + flagSet := flag.NewFlagSet("comp", flag.ExitOnError) var base string - flagSet.StringVar(&base, "out", "debug.zip", "The name of the output zip archive") + flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -33,7 +33,7 @@ Examples: //validate out flag if base == "" { - return fmt.Errorf("empty -out flag") + return fmt.Errorf("empty -o flag") } // declare basedir for archive file structure var baseDir string diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index ad9129bed9..63873bfe8f 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -24,7 +24,8 @@ Examples: flagSet := flag.NewFlagSet("kube", flag.ExitOnError) var base string - flagSet.StringVar(&base, "out", "debug.zip", "The name of the output zip archive") + flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") + flagSet.BoolVar(verbose, "v", false, "print verbose output") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -33,7 +34,7 @@ Examples: //validate out flag if base == "" { - return fmt.Errorf("empty -out flag") + return fmt.Errorf("empty -o flag") } // declare basedir for archive file structure var baseDir string @@ -58,7 +59,7 @@ Examples: return nil } - debugCommands = append(batchCommands, &command{ + debugCommands = append(debugCommands, &command{ flagSet: flagSet, handler: handler, usageFunc: func() { diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index 741b1ed757..d9b3142aa5 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -24,7 +24,7 @@ Examples: flagSet := flag.NewFlagSet("serv", flag.ExitOnError) var base string - flagSet.StringVar(&base, "out", "debug.zip", "The name of the output zip archive") + flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -33,7 +33,7 @@ Examples: //validate out flag if base == "" { - return fmt.Errorf("empty -out flag") + return fmt.Errorf("empty -o flag") } // declare basedir for archive file structure var baseDir string From d3d557eb63cc340ddb3c980e54632e4ed93fbf24 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 7 Feb 2022 08:54:45 -0800 Subject: [PATCH 051/107] switching to passanger, stating getConfig --- cmd/src/debug_common.go | 7 +++---- cmd/src/debug_kube.go | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index e4060ab00f..f1375ef22c 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -364,7 +364,6 @@ func getStats(ctx context.Context, baseDir string) *archiveFile { // TODO api brainstorm // Perform the request. -/* var result interface{} -if ok, err := cfg.apiClient(apiFlags, flagSet.Output()).NewRequest(query, vars).DoRaw(context.Background(), &result); err != nil || !ok { -return err -} */ +func getConfig() *archiveFile { + +} diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 63873bfe8f..9f9e4d5f47 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -25,7 +25,6 @@ Examples: flagSet := flag.NewFlagSet("kube", flag.ExitOnError) var base string flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") - flagSet.BoolVar(verbose, "v", false, "print verbose output") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { From e39353519dfe478082f19a3a1caaac6c32f51958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senart?= Date: Mon, 7 Feb 2022 17:42:10 +0000 Subject: [PATCH 052/107] ignore errors and get extsvc configs --- cmd/src/debug_common.go | 18 ++++++++++++++---- cmd/src/debug_kube.go | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index f1375ef22c..dc11526f5c 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -162,6 +162,12 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri }(pod.Metadata.Name) } + wg.Add(1) + go func() { + defer wg.Done() + ch <- getExternalServicesConfig(ctx, baseDir) + }() + // close channel when wait group goroutines have completed go func() { wg.Wait() @@ -171,7 +177,8 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri // write to archive all the outputs from kubectl call functions passed to buffer channel for f := range ch { if f.err != nil { - return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) + log.Printf("getting data for %s failed: %v\noutput: %s", f.name, f.err, f.data) + continue } if verbose { @@ -362,8 +369,11 @@ func getStats(ctx context.Context, baseDir string) *archiveFile { return f } -// TODO api brainstorm -// Perform the request. -func getConfig() *archiveFile { +func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { + const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` + f := &archiveFile{name: baseDir + "/config/external_services.txt"} + f.data, f.err = exec.CommandContext(ctx, os.Args[0], "extsvc", "list", "-f", fmtStr).CombinedOutput() + + return f } diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 9f9e4d5f47..92857b205b 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -53,7 +53,7 @@ Examples: err = archiveKube(ctx, zw, *verbose, baseDir) if err != nil { - return cmderrors.ExitCode(1, nil) + return cmderrors.ExitCode(1, err) } return nil } From 7dff3b9e9aa34efcf9dcd70de256f5f93d9afd73 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 8 Feb 2022 20:52:04 -0800 Subject: [PATCH 053/107] add some comments from work with Tomas --- cmd/src/debug_common.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index dc11526f5c..2b3ba7f122 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -61,6 +61,7 @@ func setupDebug(base string) (*os.File, *zip.Writer, context.Context, error) { /* Kubernetes stuff TODO: handle namespaces, remove --all-namespaces from get events +TODO: have a confirmation step that warns user about which namespace and context they have kubectl pointed at */ type podList struct { @@ -369,6 +370,12 @@ func getStats(ctx context.Context, baseDir string) *archiveFile { return f } +/* +General Stuff +TODO: file issue on the existence of OAuth signKey which needs to be redacted +TODO: Create getSiteConfig function +*/ + func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` From 2e3b5251292d3081739b41a48930e0ebb7a6a1b1 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 25 Feb 2022 12:20:35 -0800 Subject: [PATCH 054/107] added namespace flag for kube subcommand --- cmd/src/debug.go | 8 +++++++ cmd/src/debug_common.go | 50 ++++++++++++++++++++--------------------- cmd/src/debug_kube.go | 6 ++++- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 8442a93e37..ba2ea62463 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -42,3 +42,11 @@ Use "src debug [command] -h" for more information about a command. usageFunc: func() { fmt.Println(usage) }, }) } + +/* +TODO: + - This project needs some consideration around monitoring + - You should be aware when a executed cmd has failed + - You should be able to recieve an output that tells you what you've created in the zip file + - an additional introspection command might be useful to look at whats in a zip file easily +*/ diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 2b3ba7f122..c32b7ea8cd 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -78,14 +78,14 @@ type podList struct { } // Run kubectl functions concurrently and archive results to zip file -func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir string) error { +func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, namespace, baseDir string) error { // Create a context with a cancel function that we call when returning // from archiveKube. This ensures we close all pending go-routines when returning // early because of an error. ctx, cancel := context.WithCancel(ctx) defer cancel() - pods, err := getPods(ctx) + pods, err := getPods(ctx, namespace) if err != nil { return fmt.Errorf("failed to get pods: %w", err) } @@ -102,21 +102,21 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri wg.Add(1) go func() { defer wg.Done() - ch <- getEvents(ctx, baseDir) + ch <- getEvents(ctx, namespace, baseDir) }() // create goroutine to get persistent volumes wg.Add(1) go func() { defer wg.Done() - ch <- getPV(ctx, baseDir) + ch <- getPV(ctx, namespace, baseDir) }() // create goroutine to get persistent volumes claim wg.Add(1) go func() { defer wg.Done() - ch <- getPVC(ctx, baseDir) + ch <- getPVC(ctx, namespace, baseDir) }() // start goroutine to run kubectl logs for each pod's container's @@ -125,7 +125,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri wg.Add(1) go func(pod, container string) { defer wg.Done() - ch <- getContainerLog(ctx, pod, container, baseDir) + ch <- getContainerLog(ctx, pod, container, namespace, baseDir) }(pod.Metadata.Name, container.Name) } } @@ -137,7 +137,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri wg.Add(1) go func(pod, container string) { defer wg.Done() - f := getPastContainerLog(ctx, pod, container, baseDir) + f := getPastContainerLog(ctx, pod, container, namespace, baseDir) if f.err == nil { ch <- f } @@ -150,7 +150,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri wg.Add(1) go func(pod string) { defer wg.Done() - ch <- getDescribe(ctx, pod, baseDir) + ch <- getDescribe(ctx, pod, namespace, baseDir) }(pod.Metadata.Name) } @@ -159,7 +159,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri wg.Add(1) go func(pod string) { defer wg.Done() - ch <- getManifest(ctx, pod, baseDir) + ch <- getManifest(ctx, pod, namespace, baseDir) }(pod.Metadata.Name) } @@ -200,12 +200,12 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, baseDir stri return nil } -func getPods(ctx context.Context) (podList, error) { +func getPods(ctx context.Context, namespace string) (podList, error) { // Declare buffer type var for kubectl pipe var podsBuff bytes.Buffer // Get all pod names as json - getPods := exec.CommandContext(ctx, "kubectl", "get", "pods", "-l", "deploy=sourcegraph", "-o=json") + getPods := exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pods", "-l", "deploy=sourcegraph", "-o=json") getPods.Stdout = &podsBuff getPods.Stderr = os.Stderr err := getPods.Run() @@ -221,47 +221,47 @@ func getPods(ctx context.Context) (podList, error) { return pods, err } -func getEvents(ctx context.Context, baseDir string) *archiveFile { +func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/events.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "events", "--all-namespaces").CombinedOutput() + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "events").CombinedOutput() return f } -func getPV(ctx context.Context, baseDir string) *archiveFile { +func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pv").CombinedOutput() + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pv").CombinedOutput() return f } -func getPVC(ctx context.Context, baseDir string) *archiveFile { +func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pvc").CombinedOutput() + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pvc").CombinedOutput() return f } // get kubectl logs for pod containers -func getContainerLog(ctx context.Context, podName, containerName, baseDir string) *archiveFile { +func getContainerLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", podName, "-c", containerName).CombinedOutput() + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", podName, "-c", containerName).CombinedOutput() return f } // get kubectl logs for past container -func getPastContainerLog(ctx context.Context, podName, containerName, baseDir string) *archiveFile { +func getPastContainerLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "logs", "--previous", podName, "-c", containerName).CombinedOutput() + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName).CombinedOutput() return f } -func getDescribe(ctx context.Context, podName, baseDir string) *archiveFile { +func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "describe", "pod", podName).CombinedOutput() + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "describe", "pod", podName).CombinedOutput() return f } -func getManifest(ctx context.Context, podName, baseDir string) *archiveFile { +func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "get", "pod", podName, "-o", "yaml").CombinedOutput() + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml").CombinedOutput() return f } diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 92857b205b..397d64780e 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -8,6 +8,8 @@ import ( "github.com/sourcegraph/src-cli/internal/cmderrors" ) +// TODO: seperate graphQL API call functions from archiveKube main function -- in accordance with database dumps, and prometheus, these should be optional via flags + func init() { usage := ` 'src debug kube' mocks kubectl commands to gather information about a kubernetes sourcegraph instance. @@ -24,7 +26,9 @@ Examples: flagSet := flag.NewFlagSet("kube", flag.ExitOnError) var base string + var namespace string flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") + flagSet.StringVar(&namespace, "n", "default", "The namespace passed to kubectl commands, if not specified the default namespace is used") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -51,7 +55,7 @@ Examples: defer out.Close() defer zw.Close() - err = archiveKube(ctx, zw, *verbose, baseDir) + err = archiveKube(ctx, zw, *verbose, namespace, baseDir) if err != nil { return cmderrors.ExitCode(1, err) } From 77f62e0e21b4157949fce4ae707e33e347122098 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 15 Mar 2022 00:40:23 -0700 Subject: [PATCH 055/107] added a little safety check to the kube command --- cmd/src/debug_common.go | 17 +++++++++-------- cmd/src/debug_kube.go | 25 ++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index c32b7ea8cd..d741edb8d9 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -24,6 +24,7 @@ type archiveFile struct { // setOpenFileLimits increases the limit of open files to the given number. This is needed // when doings lots of concurrent network requests which establish open sockets. func setOpenFileLimits(n uint64) error { + var rlimit syscall.Rlimit err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) if err != nil { @@ -78,21 +79,21 @@ type podList struct { } // Run kubectl functions concurrently and archive results to zip file -func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, namespace, baseDir string) error { +func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, namespace, baseDir string, pods podList) error { // Create a context with a cancel function that we call when returning // from archiveKube. This ensures we close all pending go-routines when returning // early because of an error. ctx, cancel := context.WithCancel(ctx) defer cancel() - pods, err := getPods(ctx, namespace) - if err != nil { - return fmt.Errorf("failed to get pods: %w", err) - } + //pods, err := getPods(ctx, namespace) + //if err != nil { + // return fmt.Errorf("failed to get pods: %w", err) + //} - if verbose { - log.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) - } + //if verbose { + // log.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) + //} // setup channel for slice of archive function outputs ch := make(chan *archiveFile) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 397d64780e..461cc7af3c 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -1,9 +1,12 @@ package main import ( + "context" "flag" "fmt" + "log" "strings" + "unicode" "github.com/sourcegraph/src-cli/internal/cmderrors" ) @@ -48,6 +51,26 @@ Examples: baseDir = strings.TrimSuffix(base, ".zip") } + ctx := context.Background() + + pods, err := getPods(ctx, namespace) + if err != nil { + return fmt.Errorf("failed to get pods: %w", err) + } + + log.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) + var verify string + fmt.Print("Do you want to start writing to an archive? [y/n] ") + _, err = fmt.Scanln(&verify) + for unicode.ToLower(rune(verify[0])) != 'y' && unicode.ToLower(rune(verify[0])) != 'n' { + fmt.Println("Input must be string y or n") + _, err = fmt.Scanln(&verify) + } + if unicode.ToLower(rune(verify[0])) == 'n' { + fmt.Println("escaping") + return nil + } + out, zw, ctx, err := setupDebug(base) if err != nil { return err @@ -55,7 +78,7 @@ Examples: defer out.Close() defer zw.Close() - err = archiveKube(ctx, zw, *verbose, namespace, baseDir) + err = archiveKube(ctx, zw, *verbose, namespace, baseDir, pods) if err != nil { return cmderrors.ExitCode(1, err) } From d1264a9e495861921585e9f2bc8f2e05875ca92b Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 15 Apr 2022 17:51:50 -0500 Subject: [PATCH 056/107] added a semaphore to kube, added some text safty checks --- cmd/src/debug_common.go | 76 ++++++++++++++++++++++++----------------- cmd/src/debug_kube.go | 4 ++- 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index d741edb8d9..0cfaaaaa65 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -12,9 +12,17 @@ import ( "sync" "syscall" + "golang.org/x/sync/semaphore" + "github.com/sourcegraph/src-cli/internal/exec" ) +/* +General Stuff +TODO: file issue on the existence of OAuth signKey which needs to be redacted +TODO: Create getSiteConfig function +*/ + type archiveFile struct { name string data []byte @@ -59,6 +67,17 @@ func setupDebug(base string) (*os.File, *zip.Writer, context.Context, error) { return out, zw, ctx, err } +// getExternalServicesConfig calls src extsvc list with the format flag -f, +//and then returns an archiveFile to be consumed +func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { + const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` + + f := &archiveFile{name: baseDir + "/config/external_services.txt"} + f.data, f.err = exec.CommandContext(ctx, os.Args[0], "extsvc", "list", "-f", fmtStr).CombinedOutput() + + return f +} + /* Kubernetes stuff TODO: handle namespaces, remove --all-namespaces from get events @@ -79,30 +98,26 @@ type podList struct { } // Run kubectl functions concurrently and archive results to zip file -func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, namespace, baseDir string, pods podList) error { +func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespace, baseDir string, pods podList) error { // Create a context with a cancel function that we call when returning // from archiveKube. This ensures we close all pending go-routines when returning // early because of an error. ctx, cancel := context.WithCancel(ctx) defer cancel() - //pods, err := getPods(ctx, namespace) - //if err != nil { - // return fmt.Errorf("failed to get pods: %w", err) - //} - - //if verbose { - // log.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) - //} - - // setup channel for slice of archive function outputs + // setup channel for slice of archive function outputs, as well as throttling semaphore ch := make(chan *archiveFile) wg := sync.WaitGroup{} + semaphore := semaphore.NewWeighted(8) // create goroutine to get kubectl events wg.Add(1) go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } defer wg.Done() + defer semaphore.Release(1) ch <- getEvents(ctx, namespace, baseDir) }() @@ -125,7 +140,11 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, namespace, b for _, container := range pod.Spec.Containers { wg.Add(1) go func(pod, container string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } defer wg.Done() + defer semaphore.Release(1) ch <- getContainerLog(ctx, pod, container, namespace, baseDir) }(pod.Metadata.Name, container.Name) } @@ -164,11 +183,14 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose bool, namespace, b }(pod.Metadata.Name) } - wg.Add(1) - go func() { - defer wg.Done() - ch <- getExternalServicesConfig(ctx, baseDir) - }() + // start goroutine to get external service config + if ext == true { + wg.Add(1) + go func() { + defer wg.Done() + ch <- getExternalServicesConfig(ctx, baseDir) + }() + } // close channel when wait group goroutines have completed go func() { @@ -313,6 +335,13 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir st }(container) } + // start goroutine to get external service config + wg.Add(1) + go func() { + defer wg.Done() + ch <- getExternalServicesConfig(ctx, baseDir) + }() + // close channel when wait group goroutines have completed go func() { wg.Wait() @@ -370,18 +399,3 @@ func getStats(ctx context.Context, baseDir string) *archiveFile { f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() return f } - -/* -General Stuff -TODO: file issue on the existence of OAuth signKey which needs to be redacted -TODO: Create getSiteConfig function -*/ - -func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { - const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` - - f := &archiveFile{name: baseDir + "/config/external_services.txt"} - f.data, f.err = exec.CommandContext(ctx, os.Args[0], "extsvc", "list", "-f", fmtStr).CombinedOutput() - - return f -} diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 461cc7af3c..134212c31b 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -30,8 +30,10 @@ Examples: flagSet := flag.NewFlagSet("kube", flag.ExitOnError) var base string var namespace string + var extsvc bool flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") flagSet.StringVar(&namespace, "n", "default", "The namespace passed to kubectl commands, if not specified the default namespace is used") + flagSet.BoolVar(&extsvc, "ext", false, "Include external service json in archive") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -78,7 +80,7 @@ Examples: defer out.Close() defer zw.Close() - err = archiveKube(ctx, zw, *verbose, namespace, baseDir, pods) + err = archiveKube(ctx, zw, *verbose, extsvc, namespace, baseDir, pods) if err != nil { return cmderrors.ExitCode(1, err) } From 47ba3c52496b003e5faa704cee32a9671267f379 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 15 Apr 2022 18:04:10 -0500 Subject: [PATCH 057/107] added semphore to all RPC calls in archiveKube --- cmd/src/debug_common.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 0cfaaaaa65..13744142ee 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -116,14 +116,18 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa if err := semaphore.Acquire(ctx, 1); err != nil { // return err } - defer wg.Done() defer semaphore.Release(1) + defer wg.Done() ch <- getEvents(ctx, namespace, baseDir) }() // create goroutine to get persistent volumes wg.Add(1) go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) defer wg.Done() ch <- getPV(ctx, namespace, baseDir) }() @@ -131,6 +135,10 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa // create goroutine to get persistent volumes claim wg.Add(1) go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) defer wg.Done() ch <- getPVC(ctx, namespace, baseDir) }() @@ -143,8 +151,8 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa if err := semaphore.Acquire(ctx, 1); err != nil { // return err } - defer wg.Done() defer semaphore.Release(1) + defer wg.Done() ch <- getContainerLog(ctx, pod, container, namespace, baseDir) }(pod.Metadata.Name, container.Name) } @@ -156,6 +164,10 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa for _, container := range pod.Spec.Containers { wg.Add(1) go func(pod, container string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) defer wg.Done() f := getPastContainerLog(ctx, pod, container, namespace, baseDir) if f.err == nil { @@ -169,6 +181,10 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa for _, pod := range pods.Items { wg.Add(1) go func(pod string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) defer wg.Done() ch <- getDescribe(ctx, pod, namespace, baseDir) }(pod.Metadata.Name) @@ -178,6 +194,10 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa for _, pod := range pods.Items { wg.Add(1) go func(pod string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) defer wg.Done() ch <- getManifest(ctx, pod, namespace, baseDir) }(pod.Metadata.Name) @@ -187,6 +207,10 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa if ext == true { wg.Add(1) go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) defer wg.Done() ch <- getExternalServicesConfig(ctx, baseDir) }() From 367de181b54f0601842bee6f2eda3921ce3ccf8f Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 15 Apr 2022 19:25:07 -0500 Subject: [PATCH 058/107] added current-context logging before kube command execution --- cmd/src/debug_kube.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 134212c31b..0d8047cdfd 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -9,6 +9,7 @@ import ( "unicode" "github.com/sourcegraph/src-cli/internal/cmderrors" + "github.com/sourcegraph/src-cli/internal/exec" ) // TODO: seperate graphQL API call functions from archiveKube main function -- in accordance with database dumps, and prometheus, these should be optional via flags @@ -59,8 +60,13 @@ Examples: if err != nil { return fmt.Errorf("failed to get pods: %w", err) } + kubectx, err := exec.CommandContext(ctx, "kubectl", "config", "current-context").CombinedOutput() + if err != nil { + return fmt.Errorf("failed to get current-context: %w", err) + } + + log.Printf("getting kubectl data for %d pods, from context %s ...\n", len(pods.Items), kubectx) - log.Printf("getting kubectl data for %d pods...\n", len(pods.Items)) var verify string fmt.Print("Do you want to start writing to an archive? [y/n] ") _, err = fmt.Scanln(&verify) From 13a2620be2744085fd57a3280f1484f537387a03 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 21 Apr 2022 11:47:04 -0700 Subject: [PATCH 059/107] Atempting to debug error inconsistent --previous logs call --- cmd/src/debug_common.go | 2 ++ cmd/src/debug_kube.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 13744142ee..84dc441ea5 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -172,6 +172,8 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa f := getPastContainerLog(ctx, pod, container, namespace, baseDir) if f.err == nil { ch <- f + } else { + fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", pod, f.err) } }(pod.Metadata.Name, container.Name) } diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 0d8047cdfd..f5b8b569b5 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -64,7 +64,7 @@ Examples: if err != nil { return fmt.Errorf("failed to get current-context: %w", err) } - + //TODO: improve formating to include ls like pod listing for pods targeted. log.Printf("getting kubectl data for %d pods, from context %s ...\n", len(pods.Items), kubectx) var verify string From a8505f8131f76909f1dfd42967709c8ca628f3cd Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 21 Apr 2022 15:01:30 -0700 Subject: [PATCH 060/107] added network validation to comp subcommand --- cmd/src/debug_common.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 84dc441ea5..1f345d7948 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -12,6 +12,8 @@ import ( "sync" "syscall" + "github.com/cockroachdb/errors" + "golang.org/x/sync/semaphore" "github.com/sourcegraph/src-cli/internal/exec" @@ -298,7 +300,11 @@ func getContainerLog(ctx context.Context, podName, containerName, namespace, bas // get kubectl logs for past container func getPastContainerLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} + cmdStr := []string{"kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName} f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName).CombinedOutput() + if f.err != nil { + f.err = errors.Wrapf(f.err, "executing command: %s: received error: %s", cmdStr, f.data) + } return f } @@ -398,13 +404,20 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir st } func getContainers(ctx context.Context) ([]string, error) { - c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}}").Output() + c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}} {{.Networks}}").Output() if err != nil { fmt.Errorf("failed to get container names with error: %w", err) } s := string(c) - containers := strings.Split(strings.TrimSpace(s), "\n") - fmt.Println(containers) + preprocessed := strings.Split(strings.TrimSpace(s), "\n") + containers := []string{} + for _, container := range preprocessed { + fmt.Printf("%#v\n", container) + tmpStr := strings.Split(container, " ") + if tmpStr[1] == "docker-compose_sourcegraph" { + containers = append(containers, tmpStr[0]) + } + } return containers, err } From 6a64a3c625f2d00346d2cb45a136b75cba46d9c3 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 22 Apr 2022 02:23:17 -0700 Subject: [PATCH 061/107] added a function to pull site config, cleaned up logging and usage funcs --- cmd/src/debug.go | 7 ++--- cmd/src/debug_common.go | 60 ++++++++++++++++++++++++++++++----------- cmd/src/debug_comp.go | 37 +++++++++++++++++++++---- cmd/src/debug_kube.go | 26 +++++++++++------- cmd/src/debug_serv.go | 15 ++++++++--- 5 files changed, 109 insertions(+), 36 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index ba2ea62463..76ad13dca2 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -21,7 +21,8 @@ The commands are: serv generates docker outputs -Use "src debug [command] -h" for more information about a command. +Use "src debug [command] -h" for more information about a subcommands. +src debug has access to flags on src -- Ex: src -v kube -o foo.zip ` @@ -46,7 +47,7 @@ Use "src debug [command] -h" for more information about a command. /* TODO: - This project needs some consideration around monitoring - - You should be aware when a executed cmd has failed - - You should be able to recieve an output that tells you what you've created in the zip file + - You should be aware when an executed cmd has failed + - You should be able to receive an output that tells you what you've created in the zip file - an additional introspection command might be useful to look at whats in a zip file easily */ diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 1f345d7948..dcfc6f5d37 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -13,10 +13,8 @@ import ( "syscall" "github.com/cockroachdb/errors" - - "golang.org/x/sync/semaphore" - "github.com/sourcegraph/src-cli/internal/exec" + "golang.org/x/sync/semaphore" ) /* @@ -69,6 +67,8 @@ func setupDebug(base string) (*os.File, *zip.Writer, context.Context, error) { return out, zw, ctx, err } +// TODO: Currently external services and site configs are pulled using the src endpoints + // getExternalServicesConfig calls src extsvc list with the format flag -f, //and then returns an archiveFile to be consumed func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { @@ -80,6 +80,16 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile return f } +// getSiteConfig calls src api -query=... to query the api for site config json +// TODO: correctly format json output before writing to zip +func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { + const siteConfigStr = `query { site { configuration { effectiveContents } } }` + f := &archiveFile{name: baseDir + "/config/siteConfig.json"} + f.data, f.err = exec.CommandContext(ctx, os.Args[0], "api", "-query", siteConfigStr).CombinedOutput() + + return f +} + /* Kubernetes stuff TODO: handle namespaces, remove --all-namespaces from get events @@ -100,7 +110,7 @@ type podList struct { } // Run kubectl functions concurrently and archive results to zip file -func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespace, baseDir string, pods podList) error { +func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, namespace, baseDir string, pods podList) error { // Create a context with a cancel function that we call when returning // from archiveKube. This ensures we close all pending go-routines when returning // early because of an error. @@ -162,6 +172,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa // start goroutine to run kubectl logs --previous for each pod's container's // won't write to zip on err, only passes bytes to channel if err not nil + // TODO: It may be nice to store a list of pods for which --previous isn't collected, to be outputted with verbose flag for _, pod := range pods.Items { for _, container := range pod.Spec.Containers { wg.Add(1) @@ -175,7 +186,9 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa if f.err == nil { ch <- f } else { - fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", pod, f.err) + if verbose { + fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", pod, f.err) + } } }(pod.Metadata.Name, container.Name) } @@ -208,7 +221,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa } // start goroutine to get external service config - if ext == true { + if configs == true { wg.Add(1) go func() { if err := semaphore.Acquire(ctx, 1); err != nil { @@ -218,6 +231,16 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, ext bool, namespa defer wg.Done() ch <- getExternalServicesConfig(ctx, baseDir) }() + + wg.Add(1) + go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getSiteConfig(ctx, baseDir) + }() } // close channel when wait group goroutines have completed @@ -322,10 +345,10 @@ func getManifest(ctx context.Context, podName, namespace, baseDir string) *archi /* Docker functions -TODO: handle for single container instance +TODO: handle for single container/server instance */ -func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir string) error { +func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, baseDir string) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -367,12 +390,20 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose bool, baseDir st }(container) } - // start goroutine to get external service config - wg.Add(1) - go func() { - defer wg.Done() - ch <- getExternalServicesConfig(ctx, baseDir) - }() + // start goroutine to get configs + if configs == true { + wg.Add(1) + go func() { + defer wg.Done() + ch <- getExternalServicesConfig(ctx, baseDir) + }() + + wg.Add(1) + go func() { + defer wg.Done() + ch <- getSiteConfig(ctx, baseDir) + }() + } // close channel when wait group goroutines have completed go func() { @@ -412,7 +443,6 @@ func getContainers(ctx context.Context) ([]string, error) { preprocessed := strings.Split(strings.TrimSpace(s), "\n") containers := []string{} for _, container := range preprocessed { - fmt.Printf("%#v\n", container) tmpStr := strings.Split(container, " ") if tmpStr[1] == "docker-compose_sourcegraph" { containers = append(containers, tmpStr[0]) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 4b30bd17ae..053d4114f0 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -1,29 +1,41 @@ package main import ( + "context" "flag" "fmt" + "log" "strings" + "unicode" "github.com/sourcegraph/src-cli/internal/cmderrors" ) func init() { usage := ` -'src debug comp' mocks docker cli commands to gather information about a docker-compose Sourcegraph instance. +'src debug comp' mocks docker cli commands to gather information about a docker-compose Sourcegraph instance. Usage: - src debug comp -o FILE [command options] + src debug comp [command options] + +Flags: + + -o Specify the name of the output zip archive. + -cfg Include Sourcegraph configuration json. Defaults to true. Examples: $ src debug comp -o debug.zip + $ src -v debug comp -cfg=false -o foo.zip + ` flagSet := flag.NewFlagSet("comp", flag.ExitOnError) var base string + var configs bool + flagSet.BoolVar(&configs, "cfg", true, "If true include Sourcegraph configuration files. Default value true.") flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") handler := func(args []string) error { @@ -44,6 +56,23 @@ Examples: baseDir = strings.TrimSuffix(base, ".zip") } + ctx := context.Background() + containers, err := getContainers(ctx) + + log.Printf("Archiving docker-cli data for %d containers\n SRC_ENDPOINT: %v\n Output filename: %v", len(containers), cfg.Endpoint, base) + + var verify string + fmt.Print("Do you want to start writing to an archive? [y/n] ") + _, err = fmt.Scanln(&verify) + for unicode.ToLower(rune(verify[0])) != 'y' && unicode.ToLower(rune(verify[0])) != 'n' { + fmt.Println("Input must be string y or n") + _, err = fmt.Scanln(&verify) + } + if unicode.ToLower(rune(verify[0])) == 'n' { + fmt.Println("escaping") + return nil + } + out, zw, ctx, err := setupDebug(base) if err != nil { return fmt.Errorf("failed to open file: %w", err) @@ -51,7 +80,7 @@ Examples: defer out.Close() defer zw.Close() - err = archiveDocker(ctx, zw, *verbose, baseDir) + err = archiveDocker(ctx, zw, *verbose, configs, baseDir) if err != nil { return cmderrors.ExitCode(1, nil) } @@ -62,8 +91,6 @@ Examples: flagSet: flagSet, handler: handler, usageFunc: func() { - fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src debug %s':\n", flagSet.Name()) - flagSet.PrintDefaults() fmt.Println(usage) }, }) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index f5b8b569b5..a7bba2b054 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -20,21 +20,31 @@ func init() { Usage: - src debug kube -o FILE [command options] + src debug kube [command options] + +Flags: + + -o Specify the name of the output zip archive. + -n Specify the namespace passed to kubectl commands. If not specified the 'default' namespace is used. + -cfg Include Sourcegraph configuration json. Defaults to true. Examples: $ src debug kube -o debug.zip + $ src -v debug kube -n ns-sourcegraph -o foo + + $ src debug kube -cfg=false -o bar.zip + ` flagSet := flag.NewFlagSet("kube", flag.ExitOnError) var base string var namespace string - var extsvc bool + var configs bool + flagSet.BoolVar(&configs, "cfg", true, "If true include Sourcegraph configuration files. Default value true.") + flagSet.StringVar(&namespace, "n", "default", "The namespace passed to kubectl commands, if not specified the 'default' namespace is used") flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") - flagSet.StringVar(&namespace, "n", "default", "The namespace passed to kubectl commands, if not specified the default namespace is used") - flagSet.BoolVar(&extsvc, "ext", false, "Include external service json in archive") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -64,8 +74,8 @@ Examples: if err != nil { return fmt.Errorf("failed to get current-context: %w", err) } - //TODO: improve formating to include ls like pod listing for pods targeted. - log.Printf("getting kubectl data for %d pods, from context %s ...\n", len(pods.Items), kubectx) + //TODO: improve formating to include 'ls' like pod listing for pods targeted. + log.Printf("Archiving kubectl data for %d pods\n SRC_ENDPOINT: %v\n Context: %s Namespace: %v\n Output filename: %v", len(pods.Items), cfg.Endpoint, kubectx, namespace, base) var verify string fmt.Print("Do you want to start writing to an archive? [y/n] ") @@ -86,7 +96,7 @@ Examples: defer out.Close() defer zw.Close() - err = archiveKube(ctx, zw, *verbose, extsvc, namespace, baseDir, pods) + err = archiveKube(ctx, zw, *verbose, configs, namespace, baseDir, pods) if err != nil { return cmderrors.ExitCode(1, err) } @@ -97,8 +107,6 @@ Examples: flagSet: flagSet, handler: handler, usageFunc: func() { - fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src debug %s':\n", flagSet.Name()) - flagSet.PrintDefaults() fmt.Println(usage) }, }) diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index d9b3142aa5..ca47813bc6 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -14,16 +14,25 @@ func init() { Usage: - src debug serv -o FILE [command options] + src debug serv [command options] + +Flags: + + -o Specify the name of the output zip archive. + -cfg Include Sourcegraph configuration json. Defaults to true. Examples: $ src debug serv -o debug.zip + $ src -v debug serv -cfg=false -o foo.zip + ` flagSet := flag.NewFlagSet("serv", flag.ExitOnError) var base string + var configs bool + flagSet.BoolVar(&configs, "cfg", true, "If true include Sourcegraph configuration files. Default value true.") flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") handler := func(args []string) error { @@ -51,7 +60,7 @@ Examples: defer out.Close() defer zw.Close() - err = archiveDocker(ctx, zw, *verbose, baseDir) + err = archiveDocker(ctx, zw, *verbose, configs, baseDir) if err != nil { return cmderrors.ExitCode(1, nil) } @@ -62,8 +71,6 @@ Examples: flagSet: flagSet, handler: handler, usageFunc: func() { - fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src debug %s':\n", flagSet.Name()) - flagSet.PrintDefaults() fmt.Println(usage) }, }) From 9c814677b3b4eedff710fb5c44847ba72a5de041 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 26 Apr 2022 00:28:19 -0700 Subject: [PATCH 062/107] moved sub-functions to relevant file, trial utility archiveFileFromCommand in src extsvc function --- cmd/src/debug_common.go | 411 ++-------------------------------------- cmd/src/debug_comp.go | 129 +++++++++++++ cmd/src/debug_kube.go | 257 ++++++++++++++++++++++++- 3 files changed, 405 insertions(+), 392 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index dcfc6f5d37..e38ecd4114 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -2,19 +2,15 @@ package main import ( "archive/zip" - "bytes" "context" - "encoding/json" "fmt" - "log" "os" + "path/filepath" "strings" - "sync" "syscall" - "github.com/cockroachdb/errors" + "github.com/sourcegraph/sourcegraph/lib/errors" "github.com/sourcegraph/src-cli/internal/exec" - "golang.org/x/sync/semaphore" ) /* @@ -29,6 +25,15 @@ type archiveFile struct { err error } +func archiveFileFromCommand(ctx context.Context, baseDir, path, cmd string, args ...string) *archiveFile { + f := &archiveFile{name: filepath.Join(baseDir, path)} + f.data, f.err = exec.CommandContext(ctx, cmd, args...).CombinedOutput() + if f.err != nil { + f.err = errors.Wrapf(f.err, "executing command: %s %s: received error: %s", cmd, strings.Join(args, " "), f.data) + } + return f +} + // setOpenFileLimits increases the limit of open files to the given number. This is needed // when doings lots of concurrent network requests which establish open sockets. func setOpenFileLimits(n uint64) error { @@ -73,13 +78,18 @@ func setupDebug(base string) (*os.File, *zip.Writer, context.Context, error) { //and then returns an archiveFile to be consumed func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` - - f := &archiveFile{name: baseDir + "/config/external_services.txt"} - f.data, f.err = exec.CommandContext(ctx, os.Args[0], "extsvc", "list", "-f", fmtStr).CombinedOutput() - - return f + return archiveFileFromCommand(ctx, baseDir, "/config/external_services.txt", os.Args[0], "extsvc", "list", "-f", fmtStr) } +//func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { +// const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` +// +// f := &archiveFile{name: baseDir + "/config/external_services.txt"} +// f.data, f.err = exec.CommandContext(ctx, os.Args[0], "extsvc", "list", "-f", fmtStr).CombinedOutput() +// +// return f +//} + // getSiteConfig calls src api -query=... to query the api for site config json // TODO: correctly format json output before writing to zip func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { @@ -89,382 +99,3 @@ func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { return f } - -/* -Kubernetes stuff -TODO: handle namespaces, remove --all-namespaces from get events -TODO: have a confirmation step that warns user about which namespace and context they have kubectl pointed at -*/ - -type podList struct { - Items []struct { - Metadata struct { - Name string - } - Spec struct { - Containers []struct { - Name string - } - } - } -} - -// Run kubectl functions concurrently and archive results to zip file -func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, namespace, baseDir string, pods podList) error { - // Create a context with a cancel function that we call when returning - // from archiveKube. This ensures we close all pending go-routines when returning - // early because of an error. - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - // setup channel for slice of archive function outputs, as well as throttling semaphore - ch := make(chan *archiveFile) - wg := sync.WaitGroup{} - semaphore := semaphore.NewWeighted(8) - - // create goroutine to get kubectl events - wg.Add(1) - go func() { - if err := semaphore.Acquire(ctx, 1); err != nil { - // return err - } - defer semaphore.Release(1) - defer wg.Done() - ch <- getEvents(ctx, namespace, baseDir) - }() - - // create goroutine to get persistent volumes - wg.Add(1) - go func() { - if err := semaphore.Acquire(ctx, 1); err != nil { - // return err - } - defer semaphore.Release(1) - defer wg.Done() - ch <- getPV(ctx, namespace, baseDir) - }() - - // create goroutine to get persistent volumes claim - wg.Add(1) - go func() { - if err := semaphore.Acquire(ctx, 1); err != nil { - // return err - } - defer semaphore.Release(1) - defer wg.Done() - ch <- getPVC(ctx, namespace, baseDir) - }() - - // start goroutine to run kubectl logs for each pod's container's - for _, pod := range pods.Items { - for _, container := range pod.Spec.Containers { - wg.Add(1) - go func(pod, container string) { - if err := semaphore.Acquire(ctx, 1); err != nil { - // return err - } - defer semaphore.Release(1) - defer wg.Done() - ch <- getContainerLog(ctx, pod, container, namespace, baseDir) - }(pod.Metadata.Name, container.Name) - } - } - - // start goroutine to run kubectl logs --previous for each pod's container's - // won't write to zip on err, only passes bytes to channel if err not nil - // TODO: It may be nice to store a list of pods for which --previous isn't collected, to be outputted with verbose flag - for _, pod := range pods.Items { - for _, container := range pod.Spec.Containers { - wg.Add(1) - go func(pod, container string) { - if err := semaphore.Acquire(ctx, 1); err != nil { - // return err - } - defer semaphore.Release(1) - defer wg.Done() - f := getPastContainerLog(ctx, pod, container, namespace, baseDir) - if f.err == nil { - ch <- f - } else { - if verbose { - fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", pod, f.err) - } - } - }(pod.Metadata.Name, container.Name) - } - } - - // start goroutine for each pod to run kubectl describe pod - for _, pod := range pods.Items { - wg.Add(1) - go func(pod string) { - if err := semaphore.Acquire(ctx, 1); err != nil { - // return err - } - defer semaphore.Release(1) - defer wg.Done() - ch <- getDescribe(ctx, pod, namespace, baseDir) - }(pod.Metadata.Name) - } - - // start goroutine for each pod to run kubectl get pod -o yaml - for _, pod := range pods.Items { - wg.Add(1) - go func(pod string) { - if err := semaphore.Acquire(ctx, 1); err != nil { - // return err - } - defer semaphore.Release(1) - defer wg.Done() - ch <- getManifest(ctx, pod, namespace, baseDir) - }(pod.Metadata.Name) - } - - // start goroutine to get external service config - if configs == true { - wg.Add(1) - go func() { - if err := semaphore.Acquire(ctx, 1); err != nil { - // return err - } - defer semaphore.Release(1) - defer wg.Done() - ch <- getExternalServicesConfig(ctx, baseDir) - }() - - wg.Add(1) - go func() { - if err := semaphore.Acquire(ctx, 1); err != nil { - // return err - } - defer semaphore.Release(1) - defer wg.Done() - ch <- getSiteConfig(ctx, baseDir) - }() - } - - // close channel when wait group goroutines have completed - go func() { - wg.Wait() - close(ch) - }() - - // write to archive all the outputs from kubectl call functions passed to buffer channel - for f := range ch { - if f.err != nil { - log.Printf("getting data for %s failed: %v\noutput: %s", f.name, f.err, f.data) - continue - } - - if verbose { - log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) - } - - zf, err := zw.Create(f.name) - if err != nil { - return fmt.Errorf("failed to create %s: %w", f.name, err) - } - - _, err = zf.Write(f.data) - if err != nil { - return fmt.Errorf("failed to write to %s: %w", f.name, err) - } - } - - return nil -} - -func getPods(ctx context.Context, namespace string) (podList, error) { - // Declare buffer type var for kubectl pipe - var podsBuff bytes.Buffer - - // Get all pod names as json - getPods := exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pods", "-l", "deploy=sourcegraph", "-o=json") - getPods.Stdout = &podsBuff - getPods.Stderr = os.Stderr - err := getPods.Run() - - //Declare struct to format decode from podList - var pods podList - - //Decode json from podList - if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { - fmt.Errorf("failed to unmarshall get pods json: %w", err) - } - - return pods, err -} - -func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/events.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "events").CombinedOutput() - return f -} - -func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pv").CombinedOutput() - return f -} - -func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pvc").CombinedOutput() - return f -} - -// get kubectl logs for pod containers -func getContainerLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", podName, "-c", containerName).CombinedOutput() - return f -} - -// get kubectl logs for past container -func getPastContainerLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} - cmdStr := []string{"kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName).CombinedOutput() - if f.err != nil { - f.err = errors.Wrapf(f.err, "executing command: %s: received error: %s", cmdStr, f.data) - } - return f -} - -func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "describe", "pod", podName).CombinedOutput() - return f -} - -func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml").CombinedOutput() - return f -} - -/* -Docker functions -TODO: handle for single container/server instance -*/ - -func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, baseDir string) error { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - containers, err := getContainers(ctx) - if err != nil { - return fmt.Errorf("failed to get docker containers: %w", err) - } - - if verbose { - log.Printf("getting docker data for %d containers...\n", len(containers)) - } - - // setup channel for slice of archive function outputs - ch := make(chan *archiveFile) - wg := sync.WaitGroup{} - - // start goroutine to run docker container stats --no-stream - wg.Add(1) - go func() { - defer wg.Done() - ch <- getStats(ctx, baseDir) - }() - - // start goroutine to run docker container logs - for _, container := range containers { - wg.Add(1) - go func(container string) { - defer wg.Done() - ch <- getLog(ctx, container, baseDir) - }(container) - } - - // start goroutine to run docker container inspect - for _, container := range containers { - wg.Add(1) - go func(container string) { - defer wg.Done() - ch <- getInspect(ctx, container, baseDir) - }(container) - } - - // start goroutine to get configs - if configs == true { - wg.Add(1) - go func() { - defer wg.Done() - ch <- getExternalServicesConfig(ctx, baseDir) - }() - - wg.Add(1) - go func() { - defer wg.Done() - ch <- getSiteConfig(ctx, baseDir) - }() - } - - // close channel when wait group goroutines have completed - go func() { - wg.Wait() - close(ch) - }() - - for f := range ch { - if f.err != nil { - return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) - } - - if verbose { - log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) - } - - zf, err := zw.Create(f.name) - if err != nil { - return fmt.Errorf("failed to create %s: %w", f.name, err) - } - - _, err = zf.Write(f.data) - if err != nil { - return fmt.Errorf("failed to write to %s: %w", f.name, err) - } - } - - return nil -} - -func getContainers(ctx context.Context) ([]string, error) { - c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}} {{.Networks}}").Output() - if err != nil { - fmt.Errorf("failed to get container names with error: %w", err) - } - s := string(c) - preprocessed := strings.Split(strings.TrimSpace(s), "\n") - containers := []string{} - for _, container := range preprocessed { - tmpStr := strings.Split(container, " ") - if tmpStr[1] == "docker-compose_sourcegraph" { - containers = append(containers, tmpStr[0]) - } - } - return containers, err -} - -func getLog(ctx context.Context, container, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/" + container + ".log"} - f.data, f.err = exec.CommandContext(ctx, "docker", "container", "logs", container).CombinedOutput() - return f -} - -func getInspect(ctx context.Context, container, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/inspect-" + container + ".txt"} - f.data, f.err = exec.CommandContext(ctx, "docker", "container", "inspect", container).CombinedOutput() - return f -} - -func getStats(ctx context.Context, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/docker/stats.txt"} - f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() - return f -} diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 053d4114f0..4affd58fdf 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -1,11 +1,14 @@ package main import ( + "archive/zip" "context" "flag" "fmt" "log" + "os/exec" "strings" + "sync" "unicode" "github.com/sourcegraph/src-cli/internal/cmderrors" @@ -95,3 +98,129 @@ Examples: }, }) } + +/* +Docker functions +TODO: handle for single container/server instance +*/ + +func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, baseDir string) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + containers, err := getContainers(ctx) + if err != nil { + return fmt.Errorf("failed to get docker containers: %w", err) + } + + if verbose { + log.Printf("getting docker data for %d containers...\n", len(containers)) + } + + // setup channel for slice of archive function outputs + ch := make(chan *archiveFile) + wg := sync.WaitGroup{} + + // start goroutine to run docker container stats --no-stream + wg.Add(1) + go func() { + defer wg.Done() + ch <- getStats(ctx, baseDir) + }() + + // start goroutine to run docker container logs + for _, container := range containers { + wg.Add(1) + go func(container string) { + defer wg.Done() + ch <- getLog(ctx, container, baseDir) + }(container) + } + + // start goroutine to run docker container inspect + for _, container := range containers { + wg.Add(1) + go func(container string) { + defer wg.Done() + ch <- getInspect(ctx, container, baseDir) + }(container) + } + + // start goroutine to get configs + if configs == true { + wg.Add(1) + go func() { + defer wg.Done() + ch <- getExternalServicesConfig(ctx, baseDir) + }() + + wg.Add(1) + go func() { + defer wg.Done() + ch <- getSiteConfig(ctx, baseDir) + }() + } + + // close channel when wait group goroutines have completed + go func() { + wg.Wait() + close(ch) + }() + + for f := range ch { + if f.err != nil { + return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) + } + + if verbose { + log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) + } + + zf, err := zw.Create(f.name) + if err != nil { + return fmt.Errorf("failed to create %s: %w", f.name, err) + } + + _, err = zf.Write(f.data) + if err != nil { + return fmt.Errorf("failed to write to %s: %w", f.name, err) + } + } + + return nil +} + +func getContainers(ctx context.Context) ([]string, error) { + c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}} {{.Networks}}").Output() + if err != nil { + fmt.Errorf("failed to get container names with error: %w", err) + } + s := string(c) + preprocessed := strings.Split(strings.TrimSpace(s), "\n") + containers := []string{} + for _, container := range preprocessed { + tmpStr := strings.Split(container, " ") + if tmpStr[1] == "docker-compose_sourcegraph" { + containers = append(containers, tmpStr[0]) + } + } + return containers, err +} + +func getLog(ctx context.Context, container, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/" + container + ".log"} + f.data, f.err = exec.CommandContext(ctx, "docker", "container", "logs", container).CombinedOutput() + return f +} + +func getInspect(ctx context.Context, container, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/inspect-" + container + ".txt"} + f.data, f.err = exec.CommandContext(ctx, "docker", "container", "inspect", container).CombinedOutput() + return f +} + +func getStats(ctx context.Context, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/docker/stats.txt"} + f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() + return f +} diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index a7bba2b054..920a0514be 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -1,19 +1,25 @@ package main import ( + "archive/zip" + "bytes" "context" + "encoding/json" "flag" "fmt" "log" + "os" "strings" + "sync" "unicode" + "golang.org/x/sync/semaphore" + + "github.com/sourcegraph/sourcegraph/lib/errors" "github.com/sourcegraph/src-cli/internal/cmderrors" "github.com/sourcegraph/src-cli/internal/exec" ) -// TODO: seperate graphQL API call functions from archiveKube main function -- in accordance with database dumps, and prometheus, these should be optional via flags - func init() { usage := ` 'src debug kube' mocks kubectl commands to gather information about a kubernetes sourcegraph instance. @@ -111,3 +117,250 @@ Examples: }, }) } + +type podList struct { + Items []struct { + Metadata struct { + Name string + } + Spec struct { + Containers []struct { + Name string + } + } + } +} + +// Run kubectl functions concurrently and archive results to zip file +func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, namespace, baseDir string, pods podList) error { + // Create a context with a cancel function that we call when returning + // from archiveKube. This ensures we close all pending go-routines when returning + // early because of an error. + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // setup channel for slice of archive function outputs, as well as throttling semaphore + ch := make(chan *archiveFile) + wg := sync.WaitGroup{} + semaphore := semaphore.NewWeighted(8) + + // create goroutine to get kubectl events + wg.Add(1) + go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getEvents(ctx, namespace, baseDir) + }() + + // create goroutine to get persistent volumes + wg.Add(1) + go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getPV(ctx, namespace, baseDir) + }() + + // create goroutine to get persistent volumes claim + wg.Add(1) + go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getPVC(ctx, namespace, baseDir) + }() + + // start goroutine to run kubectl logs for each pod's container's + for _, pod := range pods.Items { + for _, container := range pod.Spec.Containers { + wg.Add(1) + go func(pod, container string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getContainerLog(ctx, pod, container, namespace, baseDir) + }(pod.Metadata.Name, container.Name) + } + } + + // start goroutine to run kubectl logs --previous for each pod's container's + // won't write to zip on err, only passes bytes to channel if err not nil + // TODO: It may be nice to store a list of pods for which --previous isn't collected, to be outputted with verbose flag + for _, pod := range pods.Items { + for _, container := range pod.Spec.Containers { + wg.Add(1) + go func(pod, container string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + f := getPastContainerLog(ctx, pod, container, namespace, baseDir) + if f.err == nil { + ch <- f + } else { + if verbose { + fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", pod, f.err) + } + } + }(pod.Metadata.Name, container.Name) + } + } + + // start goroutine for each pod to run kubectl describe pod + for _, pod := range pods.Items { + wg.Add(1) + go func(pod string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getDescribe(ctx, pod, namespace, baseDir) + }(pod.Metadata.Name) + } + + // start goroutine for each pod to run kubectl get pod -o yaml + for _, pod := range pods.Items { + wg.Add(1) + go func(pod string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getManifest(ctx, pod, namespace, baseDir) + }(pod.Metadata.Name) + } + + // start goroutine to get external service config + if configs == true { + wg.Add(1) + go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getExternalServicesConfig(ctx, baseDir) + }() + + wg.Add(1) + go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getSiteConfig(ctx, baseDir) + }() + } + + // close channel when wait group goroutines have completed + go func() { + wg.Wait() + close(ch) + }() + + // write to archive all the outputs from kubectl call functions passed to buffer channel + for f := range ch { + if f.err != nil { + log.Printf("getting data for %s failed: %v\noutput: %s", f.name, f.err, f.data) + continue + } + + if verbose { + log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) + } + + zf, err := zw.Create(f.name) + if err != nil { + return fmt.Errorf("failed to create %s: %w", f.name, err) + } + + _, err = zf.Write(f.data) + if err != nil { + return fmt.Errorf("failed to write to %s: %w", f.name, err) + } + } + + return nil +} + +func getPods(ctx context.Context, namespace string) (podList, error) { + // Declare buffer type var for kubectl pipe + var podsBuff bytes.Buffer + + // Get all pod names as json + getPods := exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pods", "-l", "deploy=sourcegraph", "-o=json") + getPods.Stdout = &podsBuff + getPods.Stderr = os.Stderr + err := getPods.Run() + + //Declare struct to format decode from podList + var pods podList + + //Decode json from podList + if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { + fmt.Errorf("failed to unmarshall get pods json: %w", err) + } + + return pods, err +} + +func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/events.txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "events").CombinedOutput() + return f +} + +func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pv").CombinedOutput() + return f +} + +func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pvc").CombinedOutput() + return f +} + +// get kubectl logs for pod containers +func getContainerLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", podName, "-c", containerName).CombinedOutput() + return f +} + +// get kubectl logs for past container +func getPastContainerLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} + cmdStr := []string{"kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName).CombinedOutput() + if f.err != nil { + f.err = errors.Wrapf(f.err, "executing command: %s: received error: %s", cmdStr, f.data) + } + return f +} + +func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "describe", "pod", podName).CombinedOutput() + return f +} + +func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { + f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} + f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml").CombinedOutput() + return f +} From d080d660b6bb2cb5b125d4a87773563ff1e34cde Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 26 Apr 2022 03:07:45 -0700 Subject: [PATCH 063/107] converted all kube commands to , renamed kube getContainers to getPods --- cmd/src/debug_common.go | 13 ++++-- cmd/src/debug_comp.go | 4 +- cmd/src/debug_kube.go | 88 +++++++++++++++++++++++++++-------------- 3 files changed, 69 insertions(+), 36 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index e38ecd4114..d52eecbde1 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -94,8 +94,13 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile // TODO: correctly format json output before writing to zip func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { const siteConfigStr = `query { site { configuration { effectiveContents } } }` - f := &archiveFile{name: baseDir + "/config/siteConfig.json"} - f.data, f.err = exec.CommandContext(ctx, os.Args[0], "api", "-query", siteConfigStr).CombinedOutput() - - return f + return archiveFileFromCommand(ctx, baseDir, "/config/siteConfig.json", os.Args[0], "api", "-query", siteConfigStr) } + +//func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { +// const siteConfigStr = `query { site { configuration { effectiveContents } } }` +// f := &archiveFile{name: baseDir + "/config/siteConfig.json"} +// f.data, f.err = exec.CommandContext(ctx, os.Args[0], "api", "-query", siteConfigStr).CombinedOutput() +// +// return f +//} diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 4affd58fdf..4a19b4b884 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -133,7 +133,7 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b wg.Add(1) go func(container string) { defer wg.Done() - ch <- getLog(ctx, container, baseDir) + ch <- getContainerLog(ctx, container, baseDir) }(container) } @@ -207,7 +207,7 @@ func getContainers(ctx context.Context) ([]string, error) { return containers, err } -func getLog(ctx context.Context, container, baseDir string) *archiveFile { +func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/" + container + ".log"} f.data, f.err = exec.CommandContext(ctx, "docker", "container", "logs", container).CombinedOutput() return f diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 920a0514be..b4cdddd95d 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -9,13 +9,13 @@ import ( "fmt" "log" "os" + "path" "strings" "sync" "unicode" "golang.org/x/sync/semaphore" - "github.com/sourcegraph/sourcegraph/lib/errors" "github.com/sourcegraph/src-cli/internal/cmderrors" "github.com/sourcegraph/src-cli/internal/exec" ) @@ -187,7 +187,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam } defer semaphore.Release(1) defer wg.Done() - ch <- getContainerLog(ctx, pod, container, namespace, baseDir) + ch <- getPodLog(ctx, pod, container, namespace, baseDir) }(pod.Metadata.Name, container.Name) } } @@ -204,7 +204,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam } defer semaphore.Release(1) defer wg.Done() - f := getPastContainerLog(ctx, pod, container, namespace, baseDir) + f := getPastPodLog(ctx, pod, container, namespace, baseDir) if f.err == nil { ch <- f } else { @@ -318,49 +318,77 @@ func getPods(ctx context.Context, namespace string) (podList, error) { } func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/events.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "events").CombinedOutput() - return f + return archiveFileFromCommand(ctx, baseDir, "/kubectl/events.txt", "kubectl", "-n", namespace, "get", "events") } +//func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/kubectl/events.txt"} +// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "events").CombinedOutput() +// return f +//} + func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pv").CombinedOutput() - return f + return archiveFileFromCommand(ctx, baseDir, "/kubectl/persistent-volumes.txt", "kubectl", "-n", namespace, "get", "pv") } +//func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} +// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pv").CombinedOutput() +// return f +//} + func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pvc").CombinedOutput() - return f + return archiveFileFromCommand(ctx, baseDir, "/kubectl/persistent-volume-claims.txt", "kubectl", "-n", namespace, "get", "pvc") } +//func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} +// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pvc").CombinedOutput() +// return f +//} + // get kubectl logs for pod containers -func getContainerLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", podName, "-c", containerName).CombinedOutput() - return f +func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { + return archiveFileFromCommand(ctx, baseDir, path.Join("/kubectl/pods/", podName, containerName)+".log", "kubectl", "-n", namespace, "logs", podName, "-c", containerName) } +//func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} +// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", podName, "-c", containerName).CombinedOutput() +// return f +//} + // get kubectl logs for past container -func getPastContainerLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} - cmdStr := []string{"kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName).CombinedOutput() - if f.err != nil { - f.err = errors.Wrapf(f.err, "executing command: %s: received error: %s", cmdStr, f.data) - } - return f +func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { + return archiveFileFromCommand(ctx, baseDir, path.Join("/kubectl/pods/", podName, "prev-"+containerName)+".log", "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName) } +//func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} +// cmdStr := []string{"kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName} +// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName).CombinedOutput() +// if f.err != nil { +// f.err = errors.Wrapf(f.err, "executing command: %s: received error: %s", cmdStr, f.data) +// } +// return f +//} + func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "describe", "pod", podName).CombinedOutput() - return f + return archiveFileFromCommand(ctx, baseDir, path.Join("/kubectl/pods/", podName, "/describe-"+podName)+".txt", "kubectl", "-n", namespace, "describe", "pod", podName) } +//func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} +// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "describe", "pod", podName).CombinedOutput() +// return f +//} + func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} - f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml").CombinedOutput() - return f + return archiveFileFromCommand(ctx, baseDir, path.Join("/kubectl/pods/", podName, "/manifest-"+podName)+".yaml", "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml") } + +//func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} +// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml").CombinedOutput() +// return f +//} From a33444c90bd89bd039e3cf9a3aa25927590bef3b Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Tue, 26 Apr 2022 03:22:27 -0700 Subject: [PATCH 064/107] refactored compose functions with archiveFileFromCommand --- cmd/src/debug_comp.go | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 4a19b4b884..0664ac63c6 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -7,6 +7,7 @@ import ( "fmt" "log" "os/exec" + "path" "strings" "sync" "unicode" @@ -208,19 +209,31 @@ func getContainers(ctx context.Context) ([]string, error) { } func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/" + container + ".log"} - f.data, f.err = exec.CommandContext(ctx, "docker", "container", "logs", container).CombinedOutput() - return f + return archiveFileFromCommand(ctx, baseDir, path.Join("/docker/containers/", container, container)+".log", "docker", "container", "logs", container) } +//func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/" + container + ".log"} +// f.data, f.err = exec.CommandContext(ctx, "docker", "container", "logs", container).CombinedOutput() +// return f +//} + func getInspect(ctx context.Context, container, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/inspect-" + container + ".txt"} - f.data, f.err = exec.CommandContext(ctx, "docker", "container", "inspect", container).CombinedOutput() - return f + return archiveFileFromCommand(ctx, baseDir, path.Join("/docker/containers/", container, "/inspect-"+container)+".txt", "docker", "container", "inspect", container) } +//func getInspect(ctx context.Context, container, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/inspect-" + container + ".txt"} +// f.data, f.err = exec.CommandContext(ctx, "docker", "container", "inspect", container).CombinedOutput() +// return f +//} + func getStats(ctx context.Context, baseDir string) *archiveFile { - f := &archiveFile{name: baseDir + "/docker/stats.txt"} - f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() - return f + return archiveFileFromCommand(ctx, baseDir, "/docker/stats.txt", "docker", "container", "stats", "--no-stream") } + +//func getStats(ctx context.Context, baseDir string) *archiveFile { +// f := &archiveFile{name: baseDir + "/docker/stats.txt"} +// f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() +// return f +//} From 688ccee4068b1f249ae92d6bb6a4d877ffb12b33 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 27 Apr 2022 22:55:10 -0700 Subject: [PATCH 065/107] Made archiveFileFromCommand calls aesthetically pleasing, added docker ps, and get pods commands as a sort of index --- cmd/src/debug_common.go | 17 +++++++---- cmd/src/debug_comp.go | 33 +++++++++++++++++++-- cmd/src/debug_kube.go | 64 +++++++++++++++++++++++++++++++++++------ 3 files changed, 97 insertions(+), 17 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index d52eecbde1..9a37102e51 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -5,7 +5,7 @@ import ( "context" "fmt" "os" - "path/filepath" + "path" "strings" "syscall" @@ -25,8 +25,8 @@ type archiveFile struct { err error } -func archiveFileFromCommand(ctx context.Context, baseDir, path, cmd string, args ...string) *archiveFile { - f := &archiveFile{name: filepath.Join(baseDir, path)} +func archiveFileFromCommand(ctx context.Context, path, cmd string, args ...string) *archiveFile { + f := &archiveFile{name: path} f.data, f.err = exec.CommandContext(ctx, cmd, args...).CombinedOutput() if f.err != nil { f.err = errors.Wrapf(f.err, "executing command: %s %s: received error: %s", cmd, strings.Join(args, " "), f.data) @@ -78,7 +78,11 @@ func setupDebug(base string) (*os.File, *zip.Writer, context.Context, error) { //and then returns an archiveFile to be consumed func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` - return archiveFileFromCommand(ctx, baseDir, "/config/external_services.txt", os.Args[0], "extsvc", "list", "-f", fmtStr) + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/config/external_services.txt"), + os.Args[0], "extsvc", "list", "-f", fmtStr, + ) } //func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { @@ -94,7 +98,10 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile // TODO: correctly format json output before writing to zip func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { const siteConfigStr = `query { site { configuration { effectiveContents } } }` - return archiveFileFromCommand(ctx, baseDir, "/config/siteConfig.json", os.Args[0], "api", "-query", siteConfigStr) + return archiveFileFromCommand(ctx, + path.Join(baseDir, "/config/siteConfig.json"), + os.Args[0], "api", "-query", siteConfigStr, + ) } //func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 0664ac63c6..1f6f705832 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -122,6 +122,13 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b ch := make(chan *archiveFile) wg := sync.WaitGroup{} + // start goroutine to run docker ps -o wide + wg.Add(1) + go func() { + defer wg.Done() + ch <- getPs(ctx, baseDir) + }() + // start goroutine to run docker container stats --no-stream wg.Add(1) go func() { @@ -208,8 +215,20 @@ func getContainers(ctx context.Context) ([]string, error) { return containers, err } +func getPs(ctx context.Context, baseDir string) *archiveFile { + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/docker/docker-ps")+".txt", + "docker", "ps", + ) +} + func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, path.Join("/docker/containers/", container, container)+".log", "docker", "container", "logs", container) + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/docker/containers/", container, container)+".log", + "docker", "container", "logs", container, + ) } //func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { @@ -219,7 +238,11 @@ func getContainerLog(ctx context.Context, container, baseDir string) *archiveFil //} func getInspect(ctx context.Context, container, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, path.Join("/docker/containers/", container, "/inspect-"+container)+".txt", "docker", "container", "inspect", container) + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/docker/containers/", container, "/inspect-"+container)+".txt", + "docker", "container", "inspect", container, + ) } //func getInspect(ctx context.Context, container, baseDir string) *archiveFile { @@ -229,7 +252,11 @@ func getInspect(ctx context.Context, container, baseDir string) *archiveFile { //} func getStats(ctx context.Context, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, "/docker/stats.txt", "docker", "container", "stats", "--no-stream") + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/docker/stats")+".txt", + "docker", "container", "stats", "--no-stream", + ) } //func getStats(ctx context.Context, baseDir string) *archiveFile { diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index b4cdddd95d..833c0f66b5 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -72,7 +72,7 @@ Examples: ctx := context.Background() - pods, err := getPods(ctx, namespace) + pods, err := selectPods(ctx, namespace) if err != nil { return fmt.Errorf("failed to get pods: %w", err) } @@ -144,6 +144,16 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg := sync.WaitGroup{} semaphore := semaphore.NewWeighted(8) + wg.Add(1) + go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + // return err + } + defer semaphore.Release(1) + defer wg.Done() + ch <- getPods(ctx, namespace, baseDir) + }() + // create goroutine to get kubectl events wg.Add(1) go func() { @@ -296,7 +306,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam return nil } -func getPods(ctx context.Context, namespace string) (podList, error) { +func selectPods(ctx context.Context, namespace string) (podList, error) { // Declare buffer type var for kubectl pipe var podsBuff bytes.Buffer @@ -317,8 +327,20 @@ func getPods(ctx context.Context, namespace string) (podList, error) { return pods, err } +func getPods(ctx context.Context, namespace, baseDir string) *archiveFile { + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/kubectl/getPods.txt"), + "kubectl", "-n", namespace, "get", "pods", "-o", "wide", + ) +} + func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, "/kubectl/events.txt", "kubectl", "-n", namespace, "get", "events") + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/kubectl/events.txt"), + "kubectl", "-n", namespace, "get", "events", + ) } //func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { @@ -328,7 +350,11 @@ func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { //} func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, "/kubectl/persistent-volumes.txt", "kubectl", "-n", namespace, "get", "pv") + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/kubectl/persistent-volumes.txt"), + "kubectl", "-n", namespace, "get", "pv", + ) } //func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { @@ -338,7 +364,11 @@ func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { //} func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, "/kubectl/persistent-volume-claims.txt", "kubectl", "-n", namespace, "get", "pvc") + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/kubectl/persistent-volume-claims.txt"), + "kubectl", "-n", namespace, "get", "pvc", + ) } //func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { @@ -349,7 +379,11 @@ func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { // get kubectl logs for pod containers func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, path.Join("/kubectl/pods/", podName, containerName)+".log", "kubectl", "-n", namespace, "logs", podName, "-c", containerName) + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/kubectl/pods/", podName, containerName)+".log", + "kubectl", "-n", namespace, "logs", podName, "-c", containerName, + ) } //func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { @@ -360,7 +394,11 @@ func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir s // get kubectl logs for past container func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, path.Join("/kubectl/pods/", podName, "prev-"+containerName)+".log", "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName) + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/kubectl/pods/", podName, "prev-"+containerName)+".log", + "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName, + ) } //func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { @@ -374,7 +412,11 @@ func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseD //} func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, path.Join("/kubectl/pods/", podName, "/describe-"+podName)+".txt", "kubectl", "-n", namespace, "describe", "pod", podName) + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/kubectl/pods/", podName, "/describe-"+podName)+".txt", + "kubectl", "-n", namespace, "describe", "pod", podName, + ) } //func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { @@ -384,7 +426,11 @@ func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archi //} func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { - return archiveFileFromCommand(ctx, baseDir, path.Join("/kubectl/pods/", podName, "/manifest-"+podName)+".yaml", "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml") + return archiveFileFromCommand( + ctx, + path.Join(baseDir, "/kubectl/pods/", podName, "/manifest-"+podName)+".yaml", + "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml", + ) } //func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { From e1fe03d6b627c4d63bde997e8810dfd7d0ade8c6 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 27 Apr 2022 23:08:12 -0700 Subject: [PATCH 066/107] changes all path package calls to path/filepath calls --- cmd/src/debug_common.go | 6 +++--- cmd/src/debug_comp.go | 10 +++++----- cmd/src/debug_kube.go | 18 +++++++++--------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 9a37102e51..b7b1549070 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -5,7 +5,7 @@ import ( "context" "fmt" "os" - "path" + "path/filepath" "strings" "syscall" @@ -80,7 +80,7 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` return archiveFileFromCommand( ctx, - path.Join(baseDir, "/config/external_services.txt"), + filepath.Join(baseDir, "/config/external_services.txt"), os.Args[0], "extsvc", "list", "-f", fmtStr, ) } @@ -99,7 +99,7 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { const siteConfigStr = `query { site { configuration { effectiveContents } } }` return archiveFileFromCommand(ctx, - path.Join(baseDir, "/config/siteConfig.json"), + filepath.Join(baseDir, "/config/siteConfig.json"), os.Args[0], "api", "-query", siteConfigStr, ) } diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 1f6f705832..4e3bf2ad02 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -7,7 +7,7 @@ import ( "fmt" "log" "os/exec" - "path" + "path/filepath" "strings" "sync" "unicode" @@ -218,7 +218,7 @@ func getContainers(ctx context.Context) ([]string, error) { func getPs(ctx context.Context, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/docker/docker-ps")+".txt", + filepath.Join(baseDir, "/docker/docker-ps")+".txt", "docker", "ps", ) } @@ -226,7 +226,7 @@ func getPs(ctx context.Context, baseDir string) *archiveFile { func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/docker/containers/", container, container)+".log", + filepath.Join(baseDir, "/docker/containers/", container, container)+".log", "docker", "container", "logs", container, ) } @@ -240,7 +240,7 @@ func getContainerLog(ctx context.Context, container, baseDir string) *archiveFil func getInspect(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/docker/containers/", container, "/inspect-"+container)+".txt", + filepath.Join(baseDir, "/docker/containers/", container, "/inspect-"+container)+".txt", "docker", "container", "inspect", container, ) } @@ -254,7 +254,7 @@ func getInspect(ctx context.Context, container, baseDir string) *archiveFile { func getStats(ctx context.Context, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/docker/stats")+".txt", + filepath.Join(baseDir, "/docker/stats")+".txt", "docker", "container", "stats", "--no-stream", ) } diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 833c0f66b5..7d84943c09 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -9,7 +9,7 @@ import ( "fmt" "log" "os" - "path" + "path/filepath" "strings" "sync" "unicode" @@ -330,7 +330,7 @@ func selectPods(ctx context.Context, namespace string) (podList, error) { func getPods(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/kubectl/getPods.txt"), + filepath.Join(baseDir, "/kubectl/getPods.txt"), "kubectl", "-n", namespace, "get", "pods", "-o", "wide", ) } @@ -338,7 +338,7 @@ func getPods(ctx context.Context, namespace, baseDir string) *archiveFile { func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/kubectl/events.txt"), + filepath.Join(baseDir, "/kubectl/events.txt"), "kubectl", "-n", namespace, "get", "events", ) } @@ -352,7 +352,7 @@ func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/kubectl/persistent-volumes.txt"), + filepath.Join(baseDir, "/kubectl/persistent-volumes.txt"), "kubectl", "-n", namespace, "get", "pv", ) } @@ -366,7 +366,7 @@ func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/kubectl/persistent-volume-claims.txt"), + filepath.Join(baseDir, "/kubectl/persistent-volume-claims.txt"), "kubectl", "-n", namespace, "get", "pvc", ) } @@ -381,7 +381,7 @@ func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/kubectl/pods/", podName, containerName)+".log", + filepath.Join(baseDir, "/kubectl/pods/", podName, containerName)+".log", "kubectl", "-n", namespace, "logs", podName, "-c", containerName, ) } @@ -396,7 +396,7 @@ func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir s func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/kubectl/pods/", podName, "prev-"+containerName)+".log", + filepath.Join(baseDir, "/kubectl/pods/", podName, "prev-"+containerName)+".log", "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName, ) } @@ -414,7 +414,7 @@ func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseD func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/kubectl/pods/", podName, "/describe-"+podName)+".txt", + filepath.Join(baseDir, "/kubectl/pods/", podName, "/describe-"+podName)+".txt", "kubectl", "-n", namespace, "describe", "pod", podName, ) } @@ -428,7 +428,7 @@ func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archi func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - path.Join(baseDir, "/kubectl/pods/", podName, "/manifest-"+podName)+".yaml", + filepath.Join(baseDir, "/kubectl/pods/", podName, "/manifest-"+podName)+".yaml", "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml", ) } From df05363f9f054bed6e74ddbcefa5420b3d54a6e1 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 27 Apr 2022 23:14:11 -0700 Subject: [PATCH 067/107] emptied graveyard --- cmd/src/debug_common.go | 17 --------------- cmd/src/debug_comp.go | 18 ---------------- cmd/src/debug_kube.go | 46 ----------------------------------------- 3 files changed, 81 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index b7b1549070..2f7921a449 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -85,15 +85,6 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile ) } -//func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { -// const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` -// -// f := &archiveFile{name: baseDir + "/config/external_services.txt"} -// f.data, f.err = exec.CommandContext(ctx, os.Args[0], "extsvc", "list", "-f", fmtStr).CombinedOutput() -// -// return f -//} - // getSiteConfig calls src api -query=... to query the api for site config json // TODO: correctly format json output before writing to zip func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { @@ -103,11 +94,3 @@ func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { os.Args[0], "api", "-query", siteConfigStr, ) } - -//func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { -// const siteConfigStr = `query { site { configuration { effectiveContents } } }` -// f := &archiveFile{name: baseDir + "/config/siteConfig.json"} -// f.data, f.err = exec.CommandContext(ctx, os.Args[0], "api", "-query", siteConfigStr).CombinedOutput() -// -// return f -//} diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 4e3bf2ad02..e9b835c8cd 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -231,12 +231,6 @@ func getContainerLog(ctx context.Context, container, baseDir string) *archiveFil ) } -//func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/" + container + ".log"} -// f.data, f.err = exec.CommandContext(ctx, "docker", "container", "logs", container).CombinedOutput() -// return f -//} - func getInspect(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -245,12 +239,6 @@ func getInspect(ctx context.Context, container, baseDir string) *archiveFile { ) } -//func getInspect(ctx context.Context, container, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/docker/containers/" + container + "/inspect-" + container + ".txt"} -// f.data, f.err = exec.CommandContext(ctx, "docker", "container", "inspect", container).CombinedOutput() -// return f -//} - func getStats(ctx context.Context, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -258,9 +246,3 @@ func getStats(ctx context.Context, baseDir string) *archiveFile { "docker", "container", "stats", "--no-stream", ) } - -//func getStats(ctx context.Context, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/docker/stats.txt"} -// f.data, f.err = exec.CommandContext(ctx, "docker", "container", "stats", "--no-stream").CombinedOutput() -// return f -//} diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 7d84943c09..8944f7b2ac 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -343,12 +343,6 @@ func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { ) } -//func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/kubectl/events.txt"} -// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "events").CombinedOutput() -// return f -//} - func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -357,12 +351,6 @@ func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { ) } -//func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/kubectl/persistent-volumes.txt"} -// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pv").CombinedOutput() -// return f -//} - func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -371,12 +359,6 @@ func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { ) } -//func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/kubectl/persistent-volume-claims.txt"} -// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pvc").CombinedOutput() -// return f -//} - // get kubectl logs for pod containers func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( @@ -386,12 +368,6 @@ func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir s ) } -//func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + containerName + ".log"} -// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", podName, "-c", containerName).CombinedOutput() -// return f -//} - // get kubectl logs for past container func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( @@ -401,16 +377,6 @@ func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseD ) } -//func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/" + "prev-" + containerName + ".log"} -// cmdStr := []string{"kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName} -// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName).CombinedOutput() -// if f.err != nil { -// f.err = errors.Wrapf(f.err, "executing command: %s: received error: %s", cmdStr, f.data) -// } -// return f -//} - func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -419,12 +385,6 @@ func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archi ) } -//func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/describe-" + podName + ".txt"} -// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "describe", "pod", podName).CombinedOutput() -// return f -//} - func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -432,9 +392,3 @@ func getManifest(ctx context.Context, podName, namespace, baseDir string) *archi "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml", ) } - -//func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { -// f := &archiveFile{name: baseDir + "/kubectl/pods/" + podName + "/manifest-" + podName + ".yaml"} -// f.data, f.err = exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml").CombinedOutput() -// return f -//} From 9c656bd95308883ad64420900e37d17b6c5cf317 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 27 Apr 2022 23:24:54 -0700 Subject: [PATCH 068/107] return early from failed semaphore.Acquire rather than reading error --- cmd/src/debug_kube.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 8944f7b2ac..7611664268 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -147,7 +147,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func() { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() @@ -158,7 +158,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func() { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() @@ -169,7 +169,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func() { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() @@ -180,7 +180,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func() { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() @@ -193,7 +193,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func(pod, container string) { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() @@ -210,7 +210,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func(pod, container string) { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() @@ -231,7 +231,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func(pod string) { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() @@ -244,7 +244,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func(pod string) { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() @@ -257,7 +257,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func() { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() @@ -267,7 +267,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam wg.Add(1) go func() { if err := semaphore.Acquire(ctx, 1); err != nil { - // return err + return } defer semaphore.Release(1) defer wg.Done() From 38f5ce1da998267f781b52bfe88ee53d0bb68e29 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 28 Apr 2022 01:47:04 -0700 Subject: [PATCH 069/107] handle errors, remove direct comparison to booleans --- cmd/src/debug_comp.go | 7 +++++-- cmd/src/debug_kube.go | 20 ++++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index e9b835c8cd..bf3012b532 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -53,7 +53,7 @@ Examples: } // declare basedir for archive file structure var baseDir string - if strings.HasSuffix(base, ".zip") == false { + if !strings.HasSuffix(base, ".zip") { baseDir = base base = base + ".zip" } else { @@ -62,6 +62,9 @@ Examples: ctx := context.Background() containers, err := getContainers(ctx) + if err != nil { + fmt.Errorf("failed to get containers for subcommand with err: %v", err) + } log.Printf("Archiving docker-cli data for %d containers\n SRC_ENDPOINT: %v\n Output filename: %v", len(containers), cfg.Endpoint, base) @@ -155,7 +158,7 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b } // start goroutine to get configs - if configs == true { + if configs { wg.Add(1) go func() { defer wg.Done() diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 7611664268..7c52622046 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -253,7 +253,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam } // start goroutine to get external service config - if configs == true { + if configs { wg.Add(1) go func() { if err := semaphore.Acquire(ctx, 1); err != nil { @@ -311,15 +311,19 @@ func selectPods(ctx context.Context, namespace string) (podList, error) { var podsBuff bytes.Buffer // Get all pod names as json - getPods := exec.CommandContext(ctx, "kubectl", "-n", namespace, "get", "pods", "-l", "deploy=sourcegraph", "-o=json") - getPods.Stdout = &podsBuff - getPods.Stderr = os.Stderr - err := getPods.Run() - - //Declare struct to format decode from podList - var pods podList + podsCmd := exec.CommandContext( + ctx, + "kubectl", "-n", namespace, "get", "pods", "-l", "deploy=sourcegraph", "-o=json", + ) + podsCmd.Stdout = &podsBuff + podsCmd.Stderr = os.Stderr + err := podsCmd.Run() + if err != nil { + fmt.Errorf("failed to aquire pods for subcommands with err: %v", err) + } //Decode json from podList + var pods podList if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { fmt.Errorf("failed to unmarshall get pods json: %w", err) } From d6d71e5a92608b1b3daf94ae95e56c16f4e011d6 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 28 Apr 2022 02:13:05 -0700 Subject: [PATCH 070/107] cleaned up some more linter erros --- cmd/src/debug_kube.go | 8 +++----- cmd/src/debug_serv.go | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 7c52622046..41cf4ed8f5 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -63,7 +63,7 @@ Examples: } // declare basedir for archive file structure var baseDir string - if strings.HasSuffix(base, ".zip") == false { + if !strings.HasSuffix(base, ".zip") { baseDir = base base = base + ".zip" } else { @@ -217,10 +217,8 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam f := getPastPodLog(ctx, pod, container, namespace, baseDir) if f.err == nil { ch <- f - } else { - if verbose { - fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", pod, f.err) - } + } else if verbose { + fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", pod, f.err) } }(pod.Metadata.Name, container.Name) } diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index ca47813bc6..8be74c8e7c 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -46,7 +46,7 @@ Examples: } // declare basedir for archive file structure var baseDir string - if strings.HasSuffix(base, ".zip") == false { + if !strings.HasSuffix(base, ".zip") { baseDir = base base = base + ".zip" } else { From 023cbe0441d775dc422da701a0817fea5fda1896 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 29 Apr 2022 00:23:02 -0700 Subject: [PATCH 071/107] refactor adding verify func --- cmd/src/debug_common.go | 13 +++++++++++++ cmd/src/debug_comp.go | 18 +++++------------- cmd/src/debug_kube.go | 17 +++++------------ 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 2f7921a449..12b9aeab49 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -34,6 +34,19 @@ func archiveFileFromCommand(ctx context.Context, path, cmd string, args ...strin return f } +// This function prompts the user to confirm they want to run the command +func verify(confirmationText string) (bool, error) { + input := "" + for strings.ToLower(input) != "y" && strings.ToLower(input) != "n" { + fmt.Printf("%s [y/N]: ", confirmationText) + if _, err := fmt.Scanln(&input); err != nil { + return false, err + } + } + + return strings.ToLower(input) == "y", nil +} + // setOpenFileLimits increases the limit of open files to the given number. This is needed // when doings lots of concurrent network requests which establish open sockets. func setOpenFileLimits(n uint64) error { diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index bf3012b532..f44550b26d 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -10,7 +10,6 @@ import ( "path/filepath" "strings" "sync" - "unicode" "github.com/sourcegraph/src-cli/internal/cmderrors" ) @@ -61,22 +60,15 @@ Examples: } ctx := context.Background() + + //Gather data for safety check containers, err := getContainers(ctx) if err != nil { fmt.Errorf("failed to get containers for subcommand with err: %v", err) } - - log.Printf("Archiving docker-cli data for %d containers\n SRC_ENDPOINT: %v\n Output filename: %v", len(containers), cfg.Endpoint, base) - - var verify string - fmt.Print("Do you want to start writing to an archive? [y/n] ") - _, err = fmt.Scanln(&verify) - for unicode.ToLower(rune(verify[0])) != 'y' && unicode.ToLower(rune(verify[0])) != 'n' { - fmt.Println("Input must be string y or n") - _, err = fmt.Scanln(&verify) - } - if unicode.ToLower(rune(verify[0])) == 'n' { - fmt.Println("escaping") + // Safety check user knows what they are targeting with this debug command + log.Printf("This command will archive docker-cli data for %d containers\n SRC_ENDPOINT: %v\n Output filename: %v", len(containers), cfg.Endpoint, base) + if verified, _ := verify("Do you want to start writing to an archive?"); !verified { return nil } diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 41cf4ed8f5..ab4a7aa1d3 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -12,7 +12,6 @@ import ( "path/filepath" "strings" "sync" - "unicode" "golang.org/x/sync/semaphore" @@ -72,6 +71,9 @@ Examples: ctx := context.Background() + //TODO: improve formating to include 'ls' like pod listing for pods targeted. + + // Gather data for safety check pods, err := selectPods(ctx, namespace) if err != nil { return fmt.Errorf("failed to get pods: %w", err) @@ -80,18 +82,9 @@ Examples: if err != nil { return fmt.Errorf("failed to get current-context: %w", err) } - //TODO: improve formating to include 'ls' like pod listing for pods targeted. + // Safety check user knows what they've targeted with this command log.Printf("Archiving kubectl data for %d pods\n SRC_ENDPOINT: %v\n Context: %s Namespace: %v\n Output filename: %v", len(pods.Items), cfg.Endpoint, kubectx, namespace, base) - - var verify string - fmt.Print("Do you want to start writing to an archive? [y/n] ") - _, err = fmt.Scanln(&verify) - for unicode.ToLower(rune(verify[0])) != 'y' && unicode.ToLower(rune(verify[0])) != 'n' { - fmt.Println("Input must be string y or n") - _, err = fmt.Scanln(&verify) - } - if unicode.ToLower(rune(verify[0])) == 'n' { - fmt.Println("escaping") + if verified, _ := verify("Do you want to start writing to an archive?"); !verified { return nil } From 3fafa35535e953e21dbe62af7b65183349234bb0 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 29 Apr 2022 00:31:12 -0700 Subject: [PATCH 072/107] fixed final improperly handled error --- cmd/src/debug_comp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index f44550b26d..e52f8c9ed1 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -196,7 +196,7 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b func getContainers(ctx context.Context) ([]string, error) { c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}} {{.Networks}}").Output() if err != nil { - fmt.Errorf("failed to get container names with error: %w", err) + return nil, fmt.Errorf("failed to get container names with error: %w", err) } s := string(c) preprocessed := strings.Split(strings.TrimSpace(s), "\n") From 7ecd7de512858620c18ed3013f3900fbb6d2775a Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 29 Apr 2022 00:36:32 -0700 Subject: [PATCH 073/107] use semaphore in debug comp --- cmd/src/debug_comp.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index e52f8c9ed1..b8ee66aa76 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -11,6 +11,8 @@ import ( "strings" "sync" + "golang.org/x/sync/semaphore" + "github.com/sourcegraph/src-cli/internal/cmderrors" ) @@ -116,10 +118,15 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b // setup channel for slice of archive function outputs ch := make(chan *archiveFile) wg := sync.WaitGroup{} + semaphore := semaphore.NewWeighted(8) // start goroutine to run docker ps -o wide wg.Add(1) go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + return + } + defer semaphore.Release(1) defer wg.Done() ch <- getPs(ctx, baseDir) }() @@ -127,6 +134,10 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b // start goroutine to run docker container stats --no-stream wg.Add(1) go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + return + } + defer semaphore.Release(1) defer wg.Done() ch <- getStats(ctx, baseDir) }() @@ -135,6 +146,10 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b for _, container := range containers { wg.Add(1) go func(container string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + return + } + defer semaphore.Release(1) defer wg.Done() ch <- getContainerLog(ctx, container, baseDir) }(container) @@ -144,6 +159,10 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b for _, container := range containers { wg.Add(1) go func(container string) { + if err := semaphore.Acquire(ctx, 1); err != nil { + return + } + defer semaphore.Release(1) defer wg.Done() ch <- getInspect(ctx, container, baseDir) }(container) @@ -153,12 +172,20 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b if configs { wg.Add(1) go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + return + } + defer semaphore.Release(1) defer wg.Done() ch <- getExternalServicesConfig(ctx, baseDir) }() wg.Add(1) go func() { + if err := semaphore.Acquire(ctx, 1); err != nil { + return + } + defer semaphore.Release(1) defer wg.Done() ch <- getSiteConfig(ctx, baseDir) }() From daa38e83eb979642d3e17d7807b4700469b84739 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 29 Apr 2022 15:02:29 -0700 Subject: [PATCH 074/107] working errgroups in comp --- cmd/src/debug_comp.go | 67 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index b8ee66aa76..c4b1c9ef13 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -9,7 +9,8 @@ import ( "os/exec" "path/filepath" "strings" - "sync" + + "golang.org/x/sync/errgroup" "golang.org/x/sync/semaphore" @@ -117,83 +118,79 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b // setup channel for slice of archive function outputs ch := make(chan *archiveFile) - wg := sync.WaitGroup{} + g, ctx := errgroup.WithContext(ctx) semaphore := semaphore.NewWeighted(8) // start goroutine to run docker ps -o wide - wg.Add(1) - go func() { + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getPs(ctx, baseDir) - }() + return nil + }) // start goroutine to run docker container stats --no-stream - wg.Add(1) - go func() { + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getStats(ctx, baseDir) - }() + return nil + }) // start goroutine to run docker container logs for _, container := range containers { - wg.Add(1) - go func(container string) { + c := container + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() - ch <- getContainerLog(ctx, container, baseDir) - }(container) + ch <- getContainerLog(ctx, c, baseDir) + return nil + }) } // start goroutine to run docker container inspect for _, container := range containers { - wg.Add(1) - go func(container string) { + c := container + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() - ch <- getInspect(ctx, container, baseDir) - }(container) + ch <- getInspect(ctx, c, baseDir) + return nil + }) } // start goroutine to get configs if configs { - wg.Add(1) - go func() { + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getExternalServicesConfig(ctx, baseDir) - }() + return nil + }) - wg.Add(1) - go func() { + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getSiteConfig(ctx, baseDir) - }() + return nil + }) } // close channel when wait group goroutines have completed go func() { - wg.Wait() + g.Wait() close(ch) }() From e5c3f8c603cecc4658799189b31313ea759b7b6d Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 29 Apr 2022 15:35:56 -0700 Subject: [PATCH 075/107] refactor to errgroup in kube --- cmd/src/debug_kube.go | 114 +++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 58 deletions(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index ab4a7aa1d3..c761048575 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -11,7 +11,8 @@ import ( "os" "path/filepath" "strings" - "sync" + + "golang.org/x/sync/errgroup" "golang.org/x/sync/semaphore" @@ -134,64 +135,62 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam // setup channel for slice of archive function outputs, as well as throttling semaphore ch := make(chan *archiveFile) - wg := sync.WaitGroup{} + g, ctx := errgroup.WithContext(ctx) semaphore := semaphore.NewWeighted(8) - wg.Add(1) - go func() { + // create goroutine to get pods + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getPods(ctx, namespace, baseDir) - }() + return nil + }) // create goroutine to get kubectl events - wg.Add(1) - go func() { + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getEvents(ctx, namespace, baseDir) - }() + return nil + }) // create goroutine to get persistent volumes - wg.Add(1) - go func() { + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getPV(ctx, namespace, baseDir) - }() + return nil + }) // create goroutine to get persistent volumes claim - wg.Add(1) - go func() { + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getPVC(ctx, namespace, baseDir) - }() + return nil + }) // start goroutine to run kubectl logs for each pod's container's for _, pod := range pods.Items { for _, container := range pod.Spec.Containers { - wg.Add(1) - go func(pod, container string) { + p := pod.Metadata.Name + c := container.Name + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() - ch <- getPodLog(ctx, pod, container, namespace, baseDir) - }(pod.Metadata.Name, container.Name) + ch <- getPodLog(ctx, p, c, namespace, baseDir) + return nil + }) } } @@ -200,75 +199,74 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam // TODO: It may be nice to store a list of pods for which --previous isn't collected, to be outputted with verbose flag for _, pod := range pods.Items { for _, container := range pod.Spec.Containers { - wg.Add(1) - go func(pod, container string) { + p := pod.Metadata.Name + c := container.Name + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() - f := getPastPodLog(ctx, pod, container, namespace, baseDir) + f := getPastPodLog(ctx, p, c, namespace, baseDir) if f.err == nil { ch <- f } else if verbose { - fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", pod, f.err) + fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", p, f.err) } - }(pod.Metadata.Name, container.Name) + return nil + }) } } // start goroutine for each pod to run kubectl describe pod for _, pod := range pods.Items { - wg.Add(1) - go func(pod string) { + p := pod.Metadata.Name + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() - ch <- getDescribe(ctx, pod, namespace, baseDir) - }(pod.Metadata.Name) + ch <- getDescribe(ctx, p, namespace, baseDir) + return nil + }) } // start goroutine for each pod to run kubectl get pod -o yaml for _, pod := range pods.Items { - wg.Add(1) - go func(pod string) { + p := pod.Metadata.Name + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() - ch <- getManifest(ctx, pod, namespace, baseDir) - }(pod.Metadata.Name) + ch <- getManifest(ctx, p, namespace, baseDir) + return nil + }) } // start goroutine to get external service config if configs { - wg.Add(1) - go func() { + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getExternalServicesConfig(ctx, baseDir) - }() + return nil + }) - wg.Add(1) - go func() { + g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { - return + return err } defer semaphore.Release(1) - defer wg.Done() ch <- getSiteConfig(ctx, baseDir) - }() + return nil + }) } // close channel when wait group goroutines have completed go func() { - wg.Wait() + g.Wait() close(ch) }() From 4bdba62668f606f9d9d410b8f5b8a2bfcc885e8c Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 29 Apr 2022 17:07:04 -0700 Subject: [PATCH 076/107] refactored writer in archive functions --- cmd/src/debug_common.go | 26 ++++++++++++++++++++++++++ cmd/src/debug_comp.go | 21 +++------------------ cmd/src/debug_kube.go | 23 +++-------------------- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 12b9aeab49..419e27425f 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -4,6 +4,7 @@ import ( "archive/zip" "context" "fmt" + "log" "os" "path/filepath" "strings" @@ -85,6 +86,31 @@ func setupDebug(base string) (*os.File, *zip.Writer, context.Context, error) { return out, zw, ctx, err } +// write to archive all the outputs from kubectl call functions passed to buffer channel +func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose bool) error { + for f := range ch { + if f.err != nil { + log.Printf("getting data for %s failed: %v\noutput: %s", f.name, f.err, f.data) + continue + } + + if verbose { + log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) + } + + zf, err := zw.Create(f.name) + if err != nil { + return fmt.Errorf("failed to create %s: %w", f.name, err) + } + + _, err = zf.Write(f.data) + if err != nil { + return fmt.Errorf("failed to write to %s: %w", f.name, err) + } + } + return nil +} + // TODO: Currently external services and site configs are pulled using the src endpoints // getExternalServicesConfig calls src extsvc list with the format flag -f, diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index c4b1c9ef13..8301a80f0c 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -194,24 +194,9 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b close(ch) }() - for f := range ch { - if f.err != nil { - return fmt.Errorf("aborting due to error on %s: %v\noutput: %s", f.name, f.err, f.data) - } - - if verbose { - log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) - } - - zf, err := zw.Create(f.name) - if err != nil { - return fmt.Errorf("failed to create %s: %w", f.name, err) - } - - _, err = zf.Write(f.data) - if err != nil { - return fmt.Errorf("failed to write to %s: %w", f.name, err) - } + // Read binarys from channel and write to archive on host machine + if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { + return fmt.Errorf("failed to write archives from channel: %w", err) } return nil diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index c761048575..af1c6d5d1c 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -270,26 +270,9 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam close(ch) }() - // write to archive all the outputs from kubectl call functions passed to buffer channel - for f := range ch { - if f.err != nil { - log.Printf("getting data for %s failed: %v\noutput: %s", f.name, f.err, f.data) - continue - } - - if verbose { - log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) - } - - zf, err := zw.Create(f.name) - if err != nil { - return fmt.Errorf("failed to create %s: %w", f.name, err) - } - - _, err = zf.Write(f.data) - if err != nil { - return fmt.Errorf("failed to write to %s: %w", f.name, err) - } + // Read binarys from channel and write to archive on host machine + if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { + return fmt.Errorf("failed to write archives from channel: %w", err) } return nil From 6b3507895c6cfe149a99a5c88b381ba3a478399c Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Sun, 1 May 2022 20:43:32 -0700 Subject: [PATCH 077/107] corrected all complex filepath calls using fmt.Sprintf() --- cmd/src/debug_common.go | 4 ++-- cmd/src/debug_comp.go | 11 +++++------ cmd/src/debug_kube.go | 18 +++++++++--------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 419e27425f..2f29e85e77 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -119,7 +119,7 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/config/external_services.txt"), + filepath.Join(baseDir, "config", "external_services.txt"), os.Args[0], "extsvc", "list", "-f", fmtStr, ) } @@ -129,7 +129,7 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { const siteConfigStr = `query { site { configuration { effectiveContents } } }` return archiveFileFromCommand(ctx, - filepath.Join(baseDir, "/config/siteConfig.json"), + filepath.Join(baseDir, "config", "siteConfig.json"), os.Args[0], "api", "-query", siteConfigStr, ) } diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 8301a80f0c..7e39616b95 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -100,7 +100,6 @@ Examples: /* Docker functions -TODO: handle for single container/server instance */ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, baseDir string) error { @@ -194,7 +193,7 @@ func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, b close(ch) }() - // Read binarys from channel and write to archive on host machine + // Read binaries from channel and write to archive on host machine if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { return fmt.Errorf("failed to write archives from channel: %w", err) } @@ -222,7 +221,7 @@ func getContainers(ctx context.Context) ([]string, error) { func getPs(ctx context.Context, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/docker/docker-ps")+".txt", + filepath.Join(baseDir, "docker", "docker-ps.txt"), "docker", "ps", ) } @@ -230,7 +229,7 @@ func getPs(ctx context.Context, baseDir string) *archiveFile { func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/docker/containers/", container, container)+".log", + filepath.Join(baseDir, "docker", "containers", container, fmt.Sprintf("%v.log", container)), "docker", "container", "logs", container, ) } @@ -238,7 +237,7 @@ func getContainerLog(ctx context.Context, container, baseDir string) *archiveFil func getInspect(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/docker/containers/", container, "/inspect-"+container)+".txt", + filepath.Join(baseDir, "docker", "containers", container, fmt.Sprintf("inspect-%v.txt", container)), "docker", "container", "inspect", container, ) } @@ -246,7 +245,7 @@ func getInspect(ctx context.Context, container, baseDir string) *archiveFile { func getStats(ctx context.Context, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/docker/stats")+".txt", + filepath.Join(baseDir, "docker", "stats.txt"), "docker", "container", "stats", "--no-stream", ) } diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index af1c6d5d1c..257d7fad0a 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -270,7 +270,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam close(ch) }() - // Read binarys from channel and write to archive on host machine + // Read binaries from channel and write to archive on host machine if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { return fmt.Errorf("failed to write archives from channel: %w", err) } @@ -306,7 +306,7 @@ func selectPods(ctx context.Context, namespace string) (podList, error) { func getPods(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/kubectl/getPods.txt"), + filepath.Join(baseDir, "kubectl", "getPods.txt"), "kubectl", "-n", namespace, "get", "pods", "-o", "wide", ) } @@ -314,7 +314,7 @@ func getPods(ctx context.Context, namespace, baseDir string) *archiveFile { func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/kubectl/events.txt"), + filepath.Join(baseDir, "kubectl", "events.txt"), "kubectl", "-n", namespace, "get", "events", ) } @@ -322,7 +322,7 @@ func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/kubectl/persistent-volumes.txt"), + filepath.Join(baseDir, "kubectl", "persistent-volumes.txt"), "kubectl", "-n", namespace, "get", "pv", ) } @@ -330,7 +330,7 @@ func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/kubectl/persistent-volume-claims.txt"), + filepath.Join(baseDir, "kubectl", "persistent-volume-claims.txt"), "kubectl", "-n", namespace, "get", "pvc", ) } @@ -339,7 +339,7 @@ func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/kubectl/pods/", podName, containerName)+".log", + filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("%v.log", containerName)), "kubectl", "-n", namespace, "logs", podName, "-c", containerName, ) } @@ -348,7 +348,7 @@ func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir s func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/kubectl/pods/", podName, "prev-"+containerName)+".log", + filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("prev-%v.log", containerName)), "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName, ) } @@ -356,7 +356,7 @@ func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseD func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/kubectl/pods/", podName, "/describe-"+podName)+".txt", + filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("describe-%v.txt", podName)), "kubectl", "-n", namespace, "describe", "pod", podName, ) } @@ -364,7 +364,7 @@ func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archi func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "/kubectl/pods/", podName, "/manifest-"+podName)+".yaml", + filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("manifest-%v.yaml", podName)), "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml", ) } From 94a653828fcf27087b88ea1e78fae2c8bf0fe2ad Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 2 May 2022 01:52:20 -0700 Subject: [PATCH 078/107] filter docker ps output to appropriate network --- cmd/src/debug_comp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 7e39616b95..f6a91950cf 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -222,7 +222,7 @@ func getPs(ctx context.Context, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, filepath.Join(baseDir, "docker", "docker-ps.txt"), - "docker", "ps", + "docker", "ps", "--filter", "network=docker-compose_sourcegraph", ) } From f759711d3d1db30cc243fe7c9694d330f77775ab Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 2 May 2022 02:47:58 -0700 Subject: [PATCH 079/107] removed setup debug as will as openfile limit adjustment --- cmd/src/debug_common.go | 22 ---------------------- cmd/src/debug_comp.go | 34 +++++++++++++++++++--------------- cmd/src/debug_kube.go | 17 ++++++++++------- cmd/src/debug_serv.go | 12 ++++++++++-- 4 files changed, 39 insertions(+), 46 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 2f29e85e77..1e8aa34171 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -64,28 +64,6 @@ func setOpenFileLimits(n uint64) error { return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) } -// setupDebug takes the name of a base directory and returns the file pipe, zip writer, -// and context needed for later archive functions. Don't forget to defer close on these -// after calling setupDebug! -func setupDebug(base string) (*os.File, *zip.Writer, context.Context, error) { - // open pipe to output file - out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to open file: %w", err) - } - // increase limit of open files - err = setOpenFileLimits(64000) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to set open file limits: %w", err) - } - // init zip writer - zw := zip.NewWriter(out) - // init context - ctx := context.Background() - - return out, zw, ctx, err -} - // write to archive all the outputs from kubectl call functions passed to buffer channel func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose bool) error { for f := range ch { diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index f6a91950cf..379db80eb4 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -6,6 +6,7 @@ import ( "flag" "fmt" "log" + "os" "os/exec" "path/filepath" "strings" @@ -62,7 +63,17 @@ Examples: baseDir = strings.TrimSuffix(base, ".zip") } + // init context ctx := context.Background() + // open pipe to output file + out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) + if err != nil { + fmt.Errorf("failed to open file: %w", err) + } + defer out.Close() + // init zip writer + zw := zip.NewWriter(out) + defer zw.Close() //Gather data for safety check containers, err := getContainers(ctx) @@ -75,13 +86,6 @@ Examples: return nil } - out, zw, ctx, err := setupDebug(base) - if err != nil { - return fmt.Errorf("failed to open file: %w", err) - } - defer out.Close() - defer zw.Close() - err = archiveDocker(ctx, zw, *verbose, configs, baseDir) if err != nil { return cmderrors.ExitCode(1, nil) @@ -226,6 +230,14 @@ func getPs(ctx context.Context, baseDir string) *archiveFile { ) } +func getStats(ctx context.Context, baseDir string) *archiveFile { + return archiveFileFromCommand( + ctx, + filepath.Join(baseDir, "docker", "stats.txt"), + "docker", "container", "stats", "--no-stream", + ) +} + func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -241,11 +253,3 @@ func getInspect(ctx context.Context, container, baseDir string) *archiveFile { "docker", "container", "inspect", container, ) } - -func getStats(ctx context.Context, baseDir string) *archiveFile { - return archiveFileFromCommand( - ctx, - filepath.Join(baseDir, "docker", "stats.txt"), - "docker", "container", "stats", "--no-stream", - ) -} diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 257d7fad0a..9642d1b387 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -70,7 +70,17 @@ Examples: baseDir = strings.TrimSuffix(base, ".zip") } + // init context ctx := context.Background() + // open pipe to output file + out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) + if err != nil { + fmt.Errorf("failed to open file: %w", err) + } + defer out.Close() + // init zip writer + zw := zip.NewWriter(out) + defer zw.Close() //TODO: improve formating to include 'ls' like pod listing for pods targeted. @@ -89,13 +99,6 @@ Examples: return nil } - out, zw, ctx, err := setupDebug(base) - if err != nil { - return err - } - defer out.Close() - defer zw.Close() - err = archiveKube(ctx, zw, *verbose, configs, namespace, baseDir, pods) if err != nil { return cmderrors.ExitCode(1, err) diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index 8be74c8e7c..4f285080ef 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -1,8 +1,11 @@ package main import ( + "archive/zip" + "context" "flag" "fmt" + "os" "strings" "github.com/sourcegraph/src-cli/internal/cmderrors" @@ -53,11 +56,16 @@ Examples: baseDir = strings.TrimSuffix(base, ".zip") } - out, zw, ctx, err := setupDebug(base) + // init context + ctx := context.Background() + // open pipe to output file + out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { - return fmt.Errorf("failed to open file: %w", err) + fmt.Errorf("failed to open file: %w", err) } defer out.Close() + // init zip writer + zw := zip.NewWriter(out) defer zw.Close() err = archiveDocker(ctx, zw, *verbose, configs, baseDir) From 06640e535eedade098479b94baf965a324bd082b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senart?= Date: Mon, 2 May 2022 18:00:37 +0200 Subject: [PATCH 080/107] normalize site config --- cmd/src/debug_common.go | 34 +++++++++++++++++++++++++++++++--- go.mod | 2 +- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 1e8aa34171..61397bc55b 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -3,6 +3,7 @@ package main import ( "archive/zip" "context" + "encoding/json" "fmt" "log" "os" @@ -10,8 +11,10 @@ import ( "strings" "syscall" - "github.com/sourcegraph/sourcegraph/lib/errors" + "github.com/sourcegraph/jsonx" "github.com/sourcegraph/src-cli/internal/exec" + + "github.com/sourcegraph/sourcegraph/lib/errors" ) /* @@ -92,7 +95,7 @@ func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose b // TODO: Currently external services and site configs are pulled using the src endpoints // getExternalServicesConfig calls src extsvc list with the format flag -f, -//and then returns an archiveFile to be consumed +// and then returns an archiveFile to be consumed func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile { const fmtStr = `{{range .Nodes}}{{.id}} | {{.kind}} | {{.displayName}}{{"\n"}}{{.config}}{{"\n---\n"}}{{end}}` return archiveFileFromCommand( @@ -106,8 +109,33 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile // TODO: correctly format json output before writing to zip func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { const siteConfigStr = `query { site { configuration { effectiveContents } } }` - return archiveFileFromCommand(ctx, + f := archiveFileFromCommand(ctx, filepath.Join(baseDir, "config", "siteConfig.json"), os.Args[0], "api", "-query", siteConfigStr, ) + + if f.err != nil { + return f + } + + var siteConfig struct { + Site struct { + Configuration struct { + EffectiveContents json.RawMessage + } + } + } + + normalized, errs := jsonx.Parse(string(siteConfig.Site.Configuration.EffectiveContents), jsonx.ParseOptions{ + Comments: true, + TrailingCommas: true, + }) + + if len(errs) > 0 { + f.err = errors.Errorf("failed to parse site config as JSONC: %v", errs) + return f + } + + f.data = normalized + return f } diff --git a/go.mod b/go.mod index 0b8f2dd5fe..29cb553be8 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/sourcegraph/sourcegraph/lib v0.0.0-20220414150621-eeb00fcedd88 github.com/stretchr/testify v1.7.1 golang.org/x/net v0.0.0-20220325170049-de3da57026de + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b jaytaylor.com/html2text v0.0.0-20200412013138-3577fbdbcff7 ) @@ -55,7 +56,6 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect gopkg.in/yaml.v2 v2.4.0 // indirect From 8ecdff346eb03aa7e4ba3d7d62ee0caaeffa4f4a Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 2 May 2022 09:35:09 -0700 Subject: [PATCH 081/107] correctly process json --- cmd/src/debug_common.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 61397bc55b..5e8273d734 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -11,7 +11,6 @@ import ( "strings" "syscall" - "github.com/sourcegraph/jsonx" "github.com/sourcegraph/src-cli/internal/exec" "github.com/sourcegraph/sourcegraph/lib/errors" @@ -119,23 +118,20 @@ func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { } var siteConfig struct { - Site struct { - Configuration struct { - EffectiveContents json.RawMessage + Data struct { + Site struct { + Configuration struct { + EffectiveContents string + } } } } - normalized, errs := jsonx.Parse(string(siteConfig.Site.Configuration.EffectiveContents), jsonx.ParseOptions{ - Comments: true, - TrailingCommas: true, - }) - - if len(errs) > 0 { - f.err = errors.Errorf("failed to parse site config as JSONC: %v", errs) + f.err = json.Unmarshal(f.data, &siteConfig) + if f.err != nil { return f } - f.data = normalized + f.data = []byte(siteConfig.Data.Site.Configuration.EffectiveContents) return f } From 4396daadf571bbfd4ed450e2b9406264647f6b68 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Mon, 2 May 2022 15:58:17 -0700 Subject: [PATCH 082/107] fleshed out serv command --- cmd/src/debug_comp.go | 4 +- cmd/src/debug_serv.go | 122 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 120 insertions(+), 6 deletions(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 379db80eb4..d03a109ffd 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -86,7 +86,7 @@ Examples: return nil } - err = archiveDocker(ctx, zw, *verbose, configs, baseDir) + err = archiveCompose(ctx, zw, *verbose, configs, baseDir) if err != nil { return cmderrors.ExitCode(1, nil) } @@ -106,7 +106,7 @@ Examples: Docker functions */ -func archiveDocker(ctx context.Context, zw *zip.Writer, verbose, configs bool, baseDir string) error { +func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, configs bool, baseDir string) error { ctx, cancel := context.WithCancel(ctx) defer cancel() diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index 4f285080ef..c7404f3da5 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -5,9 +5,14 @@ import ( "context" "flag" "fmt" + "log" "os" + "path/filepath" "strings" + "golang.org/x/sync/errgroup" + "golang.org/x/sync/semaphore" + "github.com/sourcegraph/src-cli/internal/cmderrors" ) @@ -26,27 +31,32 @@ Flags: Examples: - $ src debug serv -o debug.zip + $ src debug serv -c foo -o debug.zip - $ src -v debug serv -cfg=false -o foo.zip + $ src -v debug serv -cfg=false -c ViktorVaughn -o foo.zip ` flagSet := flag.NewFlagSet("serv", flag.ExitOnError) var base string + var container string var configs bool flagSet.BoolVar(&configs, "cfg", true, "If true include Sourcegraph configuration files. Default value true.") flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") + flagSet.StringVar(&container, "c", "", "The container to target") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { return err } - //validate out flag + //validate required flags aren't empty if base == "" { return fmt.Errorf("empty -o flag") } + if container == "" { + return fmt.Errorf("empty -c flag, specifying a container is required") + } // declare basedir for archive file structure var baseDir string if !strings.HasSuffix(base, ".zip") { @@ -68,7 +78,13 @@ Examples: zw := zip.NewWriter(out) defer zw.Close() - err = archiveDocker(ctx, zw, *verbose, configs, baseDir) + // Safety check user knows what they are targeting with this debug command + log.Printf("This command will archive docker-cli data for container: %v\n SRC_ENDPOINT: %v\n Output filename: %v", container, cfg.Endpoint, base) + if verified, _ := verify("Do you want to start writing to an archive?"); !verified { + return nil + } + + err = archiveServ(ctx, zw, *verbose, configs, container, baseDir) if err != nil { return cmderrors.ExitCode(1, nil) } @@ -83,3 +99,101 @@ Examples: }, }) } + +func archiveServ(ctx context.Context, zw *zip.Writer, verbose, configs bool, container, baseDir string) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // setup channel for slice of archive function outputs + ch := make(chan *archiveFile) + g, ctx := errgroup.WithContext(ctx) + semaphore := semaphore.NewWeighted(8) + + // start goroutine to run docker ps -o wide + g.Go(func() error { + if err := semaphore.Acquire(ctx, 1); err != nil { + return err + } + defer semaphore.Release(1) + ch <- getServLog(ctx, container, baseDir) + return nil + }) + + // start goroutine to run docker ps -o wide + g.Go(func() error { + if err := semaphore.Acquire(ctx, 1); err != nil { + return err + } + defer semaphore.Release(1) + ch <- getServInspect(ctx, container, baseDir) + return nil + }) + + // start goroutine to run docker ps -o wide + g.Go(func() error { + if err := semaphore.Acquire(ctx, 1); err != nil { + return err + } + defer semaphore.Release(1) + ch <- getServTop(ctx, container, baseDir) + return nil + }) + + // start goroutine to get configs + if configs { + g.Go(func() error { + if err := semaphore.Acquire(ctx, 1); err != nil { + return err + } + defer semaphore.Release(1) + ch <- getExternalServicesConfig(ctx, baseDir) + return nil + }) + + g.Go(func() error { + if err := semaphore.Acquire(ctx, 1); err != nil { + return err + } + defer semaphore.Release(1) + ch <- getSiteConfig(ctx, baseDir) + return nil + }) + } + + // close channel when wait group goroutines have completed + go func() { + g.Wait() + close(ch) + }() + + // Read binaries from channel and write to archive on host machine + if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { + return fmt.Errorf("failed to write archives from channel: %w", err) + } + + return nil +} + +func getServLog(ctx context.Context, container, baseDir string) *archiveFile { + return archiveFileFromCommand( + ctx, + filepath.Join(baseDir, fmt.Sprintf("%v.log", container)), + "docker", "container", "logs", container, + ) +} + +func getServInspect(ctx context.Context, container, baseDir string) *archiveFile { + return archiveFileFromCommand( + ctx, + filepath.Join(baseDir, fmt.Sprintf("inspect-%v.txt", container)), + "docker", "container", "inspect", container, + ) +} + +func getServTop(ctx context.Context, container, baseDir string) *archiveFile { + return archiveFileFromCommand( + ctx, + filepath.Join(baseDir, fmt.Sprintf("top-%v.txt", container)), + "docker", "top", container, + ) +} From c42c855128c86dc4cc04d673ba5e59e5ff61547f Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Wed, 4 May 2022 22:22:50 -0700 Subject: [PATCH 083/107] Update .gitignore Co-authored-by: Eric Fritz --- .gitignore | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 4488faf466..c4b8f452b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -src -cmd/src/src -cmd/src/*.zip +./src +./cmd/src/src +*.zip release ./vendor .idea From 9e12b5fa01630685fe05fb943bdb8683f3971c1f Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Wed, 4 May 2022 22:51:48 -0700 Subject: [PATCH 084/107] Apply suggestions from code review Implementation of Eric's review suggestions; untested, requiring duplication in other files Co-authored-by: Eric Fritz --- cmd/src/debug_common.go | 5 ++--- cmd/src/debug_comp.go | 23 +++++++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 5e8273d734..f8270432dc 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -66,7 +66,7 @@ func setOpenFileLimits(n uint64) error { return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) } -// write to archive all the outputs from kubectl call functions passed to buffer channel +// write all the outputs from an archive command passed on the channel to to the zip writer func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose bool) error { for f := range ch { if f.err != nil { @@ -83,8 +83,7 @@ func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose b return fmt.Errorf("failed to create %s: %w", f.name, err) } - _, err = zf.Write(f.data) - if err != nil { + if _, err := zf.Write(f.data); err != nil { return fmt.Errorf("failed to write to %s: %w", f.name, err) } } diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index d03a109ffd..faf248cdfc 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -125,11 +125,18 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, configs bool, semaphore := semaphore.NewWeighted(8) // start goroutine to run docker ps -o wide - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run := func(f func() error) { + g.Go(func() error { + if err := semaphore.Acquire(ctx, 1); err != nil { + return err + } + defer semaphore.Release(1) + + return f() + }() + } + + run(func() error { ch <- getPs(ctx, baseDir) return nil }) @@ -146,7 +153,7 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, configs bool, // start goroutine to run docker container logs for _, container := range containers { - c := container + container := container g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { return err @@ -199,7 +206,7 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, configs bool, // Read binaries from channel and write to archive on host machine if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { - return fmt.Errorf("failed to write archives from channel: %w", err) + return errors.Wrap(err, "failed to write archives from channel") } return nil @@ -212,7 +219,7 @@ func getContainers(ctx context.Context) ([]string, error) { } s := string(c) preprocessed := strings.Split(strings.TrimSpace(s), "\n") - containers := []string{} + containers := make(string, 0, len(preprocessed)) for _, container := range preprocessed { tmpStr := strings.Split(container, " ") if tmpStr[1] == "docker-compose_sourcegraph" { From ed870e53cbba78182d6e8e2c87ffad87269d4e86 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 4 May 2022 23:52:45 -0700 Subject: [PATCH 085/107] implement and repair infered refactors in erics suggestions --- cmd/src/debug_common.go | 17 ---------- cmd/src/debug_comp.go | 48 +++++++++------------------- cmd/src/debug_kube.go | 71 ++++++++++++----------------------------- cmd/src/debug_serv.go | 41 ++++++++++-------------- 4 files changed, 52 insertions(+), 125 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index f8270432dc..a58ada1ab7 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -9,7 +9,6 @@ import ( "os" "path/filepath" "strings" - "syscall" "github.com/sourcegraph/src-cli/internal/exec" @@ -50,22 +49,6 @@ func verify(confirmationText string) (bool, error) { return strings.ToLower(input) == "y", nil } -// setOpenFileLimits increases the limit of open files to the given number. This is needed -// when doings lots of concurrent network requests which establish open sockets. -func setOpenFileLimits(n uint64) error { - - var rlimit syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) - if err != nil { - return err - } - - rlimit.Max = n - rlimit.Cur = n - - return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) -} - // write all the outputs from an archive command passed on the channel to to the zip writer func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose bool) error { for f := range ch { diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index faf248cdfc..5ffa24dc10 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -11,6 +11,8 @@ import ( "path/filepath" "strings" + "github.com/sourcegraph/sourcegraph/lib/errors" + "golang.org/x/sync/errgroup" "golang.org/x/sync/semaphore" @@ -124,29 +126,25 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, configs bool, g, ctx := errgroup.WithContext(ctx) semaphore := semaphore.NewWeighted(8) - // start goroutine to run docker ps -o wide run := func(f func() error) { g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { return err } defer semaphore.Release(1) - + return f() - }() + }) } - + + // start goroutine to run docker ps -o wide run(func() error { ch <- getPs(ctx, baseDir) return nil }) // start goroutine to run docker container stats --no-stream - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getStats(ctx, baseDir) return nil }) @@ -154,45 +152,29 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, configs bool, // start goroutine to run docker container logs for _, container := range containers { container := container - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) - ch <- getContainerLog(ctx, c, baseDir) + run(func() error { + ch <- getContainerLog(ctx, container, baseDir) return nil }) } // start goroutine to run docker container inspect for _, container := range containers { - c := container - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) - ch <- getInspect(ctx, c, baseDir) + container := container + run(func() error { + ch <- getInspect(ctx, container, baseDir) return nil }) } // start goroutine to get configs if configs { - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getExternalServicesConfig(ctx, baseDir) return nil }) - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getSiteConfig(ctx, baseDir) return nil }) @@ -219,7 +201,7 @@ func getContainers(ctx context.Context) ([]string, error) { } s := string(c) preprocessed := strings.Split(strings.TrimSpace(s), "\n") - containers := make(string, 0, len(preprocessed)) + containers := make([]string, 0, len(preprocessed)) for _, container := range preprocessed { tmpStr := strings.Split(container, " ") if tmpStr[1] == "docker-compose_sourcegraph" { diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 9642d1b387..747708d41d 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -141,42 +141,37 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam g, ctx := errgroup.WithContext(ctx) semaphore := semaphore.NewWeighted(8) + run := func(f func() error) { + g.Go(func() error { + if err := semaphore.Acquire(ctx, 1); err != nil { + return err + } + defer semaphore.Release(1) + + return f() + }) + } + // create goroutine to get pods - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getPods(ctx, namespace, baseDir) return nil }) // create goroutine to get kubectl events - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getEvents(ctx, namespace, baseDir) return nil }) // create goroutine to get persistent volumes - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getPV(ctx, namespace, baseDir) return nil }) // create goroutine to get persistent volumes claim - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getPVC(ctx, namespace, baseDir) return nil }) @@ -186,11 +181,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam for _, container := range pod.Spec.Containers { p := pod.Metadata.Name c := container.Name - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getPodLog(ctx, p, c, namespace, baseDir) return nil }) @@ -204,11 +195,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam for _, container := range pod.Spec.Containers { p := pod.Metadata.Name c := container.Name - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { f := getPastPodLog(ctx, p, c, namespace, baseDir) if f.err == nil { ch <- f @@ -223,11 +210,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam // start goroutine for each pod to run kubectl describe pod for _, pod := range pods.Items { p := pod.Metadata.Name - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getDescribe(ctx, p, namespace, baseDir) return nil }) @@ -236,11 +219,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam // start goroutine for each pod to run kubectl get pod -o yaml for _, pod := range pods.Items { p := pod.Metadata.Name - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getManifest(ctx, p, namespace, baseDir) return nil }) @@ -248,20 +227,12 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam // start goroutine to get external service config if configs { - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getExternalServicesConfig(ctx, baseDir) return nil }) - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getSiteConfig(ctx, baseDir) return nil }) diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index c7404f3da5..8cd113b3d8 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -109,52 +109,43 @@ func archiveServ(ctx context.Context, zw *zip.Writer, verbose, configs bool, con g, ctx := errgroup.WithContext(ctx) semaphore := semaphore.NewWeighted(8) + run := func(f func() error) { + g.Go(func() error { + if err := semaphore.Acquire(ctx, 1); err != nil { + return err + } + defer semaphore.Release(1) + + return f() + }) + } + // start goroutine to run docker ps -o wide - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getServLog(ctx, container, baseDir) return nil }) // start goroutine to run docker ps -o wide - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getServInspect(ctx, container, baseDir) return nil }) // start goroutine to run docker ps -o wide - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getServTop(ctx, container, baseDir) return nil }) // start goroutine to get configs if configs { - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getExternalServicesConfig(ctx, baseDir) return nil }) - g.Go(func() error { - if err := semaphore.Acquire(ctx, 1); err != nil { - return err - } - defer semaphore.Release(1) + run(func() error { ch <- getSiteConfig(ctx, baseDir) return nil }) From dc7aef6d4c2fc898e80fabb6e666c6f0d9286aaa Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 5 May 2022 01:29:59 -0700 Subject: [PATCH 086/107] addressed many suggested code improvements for readability and style; still needs run through for error handling, and potentially some more refactors --- cmd/src/debug.go | 19 ++++--------------- cmd/src/debug_common.go | 13 +++++-------- cmd/src/debug_comp.go | 35 +++++++++++++++++++---------------- cmd/src/debug_kube.go | 39 +++++++++++++++++++++------------------ cmd/src/debug_serv.go | 29 +++++++++++++++++------------ 5 files changed, 66 insertions(+), 69 deletions(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 76ad13dca2..db28d703ce 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -17,8 +17,8 @@ Usage: The commands are: kube generates kubectl outputs - comp generates docker outputs - serv generates docker outputs + compose generates docker outputs + server generates docker outputs Use "src debug [command] -h" for more information about a subcommands. @@ -34,20 +34,9 @@ src debug has access to flags on src -- Ex: src -v kube -o foo.zip // Register the command. commands = append(commands, &command{ - flagSet: flagSet, - aliases: []string{ - "debug-dump", - "debugger", - }, + flagSet: flagSet, + aliases: []string{}, handler: handler, usageFunc: func() { fmt.Println(usage) }, }) } - -/* -TODO: - - This project needs some consideration around monitoring - - You should be aware when an executed cmd has failed - - You should be able to receive an output that tells you what you've created in the zip file - - an additional introspection command might be useful to look at whats in a zip file easily -*/ diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index a58ada1ab7..25a9c7e8c6 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -15,12 +15,6 @@ import ( "github.com/sourcegraph/sourcegraph/lib/errors" ) -/* -General Stuff -TODO: file issue on the existence of OAuth signKey which needs to be redacted -TODO: Create getSiteConfig function -*/ - type archiveFile struct { name string data []byte @@ -73,7 +67,11 @@ func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose b return nil } -// TODO: Currently external services and site configs are pulled using the src endpoints +// TODO: Currently external services and site configs are pulled using the SRC_ENDPOINT env var, +// if theres a way to validate that the env var is pointing at the same instance as the docker and kubectl commands, +// it should be implemented. + +// TODO: file issue on the existence of OAuth signKey which needs to be redacted // getExternalServicesConfig calls src extsvc list with the format flag -f, // and then returns an archiveFile to be consumed @@ -87,7 +85,6 @@ func getExternalServicesConfig(ctx context.Context, baseDir string) *archiveFile } // getSiteConfig calls src api -query=... to query the api for site config json -// TODO: correctly format json output before writing to zip func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { const siteConfigStr = `query { site { configuration { effectiveContents } } }` f := archiveFileFromCommand(ctx, diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 5ffa24dc10..9f44913730 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -22,30 +22,31 @@ import ( func init() { usage := ` -'src debug comp' mocks docker cli commands to gather information about a docker-compose Sourcegraph instance. +'src debug compose' invokes docker cli diagnostic commands targeting a containers that are members of a docker-compose network, +writing an archive file from their returns. Usage: - src debug comp [command options] + src debug compose [command options] Flags: - -o Specify the name of the output zip archive. - -cfg Include Sourcegraph configuration json. Defaults to true. + -o Specify the name of the output zip archive. + --no-configs Don't include Sourcegraph configuration json. Examples: - $ src debug comp -o debug.zip + $ src debug compose -o debug.zip - $ src -v debug comp -cfg=false -o foo.zip + $ src -v debug compose -no-configs -o foo.zip ` - flagSet := flag.NewFlagSet("comp", flag.ExitOnError) + flagSet := flag.NewFlagSet("compose", flag.ExitOnError) var base string - var configs bool - flagSet.BoolVar(&configs, "cfg", true, "If true include Sourcegraph configuration files. Default value true.") + var noConfigs bool flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") + flagSet.BoolVar(&noConfigs, "no-configs", false, "If true include Sourcegraph configuration files. Default value true.") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -88,7 +89,7 @@ Examples: return nil } - err = archiveCompose(ctx, zw, *verbose, configs, baseDir) + err = archiveCompose(ctx, zw, *verbose, noConfigs, baseDir) if err != nil { return cmderrors.ExitCode(1, nil) } @@ -104,11 +105,8 @@ Examples: }) } -/* -Docker functions -*/ - -func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, configs bool, baseDir string) error { +// writes archive of common docker cli commands +func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, baseDir string) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -168,7 +166,7 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, configs bool, } // start goroutine to get configs - if configs { + if !noConfigs { run(func() error { ch <- getExternalServicesConfig(ctx, baseDir) return nil @@ -194,6 +192,7 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, configs bool, return nil } +// Returns list of containers that are members of the docker-compose_sourcegraph func getContainers(ctx context.Context) ([]string, error) { c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}} {{.Networks}}").Output() if err != nil { @@ -211,6 +210,7 @@ func getContainers(ctx context.Context) ([]string, error) { return containers, err } +// runs archiveFileFromCommand with args docker ps func getPs(ctx context.Context, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -219,6 +219,7 @@ func getPs(ctx context.Context, baseDir string) *archiveFile { ) } +// runs archiveFileFromCommand with args docker container stats func getStats(ctx context.Context, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -227,6 +228,7 @@ func getStats(ctx context.Context, baseDir string) *archiveFile { ) } +// runs archiveFileFromCommand with args docker container logs $CONTAINER func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -235,6 +237,7 @@ func getContainerLog(ctx context.Context, container, baseDir string) *archiveFil ) } +// runs archiveFileFromCommand with args docker container inspect $CONTAINER func getInspect(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 747708d41d..7f530471ed 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -22,17 +22,16 @@ import ( func init() { usage := ` -'src debug kube' mocks kubectl commands to gather information about a kubernetes sourcegraph instance. - +'src debug kube' invokes kubectl diagnostic commands targeting kubectl's current-context, writing returns to an archive. Usage: src debug kube [command options] Flags: - -o Specify the name of the output zip archive. - -n Specify the namespace passed to kubectl commands. If not specified the 'default' namespace is used. - -cfg Include Sourcegraph configuration json. Defaults to true. + -o Specify the name of the output zip archive. + -n Specify the namespace passed to kubectl commands. If not specified the 'default' namespace is used. + --no-config Don't include Sourcegraph configuration json. Examples: @@ -40,17 +39,17 @@ Examples: $ src -v debug kube -n ns-sourcegraph -o foo - $ src debug kube -cfg=false -o bar.zip + $ src debug kube -no-configs -o bar.zip ` flagSet := flag.NewFlagSet("kube", flag.ExitOnError) var base string var namespace string - var configs bool - flagSet.BoolVar(&configs, "cfg", true, "If true include Sourcegraph configuration files. Default value true.") - flagSet.StringVar(&namespace, "n", "default", "The namespace passed to kubectl commands, if not specified the 'default' namespace is used") + var noConfigs bool flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") + flagSet.StringVar(&namespace, "n", "default", "The namespace passed to kubectl commands, if not specified the 'default' namespace is used") + flagSet.BoolVar(&noConfigs, "no-configs", false, "If true include Sourcegraph configuration files. Default value true.") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -82,8 +81,6 @@ Examples: zw := zip.NewWriter(out) defer zw.Close() - //TODO: improve formating to include 'ls' like pod listing for pods targeted. - // Gather data for safety check pods, err := selectPods(ctx, namespace) if err != nil { @@ -99,7 +96,7 @@ Examples: return nil } - err = archiveKube(ctx, zw, *verbose, configs, namespace, baseDir, pods) + err = archiveKube(ctx, zw, *verbose, noConfigs, namespace, baseDir, pods) if err != nil { return cmderrors.ExitCode(1, err) } @@ -128,8 +125,8 @@ type podList struct { } } -// Run kubectl functions concurrently and archive results to zip file -func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, namespace, baseDir string, pods podList) error { +// Runs common kubectl functions and archive results to zip file +func archiveKube(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, namespace, baseDir string, pods podList) error { // Create a context with a cancel function that we call when returning // from archiveKube. This ensures we close all pending go-routines when returning // early because of an error. @@ -190,7 +187,6 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam // start goroutine to run kubectl logs --previous for each pod's container's // won't write to zip on err, only passes bytes to channel if err not nil - // TODO: It may be nice to store a list of pods for which --previous isn't collected, to be outputted with verbose flag for _, pod := range pods.Items { for _, container := range pod.Spec.Containers { p := pod.Metadata.Name @@ -226,7 +222,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam } // start goroutine to get external service config - if configs { + if !noConfigs { run(func() error { ch <- getExternalServicesConfig(ctx, baseDir) return nil @@ -252,6 +248,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, configs bool, nam return nil } +// Calls kubectl get pods and returns a list of pods to be processed func selectPods(ctx context.Context, namespace string) (podList, error) { // Declare buffer type var for kubectl pipe var podsBuff bytes.Buffer @@ -277,6 +274,7 @@ func selectPods(ctx context.Context, namespace string) (podList, error) { return pods, err } +// runs archiveFileFromCommand with arg get pods func getPods(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -285,6 +283,7 @@ func getPods(ctx context.Context, namespace, baseDir string) *archiveFile { ) } +// runs archiveFileFromCommand with arg get events func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -293,6 +292,7 @@ func getEvents(ctx context.Context, namespace, baseDir string) *archiveFile { ) } +// runs archiveFileFromCommand with arg get pv func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -301,6 +301,7 @@ func getPV(ctx context.Context, namespace, baseDir string) *archiveFile { ) } +// runs archiveFileFromCommand with arg get pvc func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -309,7 +310,7 @@ func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { ) } -// get kubectl logs for pod containers +// runs archiveFileFromCommand with arg logs $POD -c $CONTAINER func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -318,7 +319,7 @@ func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir s ) } -// get kubectl logs for past container +// runs archiveFileFromCommand with arg logs --previous $POD -c $CONTAINER func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -327,6 +328,7 @@ func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseD ) } +// runs archiveFileFromCommand with arg describe pod $POD func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -335,6 +337,7 @@ func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archi ) } +// runs archiveFileFromCommand with arg get pod $POD -o yaml func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index 8cd113b3d8..bacd4eec4a 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -18,7 +18,8 @@ import ( func init() { usage := ` -'src debug serv' mocks docker cli commands to gather information about a Sourcegraph server instance. +'src debug server' invokes docker cli diagnostic commands targeting a Sourcegraph server container, +and writes an archive file from their returns. Usage: @@ -26,24 +27,24 @@ Usage: Flags: - -o Specify the name of the output zip archive. - -cfg Include Sourcegraph configuration json. Defaults to true. + -o Specify the name of the output zip archive. + -no-config Don't include Sourcegraph configuration json. Examples: - $ src debug serv -c foo -o debug.zip + $ src debug server -c foo -o debug.zip - $ src -v debug serv -cfg=false -c ViktorVaughn -o foo.zip + $ src -v debug server --no-configs -c ViktorVaughn -o foo.zip ` - flagSet := flag.NewFlagSet("serv", flag.ExitOnError) + flagSet := flag.NewFlagSet("server", flag.ExitOnError) var base string var container string - var configs bool - flagSet.BoolVar(&configs, "cfg", true, "If true include Sourcegraph configuration files. Default value true.") + var noConfigs bool flagSet.StringVar(&base, "o", "debug.zip", "The name of the output zip archive") flagSet.StringVar(&container, "c", "", "The container to target") + flagSet.BoolVar(&noConfigs, "no-configs", false, "If true include Sourcegraph configuration files. Default value true.") handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { @@ -55,7 +56,7 @@ Examples: return fmt.Errorf("empty -o flag") } if container == "" { - return fmt.Errorf("empty -c flag, specifying a container is required") + return fmt.Errorf("empty -c flag, specify a container: src debug server -c foo") } // declare basedir for archive file structure var baseDir string @@ -84,7 +85,7 @@ Examples: return nil } - err = archiveServ(ctx, zw, *verbose, configs, container, baseDir) + err = archiveServ(ctx, zw, *verbose, noConfigs, container, baseDir) if err != nil { return cmderrors.ExitCode(1, nil) } @@ -100,7 +101,8 @@ Examples: }) } -func archiveServ(ctx context.Context, zw *zip.Writer, verbose, configs bool, container, baseDir string) error { +// Runs common docker cli commands on a single container +func archiveServ(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, container, baseDir string) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -139,7 +141,7 @@ func archiveServ(ctx context.Context, zw *zip.Writer, verbose, configs bool, con }) // start goroutine to get configs - if configs { + if !noConfigs { run(func() error { ch <- getExternalServicesConfig(ctx, baseDir) return nil @@ -165,6 +167,7 @@ func archiveServ(ctx context.Context, zw *zip.Writer, verbose, configs bool, con return nil } +// runs archiveFileFromCommand with args container logs $CONTAINER func getServLog(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -173,6 +176,7 @@ func getServLog(ctx context.Context, container, baseDir string) *archiveFile { ) } +// runs archiveFileFromCommand with args container inspect $CONTAINER func getServInspect(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, @@ -181,6 +185,7 @@ func getServInspect(ctx context.Context, container, baseDir string) *archiveFile ) } +// runs archiveFileFromCommand with args top $CONTAINER func getServTop(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, From bd1366c59960187f8ceae38be6e39f3232e6947e Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 6 May 2022 00:10:05 -0700 Subject: [PATCH 087/107] refactor baseDir processor --- cmd/src/debug_common.go | 15 +++++++++++++-- cmd/src/debug_comp.go | 12 +++--------- cmd/src/debug_kube.go | 12 ++---------- cmd/src/debug_serv.go | 12 ++---------- 4 files changed, 20 insertions(+), 31 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 25a9c7e8c6..d1900c5488 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -43,6 +43,17 @@ func verify(confirmationText string) (bool, error) { return strings.ToLower(input) == "y", nil } +func processBaseDir(base string) (string, string) { + var baseDir string + if !strings.HasSuffix(base, ".zip") { + baseDir = base + base = base + ".zip" + } else { + baseDir = strings.TrimSuffix(base, ".zip") + } + return base, baseDir +} + // write all the outputs from an archive command passed on the channel to to the zip writer func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose bool) error { for f := range ch { @@ -57,11 +68,11 @@ func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose b zf, err := zw.Create(f.name) if err != nil { - return fmt.Errorf("failed to create %s: %w", f.name, err) + return errors.Wrapf(err, "failed to create %s: %w", f.name, err) } if _, err := zf.Write(f.data); err != nil { - return fmt.Errorf("failed to write to %s: %w", f.name, err) + return errors.Wrapf(err, "failed to write to %s: %w", f.name, err) } } return nil diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 9f44913730..595e918d92 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -53,25 +53,19 @@ Examples: return err } - //validate out flag + // process -o flag to get zipfile and base directory names if base == "" { return fmt.Errorf("empty -o flag") } // declare basedir for archive file structure - var baseDir string - if !strings.HasSuffix(base, ".zip") { - baseDir = base - base = base + ".zip" - } else { - baseDir = strings.TrimSuffix(base, ".zip") - } + base, baseDir := processBaseDir(base) // init context ctx := context.Background() // open pipe to output file out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { - fmt.Errorf("failed to open file: %w", err) + err = errors.Wrapf(err, "failed to open file: %w", err) } defer out.Close() // init zip writer diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 7f530471ed..83ba9c62c9 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -10,7 +10,6 @@ import ( "log" "os" "path/filepath" - "strings" "golang.org/x/sync/errgroup" @@ -56,18 +55,11 @@ Examples: return err } - //validate out flag + // process -o flag to get zipfile and base directory names if base == "" { return fmt.Errorf("empty -o flag") } - // declare basedir for archive file structure - var baseDir string - if !strings.HasSuffix(base, ".zip") { - baseDir = base - base = base + ".zip" - } else { - baseDir = strings.TrimSuffix(base, ".zip") - } + base, baseDir := processBaseDir(base) // init context ctx := context.Background() diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index bacd4eec4a..dd8140cff6 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -8,7 +8,6 @@ import ( "log" "os" "path/filepath" - "strings" "golang.org/x/sync/errgroup" "golang.org/x/sync/semaphore" @@ -51,21 +50,14 @@ Examples: return err } - //validate required flags aren't empty + //process -o flag to get zipfile and base directory names, make sure container is targeted if base == "" { return fmt.Errorf("empty -o flag") } if container == "" { return fmt.Errorf("empty -c flag, specify a container: src debug server -c foo") } - // declare basedir for archive file structure - var baseDir string - if !strings.HasSuffix(base, ".zip") { - baseDir = base - base = base + ".zip" - } else { - baseDir = strings.TrimSuffix(base, ".zip") - } + base, baseDir := processBaseDir(base) // init context ctx := context.Background() From 91c28d6a3e40656a3fb6aab97a4b12fe9c967d9e Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 6 May 2022 01:44:11 -0700 Subject: [PATCH 088/107] went over errors, still probably needs another run since I widely used errors.Wrapf --- cmd/src/debug_common.go | 5 ----- cmd/src/debug_comp.go | 12 +++++++----- cmd/src/debug_kube.go | 13 +++++++------ cmd/src/debug_serv.go | 7 ++++--- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index d1900c5488..43d011d1dc 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -57,11 +57,6 @@ func processBaseDir(base string) (string, string) { // write all the outputs from an archive command passed on the channel to to the zip writer func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose bool) error { for f := range ch { - if f.err != nil { - log.Printf("getting data for %s failed: %v\noutput: %s", f.name, f.err, f.data) - continue - } - if verbose { log.Printf("archiving file %q with %d bytes", f.name, len(f.data)) } diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 595e918d92..a0e910d0fb 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -65,7 +65,7 @@ Examples: // open pipe to output file out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { - err = errors.Wrapf(err, "failed to open file: %w", err) + return errors.Wrapf(err, "failed to open file: %w", err) } defer out.Close() // init zip writer @@ -75,7 +75,7 @@ Examples: //Gather data for safety check containers, err := getContainers(ctx) if err != nil { - fmt.Errorf("failed to get containers for subcommand with err: %v", err) + return errors.Wrapf(err, "failed to get containers for subcommand with err: %v", err) } // Safety check user knows what they are targeting with this debug command log.Printf("This command will archive docker-cli data for %d containers\n SRC_ENDPOINT: %v\n Output filename: %v", len(containers), cfg.Endpoint, base) @@ -106,7 +106,7 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool containers, err := getContainers(ctx) if err != nil { - return fmt.Errorf("failed to get docker containers: %w", err) + return errors.Wrapf(err, "failed to get docker containers: %w", err) } if verbose { @@ -174,7 +174,9 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool // close channel when wait group goroutines have completed go func() { - g.Wait() + if err := g.Wait(); err != nil { + fmt.Printf("archiveCompose failed to open wait group: %v", err) + } close(ch) }() @@ -190,7 +192,7 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool func getContainers(ctx context.Context) ([]string, error) { c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}} {{.Networks}}").Output() if err != nil { - return nil, fmt.Errorf("failed to get container names with error: %w", err) + return nil, errors.Wrapf(err, "failed to get container names with error: %w", err) } s := string(c) preprocessed := strings.Split(strings.TrimSpace(s), "\n") diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 83ba9c62c9..ab807cdc0e 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -15,6 +15,7 @@ import ( "golang.org/x/sync/semaphore" + "github.com/sourcegraph/sourcegraph/lib/errors" "github.com/sourcegraph/src-cli/internal/cmderrors" "github.com/sourcegraph/src-cli/internal/exec" ) @@ -66,7 +67,7 @@ Examples: // open pipe to output file out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { - fmt.Errorf("failed to open file: %w", err) + return errors.Wrapf(err, "failed to open file: %w", err) } defer out.Close() // init zip writer @@ -76,11 +77,11 @@ Examples: // Gather data for safety check pods, err := selectPods(ctx, namespace) if err != nil { - return fmt.Errorf("failed to get pods: %w", err) + return errors.Wrapf(err, "failed to get pods: %w", err) } kubectx, err := exec.CommandContext(ctx, "kubectl", "config", "current-context").CombinedOutput() if err != nil { - return fmt.Errorf("failed to get current-context: %w", err) + return errors.Wrapf(err, "failed to get current-context: %w", err) } // Safety check user knows what they've targeted with this command log.Printf("Archiving kubectl data for %d pods\n SRC_ENDPOINT: %v\n Context: %s Namespace: %v\n Output filename: %v", len(pods.Items), cfg.Endpoint, kubectx, namespace, base) @@ -234,7 +235,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, n // Read binaries from channel and write to archive on host machine if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { - return fmt.Errorf("failed to write archives from channel: %w", err) + return errors.Wrapf(err, "failed to write archives from channel: %w", err) } return nil @@ -254,13 +255,13 @@ func selectPods(ctx context.Context, namespace string) (podList, error) { podsCmd.Stderr = os.Stderr err := podsCmd.Run() if err != nil { - fmt.Errorf("failed to aquire pods for subcommands with err: %v", err) + errors.Wrapf(err, "failed to aquire pods for subcommands with err: %v", err) } //Decode json from podList var pods podList if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { - fmt.Errorf("failed to unmarshall get pods json: %w", err) + errors.Wrapf(err, "failed to unmarshall get pods json: %w", err) } return pods, err diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index dd8140cff6..6f27b0d039 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -12,6 +12,7 @@ import ( "golang.org/x/sync/errgroup" "golang.org/x/sync/semaphore" + "github.com/sourcegraph/sourcegraph/lib/errors" "github.com/sourcegraph/src-cli/internal/cmderrors" ) @@ -64,7 +65,7 @@ Examples: // open pipe to output file out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { - fmt.Errorf("failed to open file: %w", err) + return errors.Wrapf(err, "failed to open file: %w", err) } defer out.Close() // init zip writer @@ -79,7 +80,7 @@ Examples: err = archiveServ(ctx, zw, *verbose, noConfigs, container, baseDir) if err != nil { - return cmderrors.ExitCode(1, nil) + return cmderrors.ExitCode(1, err) } return nil } @@ -153,7 +154,7 @@ func archiveServ(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, c // Read binaries from channel and write to archive on host machine if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { - return fmt.Errorf("failed to write archives from channel: %w", err) + return errors.Wrapf(err, "failed to write archives from channel: %w", err) } return nil From 109f49e1382a7a9a718523385db81d2a4260df0d Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 6 May 2022 01:51:06 -0700 Subject: [PATCH 089/107] clarify all string serializations --- cmd/src/debug_comp.go | 4 ++-- cmd/src/debug_kube.go | 8 ++++---- cmd/src/debug_serv.go | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index a0e910d0fb..d1aa5e900b 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -228,7 +228,7 @@ func getStats(ctx context.Context, baseDir string) *archiveFile { func getContainerLog(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "docker", "containers", container, fmt.Sprintf("%v.log", container)), + filepath.Join(baseDir, "docker", "containers", container, fmt.Sprintf("%s.log", container)), "docker", "container", "logs", container, ) } @@ -237,7 +237,7 @@ func getContainerLog(ctx context.Context, container, baseDir string) *archiveFil func getInspect(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "docker", "containers", container, fmt.Sprintf("inspect-%v.txt", container)), + filepath.Join(baseDir, "docker", "containers", container, fmt.Sprintf("inspect-%s.txt", container)), "docker", "container", "inspect", container, ) } diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index ab807cdc0e..ddd18cbf29 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -307,7 +307,7 @@ func getPVC(ctx context.Context, namespace, baseDir string) *archiveFile { func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("%v.log", containerName)), + filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("%s.log", containerName)), "kubectl", "-n", namespace, "logs", podName, "-c", containerName, ) } @@ -316,7 +316,7 @@ func getPodLog(ctx context.Context, podName, containerName, namespace, baseDir s func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("prev-%v.log", containerName)), + filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("prev-%s.log", containerName)), "kubectl", "-n", namespace, "logs", "--previous", podName, "-c", containerName, ) } @@ -325,7 +325,7 @@ func getPastPodLog(ctx context.Context, podName, containerName, namespace, baseD func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("describe-%v.txt", podName)), + filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("describe-%s.txt", podName)), "kubectl", "-n", namespace, "describe", "pod", podName, ) } @@ -334,7 +334,7 @@ func getDescribe(ctx context.Context, podName, namespace, baseDir string) *archi func getManifest(ctx context.Context, podName, namespace, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("manifest-%v.yaml", podName)), + filepath.Join(baseDir, "kubectl", "pods", podName, fmt.Sprintf("manifest-%s.yaml", podName)), "kubectl", "-n", namespace, "get", "pod", podName, "-o", "yaml", ) } diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index 6f27b0d039..ed0a1ced48 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -73,7 +73,7 @@ Examples: defer zw.Close() // Safety check user knows what they are targeting with this debug command - log.Printf("This command will archive docker-cli data for container: %v\n SRC_ENDPOINT: %v\n Output filename: %v", container, cfg.Endpoint, base) + log.Printf("This command will archive docker-cli data for container: %s\n SRC_ENDPOINT: %s\n Output filename: %s", container, cfg.Endpoint, base) if verified, _ := verify("Do you want to start writing to an archive?"); !verified { return nil } @@ -164,7 +164,7 @@ func archiveServ(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, c func getServLog(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, fmt.Sprintf("%v.log", container)), + filepath.Join(baseDir, fmt.Sprintf("%s.log", container)), "docker", "container", "logs", container, ) } @@ -173,7 +173,7 @@ func getServLog(ctx context.Context, container, baseDir string) *archiveFile { func getServInspect(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, fmt.Sprintf("inspect-%v.txt", container)), + filepath.Join(baseDir, fmt.Sprintf("inspect-%s.txt", container)), "docker", "container", "inspect", container, ) } @@ -182,7 +182,7 @@ func getServInspect(ctx context.Context, container, baseDir string) *archiveFile func getServTop(ctx context.Context, container, baseDir string) *archiveFile { return archiveFileFromCommand( ctx, - filepath.Join(baseDir, fmt.Sprintf("top-%v.txt", container)), + filepath.Join(baseDir, fmt.Sprintf("top-%s.txt", container)), "docker", "top", container, ) } From 877a333f6f7d49a0ffbc8a75915cae24c56d3738 Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 6 May 2022 10:44:15 -0700 Subject: [PATCH 090/107] Update cmd/src/debug_comp.go Co-authored-by: Eric Fritz --- cmd/src/debug_comp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index d1aa5e900b..5dbc49c80b 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -199,7 +199,7 @@ func getContainers(ctx context.Context) ([]string, error) { containers := make([]string, 0, len(preprocessed)) for _, container := range preprocessed { tmpStr := strings.Split(container, " ") - if tmpStr[1] == "docker-compose_sourcegraph" { + if len(tmpStr) >= 2 && tmpStr[1] == "docker-compose_sourcegraph" { containers = append(containers, tmpStr[0]) } } From edf6100a0c763197286051c219ea00a1597b2b48 Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 6 May 2022 10:57:40 -0700 Subject: [PATCH 091/107] Update cmd/src/debug_common.go Co-authored-by: Eric Fritz --- cmd/src/debug_common.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 43d011d1dc..00564282f2 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -44,14 +44,11 @@ func verify(confirmationText string) (bool, error) { } func processBaseDir(base string) (string, string) { - var baseDir string if !strings.HasSuffix(base, ".zip") { - baseDir = base - base = base + ".zip" - } else { - baseDir = strings.TrimSuffix(base, ".zip") + return base + ".zip", base } - return base, baseDir + + return base, strings.TrimSuffix(base, ".zip") } // write all the outputs from an archive command passed on the channel to to the zip writer From 14f3441a10c0e8900fa5920f1c6431918394a6e9 Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 6 May 2022 11:00:16 -0700 Subject: [PATCH 092/107] Update cmd/src/debug_common.go Co-authored-by: Eric Fritz --- cmd/src/debug_common.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 00564282f2..bd5431bde0 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -109,8 +109,8 @@ func getSiteConfig(ctx context.Context, baseDir string) *archiveFile { } } - f.err = json.Unmarshal(f.data, &siteConfig) - if f.err != nil { + if err := json.Unmarshal(f.data, &siteConfig); err != nil { + f.err = err return f } From 1b097897bf3077fd8b7a93e91194e081ff4daf60 Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 6 May 2022 11:00:31 -0700 Subject: [PATCH 093/107] Update cmd/src/debug_kube.go Co-authored-by: Eric Fritz --- cmd/src/debug_kube.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index ddd18cbf29..4f064d9e01 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -143,10 +143,7 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, n } // create goroutine to get pods - run(func() error { - ch <- getPods(ctx, namespace, baseDir) - return nil - }) + run(func() *archiveFile { return getPods(ctx, namespace, baseDir) }) // create goroutine to get kubectl events run(func() error { From 7eee4870acaba5cd12be1a4288d6407eeefb61e5 Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 6 May 2022 11:00:40 -0700 Subject: [PATCH 094/107] Update cmd/src/debug_kube.go Co-authored-by: Eric Fritz --- cmd/src/debug_kube.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 4f064d9e01..24af98b7d8 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -181,14 +181,13 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, n for _, container := range pod.Spec.Containers { p := pod.Metadata.Name c := container.Name - run(func() error { + run(func() *archiveFile { f := getPastPodLog(ctx, p, c, namespace, baseDir) - if f.err == nil { - ch <- f - } else if verbose { + if f.err != nil { fmt.Printf("Could not gather --previous pod logs for: %s \nExited with err: %s\n", p, f.err) + return nil } - return nil + return f }) } } From 3ab8775f493c0ed659a4dcc132da8a9c9b52626b Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 6 May 2022 11:00:50 -0700 Subject: [PATCH 095/107] Update cmd/src/debug_kube.go Co-authored-by: Eric Fritz --- cmd/src/debug_kube.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 24af98b7d8..b0ef15b80d 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -131,14 +131,18 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, n g, ctx := errgroup.WithContext(ctx) semaphore := semaphore.NewWeighted(8) - run := func(f func() error) { + run := func(f func() *archiveFile) { g.Go(func() error { if err := semaphore.Acquire(ctx, 1); err != nil { return err } defer semaphore.Release(1) - return f() + if file := f(); if file != nil { + ch <- file + } + + return nil }) } From 066fd39f57586105361d6fb48ec17fae19fc1b07 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 6 May 2022 11:02:09 -0700 Subject: [PATCH 096/107] finishing touches --- cmd/src/debug_comp.go | 6 +++--- cmd/src/debug_kube.go | 8 ++++---- cmd/src/debug_serv.go | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index d1aa5e900b..43aacc8dd7 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -27,16 +27,16 @@ writing an archive file from their returns. Usage: - src debug compose [command options] + src debug compose [command options] Flags: - -o Specify the name of the output zip archive. + -o Specify the name of the output zip archive. --no-configs Don't include Sourcegraph configuration json. Examples: - $ src debug compose -o debug.zip + $ src debug compose -o debug.zip $ src -v debug compose -no-configs -o foo.zip diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index ddd18cbf29..0f7609c11e 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -25,17 +25,17 @@ func init() { 'src debug kube' invokes kubectl diagnostic commands targeting kubectl's current-context, writing returns to an archive. Usage: - src debug kube [command options] + src debug kube [command options] Flags: - -o Specify the name of the output zip archive. - -n Specify the namespace passed to kubectl commands. If not specified the 'default' namespace is used. + -o Specify the name of the output zip archive. + -n Specify the namespace passed to kubectl commands. If not specified the 'default' namespace is used. --no-config Don't include Sourcegraph configuration json. Examples: - $ src debug kube -o debug.zip + $ src debug kube -o debug.zip $ src -v debug kube -n ns-sourcegraph -o foo diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index ed0a1ced48..723dc070a1 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -23,16 +23,16 @@ and writes an archive file from their returns. Usage: - src debug serv [command options] + src debug serv [command options] Flags: - -o Specify the name of the output zip archive. + -o Specify the name of the output zip archive. -no-config Don't include Sourcegraph configuration json. Examples: - $ src debug server -c foo -o debug.zip + $ src debug server -c foo -o debug.zip $ src -v debug server --no-configs -c ViktorVaughn -o foo.zip @@ -65,7 +65,7 @@ Examples: // open pipe to output file out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { - return errors.Wrapf(err, "failed to open file: %w", err) + return errors.Wrapf(err, "failed to open file") } defer out.Close() // init zip writer From c54fd23be692b42ddd8ae6ba49e1b80aa8ab9ec9 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 6 May 2022 12:10:37 -0700 Subject: [PATCH 097/107] final error handling cleanup --- cmd/src/debug_common.go | 4 ++-- cmd/src/debug_comp.go | 15 +++++++-------- cmd/src/debug_kube.go | 22 ++++++++++++---------- cmd/src/debug_serv.go | 12 +++++++----- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 6aab72c421..1b0c5a6278 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -64,11 +64,11 @@ func writeChannelContentsToZip(zw *zip.Writer, ch <-chan *archiveFile, verbose b zf, err := zw.Create(f.name) if err != nil { - return errors.Wrapf(err, "failed to create %s: %w", f.name, err) + return errors.Wrapf(err, "failed to create %q", f.name) } if _, err := zf.Write(f.data); err != nil { - return errors.Wrapf(err, "failed to write to %s: %w", f.name, err) + return errors.Wrapf(err, "failed to write to %q", f.name) } } return nil diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 5a331146a4..179f59f491 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -16,8 +16,6 @@ import ( "golang.org/x/sync/errgroup" "golang.org/x/sync/semaphore" - - "github.com/sourcegraph/src-cli/internal/cmderrors" ) func init() { @@ -65,7 +63,7 @@ Examples: // open pipe to output file out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { - return errors.Wrapf(err, "failed to open file: %w", err) + return errors.Wrap(err, "failed to open file") } defer out.Close() // init zip writer @@ -75,7 +73,7 @@ Examples: //Gather data for safety check containers, err := getContainers(ctx) if err != nil { - return errors.Wrapf(err, "failed to get containers for subcommand with err: %v", err) + return errors.Wrap(err, "failed to get containers for subcommand with err") } // Safety check user knows what they are targeting with this debug command log.Printf("This command will archive docker-cli data for %d containers\n SRC_ENDPOINT: %v\n Output filename: %v", len(containers), cfg.Endpoint, base) @@ -85,7 +83,7 @@ Examples: err = archiveCompose(ctx, zw, *verbose, noConfigs, baseDir) if err != nil { - return cmderrors.ExitCode(1, nil) + return err } return nil } @@ -106,7 +104,7 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool containers, err := getContainers(ctx) if err != nil { - return errors.Wrapf(err, "failed to get docker containers: %w", err) + return errors.Wrap(err, "failed to get docker containers") } if verbose { @@ -161,7 +159,8 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool // close channel when wait group goroutines have completed go func() { if err := g.Wait(); err != nil { - fmt.Printf("archiveCompose failed to open wait group: %s", err) + fmt.Printf("archiveCompose failed to open wait group: %s\n", err) + os.Exit(1) } close(ch) }() @@ -178,7 +177,7 @@ func archiveCompose(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool func getContainers(ctx context.Context) ([]string, error) { c, err := exec.CommandContext(ctx, "docker", "container", "ls", "--format", "{{.Names}} {{.Networks}}").Output() if err != nil { - return nil, errors.Wrapf(err, "failed to get container names with error: %w", err) + return nil, errors.Wrapf(err, "failed to get container names with error") } s := string(c) preprocessed := strings.Split(strings.TrimSpace(s), "\n") diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 2e306b1e6f..f18ae65605 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -16,7 +16,6 @@ import ( "golang.org/x/sync/semaphore" "github.com/sourcegraph/sourcegraph/lib/errors" - "github.com/sourcegraph/src-cli/internal/cmderrors" "github.com/sourcegraph/src-cli/internal/exec" ) @@ -58,7 +57,7 @@ Examples: // process -o flag to get zipfile and base directory names if base == "" { - return fmt.Errorf("empty -o flag") + return errors.New("empty -o flag") } base, baseDir := processBaseDir(base) @@ -67,7 +66,7 @@ Examples: // open pipe to output file out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { - return errors.Wrapf(err, "failed to open file: %w", err) + return errors.Wrapf(err, "failed to open file %q", base) } defer out.Close() // init zip writer @@ -77,11 +76,11 @@ Examples: // Gather data for safety check pods, err := selectPods(ctx, namespace) if err != nil { - return errors.Wrapf(err, "failed to get pods: %w", err) + return errors.Wrap(err, "failed to get pods") } kubectx, err := exec.CommandContext(ctx, "kubectl", "config", "current-context").CombinedOutput() if err != nil { - return errors.Wrapf(err, "failed to get current-context: %w", err) + return errors.Wrapf(err, "failed to get current-context") } // Safety check user knows what they've targeted with this command log.Printf("Archiving kubectl data for %d pods\n SRC_ENDPOINT: %v\n Context: %s Namespace: %v\n Output filename: %v", len(pods.Items), cfg.Endpoint, kubectx, namespace, base) @@ -91,7 +90,7 @@ Examples: err = archiveKube(ctx, zw, *verbose, noConfigs, namespace, baseDir, pods) if err != nil { - return cmderrors.ExitCode(1, err) + return err } return nil } @@ -207,13 +206,16 @@ func archiveKube(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, n // close channel when wait group goroutines have completed go func() { - g.Wait() + if err := g.Wait(); err != nil { + fmt.Printf("archiveKube failed to open wait group: %s\n", err) + os.Exit(1) + } close(ch) }() // Read binaries from channel and write to archive on host machine if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { - return errors.Wrapf(err, "failed to write archives from channel: %w", err) + return errors.Wrap(err, "failed to write archives from channel") } return nil @@ -233,13 +235,13 @@ func selectPods(ctx context.Context, namespace string) (podList, error) { podsCmd.Stderr = os.Stderr err := podsCmd.Run() if err != nil { - errors.Wrapf(err, "failed to aquire pods for subcommands with err: %v", err) + errors.Wrap(err, "failed to aquire pods for subcommands with err") } //Decode json from podList var pods podList if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { - errors.Wrapf(err, "failed to unmarshall get pods json: %w", err) + errors.Wrap(err, "failed to unmarshall get pods json") } return pods, err diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index ec7b05bbe6..d59b836e52 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -13,7 +13,6 @@ import ( "golang.org/x/sync/semaphore" "github.com/sourcegraph/sourcegraph/lib/errors" - "github.com/sourcegraph/src-cli/internal/cmderrors" ) func init() { @@ -65,7 +64,7 @@ Examples: // open pipe to output file out, err := os.OpenFile(base, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0666) if err != nil { - return errors.Wrapf(err, "failed to open file") + return errors.Wrapf(err, "failed to open file %q", base) } defer out.Close() // init zip writer @@ -80,7 +79,7 @@ Examples: err = archiveServ(ctx, zw, *verbose, noConfigs, container, baseDir) if err != nil { - return cmderrors.ExitCode(1, err) + return err } return nil } @@ -137,13 +136,16 @@ func archiveServ(ctx context.Context, zw *zip.Writer, verbose, noConfigs bool, c // close channel when wait group goroutines have completed go func() { - g.Wait() + if err := g.Wait(); err != nil { + fmt.Printf("archiveServ failed to open wait group: %s\n", err) + os.Exit(1) + } close(ch) }() // Read binaries from channel and write to archive on host machine if err := writeChannelContentsToZip(zw, ch, verbose); err != nil { - return errors.Wrapf(err, "failed to write archives from channel: %w", err) + return errors.Wrap(err, "failed to write archives from channel") } return nil From feb5cf400f071d619d9d8987363f2ce8b207b989 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 6 May 2022 12:21:37 -0700 Subject: [PATCH 098/107] add changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb146dcca0..ffb0bd0719 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ All notable changes to `src-cli` are documented in this file. ## Unreleased ### Added - +- New command `src debug` dumps context from Sourcegraph instance, executing common `docker` and `kubectl` cli introspection commands and writing returns to a zip archive file. [#731](https://github.com/sourcegraph/src-cli/pull/731) - `src lsif upload` now supports the `-gitlab-token` flag. [#721](https://github.com/sourcegraph/src-cli/pull/721) - Batch Changes can be applied to Bitbucket Cloud when `src` is used with Sourcegraph 3.40 or later. [#725](https://github.com/sourcegraph/src-cli/pull/725) From da74d2bcb206e40366a0a91a60f6424940334239 Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 13 May 2022 11:26:24 -0700 Subject: [PATCH 099/107] Update cmd/src/debug_serv.go Co-authored-by: Adam Harvey --- cmd/src/debug_serv.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_serv.go index d59b836e52..4705ce2c1e 100644 --- a/cmd/src/debug_serv.go +++ b/cmd/src/debug_serv.go @@ -22,7 +22,7 @@ and writes an archive file from their returns. Usage: - src debug serv [command options] + src debug server [command options] Flags: From f0c57a4292fdad45e11659abbecb347eb40c1ffd Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 13 May 2022 11:33:56 -0700 Subject: [PATCH 100/107] Update cmd/src/debug_comp.go Co-authored-by: Adam Harvey --- cmd/src/debug_comp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_comp.go index 179f59f491..9fb764f78a 100644 --- a/cmd/src/debug_comp.go +++ b/cmd/src/debug_comp.go @@ -20,7 +20,7 @@ import ( func init() { usage := ` -'src debug compose' invokes docker cli diagnostic commands targeting a containers that are members of a docker-compose network, +'src debug compose' invokes docker cli diagnostic commands targeting a set of containers that are members of a docker-compose network, writing an archive file from their returns. Usage: From 9a2c7b0bea52b106b5ff087b3444b0a1d6571689 Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 13 May 2022 11:34:50 -0700 Subject: [PATCH 101/107] Update cmd/src/debug_kube.go Co-authored-by: Adam Harvey --- cmd/src/debug_kube.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index f18ae65605..03e9f5c9a1 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -240,7 +240,7 @@ func selectPods(ctx context.Context, namespace string) (podList, error) { //Decode json from podList var pods podList - if err := json.NewDecoder(&podsBuff).Decode(&pods); err != nil { + if err := json.Unmarshal(podsBuff.Bytes(), &pods); err != nil { errors.Wrap(err, "failed to unmarshall get pods json") } From 4aa5180c343c9c4f0ccabf8b642e5bbfe15a4e7e Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 13 May 2022 11:36:09 -0700 Subject: [PATCH 102/107] Update cmd/src/debug_kube.go Co-authored-by: Adam Harvey --- cmd/src/debug_kube.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 03e9f5c9a1..980cdd10cd 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -241,7 +241,7 @@ func selectPods(ctx context.Context, namespace string) (podList, error) { //Decode json from podList var pods podList if err := json.Unmarshal(podsBuff.Bytes(), &pods); err != nil { - errors.Wrap(err, "failed to unmarshall get pods json") + return nil, errors.Wrap(err, "failed to unmarshall get pods json") } return pods, err From 1a6076b4ca873e962a605f28beb558db620c4b11 Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 13 May 2022 11:37:36 -0700 Subject: [PATCH 103/107] Update cmd/src/debug.go Co-authored-by: Adam Harvey --- cmd/src/debug.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug.go b/cmd/src/debug.go index 45628f3ae2..2a513cb1c4 100644 --- a/cmd/src/debug.go +++ b/cmd/src/debug.go @@ -21,7 +21,7 @@ The commands are: server dumps context from single-container deployments -Use "src debug [command] -h" for more information about a subcommands. +Use "src debug command -h" for more information about a subcommands. src debug has access to flags on src -- Ex: src -v kube -o foo.zip ` From 91fef39043ce8e31e5d5b51af6b801c0d213a4d6 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 13 May 2022 11:40:05 -0700 Subject: [PATCH 104/107] address harvey suggestions --- CHANGELOG.md | 2 +- cmd/src/debug_common.go | 2 +- cmd/src/{debug_comp.go => debug_compose.go} | 0 cmd/src/{debug_serv.go => debug_server.go} | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename cmd/src/{debug_comp.go => debug_compose.go} (100%) rename cmd/src/{debug_serv.go => debug_server.go} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffb0bd0719..0ab10f1e4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ All notable changes to `src-cli` are documented in this file. ## Unreleased ### Added -- New command `src debug` dumps context from Sourcegraph instance, executing common `docker` and `kubectl` cli introspection commands and writing returns to a zip archive file. [#731](https://github.com/sourcegraph/src-cli/pull/731) +- New command `src debug`. [#731](https://github.com/sourcegraph/src-cli/pull/731) - `src lsif upload` now supports the `-gitlab-token` flag. [#721](https://github.com/sourcegraph/src-cli/pull/721) - Batch Changes can be applied to Bitbucket Cloud when `src` is used with Sourcegraph 3.40 or later. [#725](https://github.com/sourcegraph/src-cli/pull/725) diff --git a/cmd/src/debug_common.go b/cmd/src/debug_common.go index 1b0c5a6278..130cdd8eaf 100644 --- a/cmd/src/debug_common.go +++ b/cmd/src/debug_common.go @@ -30,7 +30,7 @@ func archiveFileFromCommand(ctx context.Context, path, cmd string, args ...strin return f } -// This function prompts the user to confirm they want to run the command +// verify prompts the user to confirm they want to run the command func verify(confirmationText string) (bool, error) { input := "" for strings.ToLower(input) != "y" && strings.ToLower(input) != "n" { diff --git a/cmd/src/debug_comp.go b/cmd/src/debug_compose.go similarity index 100% rename from cmd/src/debug_comp.go rename to cmd/src/debug_compose.go diff --git a/cmd/src/debug_serv.go b/cmd/src/debug_server.go similarity index 100% rename from cmd/src/debug_serv.go rename to cmd/src/debug_server.go From 8eb1d8fe4ba610b234f9b6c52531001303c666fb Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 13 May 2022 11:45:18 -0700 Subject: [PATCH 105/107] finalize changes from harvey's suggestions --- cmd/src/debug_kube.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/debug_kube.go b/cmd/src/debug_kube.go index 980cdd10cd..9e3dfdaf7e 100644 --- a/cmd/src/debug_kube.go +++ b/cmd/src/debug_kube.go @@ -241,7 +241,7 @@ func selectPods(ctx context.Context, namespace string) (podList, error) { //Decode json from podList var pods podList if err := json.Unmarshal(podsBuff.Bytes(), &pods); err != nil { - return nil, errors.Wrap(err, "failed to unmarshall get pods json") + return pods, errors.Wrap(err, "failed to unmarshall get pods json") } return pods, err From 6b112050fe2be08dcd1157f5b09ef8ca7fd29473 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 13 May 2022 11:48:53 -0700 Subject: [PATCH 106/107] fix go.mod --- go.mod | 1 + 1 file changed, 1 insertion(+) diff --git a/go.mod b/go.mod index 4f3d2cb8f7..05afa9e6cf 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) From 48ffc5f5acb5d903661723270c658f3db7692a31 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Fri, 13 May 2022 11:49:35 -0700 Subject: [PATCH 107/107] really fix go.mod --- go.mod | 1 - 1 file changed, 1 deletion(-) diff --git a/go.mod b/go.mod index 05afa9e6cf..4f3d2cb8f7 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,6 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect gopkg.in/yaml.v2 v2.4.0 // indirect )