From 4cf0f5881d2b605b1ee3050cdc9636b41082dbd1 Mon Sep 17 00:00:00 2001 From: danbudris Date: Wed, 15 Sep 2021 19:39:58 -0400 Subject: [PATCH 1/7] make non-interactive `support-bundle` output more machine readable when using the `interactive=false` flag of `support-bundle`, the spinner would still spin and the archive path and analysis output were kind of smooshed together with the logs. now, if `interactive=false`, only print each recieved collector callback message once, and don't spin also, add a key to the archivePath and analyzerOutput that are returned, for easier programatic parsing --- cmd/troubleshoot/cli/run.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/cmd/troubleshoot/cli/run.go b/cmd/troubleshoot/cli/run.go index e210572b..6a013df5 100644 --- a/cmd/troubleshoot/cli/run.go +++ b/cmd/troubleshoot/cli/run.go @@ -109,6 +109,7 @@ func runTroubleshoot(v *viper.Viper, arg string) error { } s := spin.New() + interactive := v.GetBool("interactive") && isatty.IsTerminal(os.Stdout.Fd()) finishedCh := make(chan bool, 1) progressChan := make(chan interface{}) // non-zero buffer can result in missed messages isFinishedChClosed := false @@ -123,15 +124,22 @@ func runTroubleshoot(v *viper.Viper, arg string) error { c.Println(fmt.Sprintf("%s\r * %v", cursor.ClearEntireLine(), msg)) case string: currentDir = filepath.Base(msg) + if !interactive { + fmt.Printf("\rCollecting support bundle %s\n", currentDir) + } } case <-finishedCh: fmt.Printf("\r%s\r", cursor.ClearEntireLine()) return case <-time.After(time.Millisecond * 100): if currentDir == "" { - fmt.Printf("\r%s \033[36mCollecting support bundle\033[m %s", cursor.ClearEntireLine(), s.Next()) + if interactive { + fmt.Printf("\r%s \033[36mCollecting support bundle\033[m %s", cursor.ClearEntireLine(), s.Next()) + } } else { - fmt.Printf("\r%s \033[36mCollecting support bundle\033[m %s %s", cursor.ClearEntireLine(), s.Next(), currentDir) + if interactive { + fmt.Printf("\r%s \033[36mCollecting support bundle\033[m %s %s", cursor.ClearEntireLine(), s.Next(), currentDir) + } } } } @@ -177,8 +185,6 @@ func runTroubleshoot(v *viper.Viper, arg string) error { // Don't die } else if len(analyzeResults) > 0 { - interactive := v.GetBool("interactive") && isatty.IsTerminal(os.Stdout.Fd()) - if interactive { close(finishedCh) // this removes the spinner isFinishedChClosed = true @@ -194,7 +200,7 @@ func runTroubleshoot(v *viper.Viper, arg string) error { c.Printf("%s\r * Failed to format analysis: %v\n", cursor.ClearEntireLine(), err) } - fmt.Printf("%s", formatted) + fmt.Printf("analyzerResults=%s\n", formatted) } } @@ -207,7 +213,7 @@ the %s Admin Console to begin analysis.` msg = fmt.Sprintf(f, appName, archivePath, appName) } - fmt.Printf("%s\n", msg) + fmt.Printf("archivePath=%s\n", msg) return nil } From 463783d2faa779397d5ed8a438ed6194688b9904 Mon Sep 17 00:00:00 2001 From: danbudris Date: Wed, 15 Sep 2021 21:25:15 -0400 Subject: [PATCH 2/7] resolve merge conflicts --- cmd/troubleshoot/cli/run.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cmd/troubleshoot/cli/run.go b/cmd/troubleshoot/cli/run.go index ffa51793..c251281c 100644 --- a/cmd/troubleshoot/cli/run.go +++ b/cmd/troubleshoot/cli/run.go @@ -171,16 +171,9 @@ func runTroubleshoot(v *viper.Viper, arg string) error { if err != nil { return errors.Wrap(err, "failed to run collect and analyze process") } - - analyzeResults, err := supportbundle.AnalyzeAndExtractSupportBundle(&supportBundle.Spec, archivePath) - if err != nil { - c := color.New(color.FgHiRed) - c.Printf("%s\r * %v\n", cursor.ClearEntireLine(), err) - // Don't die - } else if len(analyzeResults) > 0 { + if len(response.AnalyzerResults) > 0 { interactive := v.GetBool("interactive") && isatty.IsTerminal(os.Stdout.Fd()) - if interactive { close(finishedCh) // this removes the spinner isFinishedChClosed = true From e0fb7484985f80632781e896f0dcdacae3f6aeae Mon Sep 17 00:00:00 2001 From: danbudris Date: Fri, 17 Sep 2021 10:38:38 -0400 Subject: [PATCH 3/7] move non-interactive output to discreet struct with marshalling methods; dont show output for non-interactive; format everything in JSON --- cmd/troubleshoot/cli/run.go | 52 ++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/cmd/troubleshoot/cli/run.go b/cmd/troubleshoot/cli/run.go index c251281c..f2fd3b73 100644 --- a/cmd/troubleshoot/cli/run.go +++ b/cmd/troubleshoot/cli/run.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "encoding/json" "fmt" + analyzer "github.com/replicatedhq/troubleshoot/pkg/analyze" "net/http" "os/signal" @@ -124,9 +125,6 @@ func runTroubleshoot(v *viper.Viper, arg string) error { c.Println(fmt.Sprintf("%s\r * %v", cursor.ClearEntireLine(), msg)) case string: currentDir = filepath.Base(msg) - if !interactive { - fmt.Printf("\rCollecting support bundle %s\n", currentDir) - } } case <-finishedCh: fmt.Printf("\r%s\r", cursor.ClearEntireLine()) @@ -164,6 +162,8 @@ func runTroubleshoot(v *viper.Viper, arg string) error { FromCLI: true, } + nonInteractiveOutput := analysisOutput{} + c := color.New() c.Println(fmt.Sprintf("\r%s\r", cursor.ClearEntireLine())) @@ -182,28 +182,25 @@ func runTroubleshoot(v *viper.Viper, arg string) error { interactive = false } } else { - data := convert.FromAnalyzerResult(response.AnalyzerResults) - formatted, err := json.MarshalIndent(data, "", " ") - if err != nil { - c := color.New(color.FgHiRed) - c.Printf("%s\r * Failed to format analysis: %v\n", cursor.ClearEntireLine(), err) - } - - fmt.Printf("analyzerResults=%s\n", formatted) + nonInteractiveOutput.Analysis = response.AnalyzerResults } } if !response.FileUploaded { - msg := response.ArchivePath if appName := supportBundle.Labels["applicationName"]; appName != "" { f := `A support bundle for %s has been created in this directory named %s. Please upload it on the Troubleshoot page of the %s Admin Console to begin analysis.` - msg = fmt.Sprintf(f, appName, response.ArchivePath, appName) + fmt.Printf(f, appName, response.ArchivePath, appName) + return nil } - fmt.Printf("archivePath=%s\n", msg) - + nonInteractiveOutput.ArchivePath = response.ArchivePath + output, err := nonInteractiveOutput.FormattedAnalysisOutput() + if err != nil { + return errors.Wrap(err, "failed to format non-interactive output") + } + fmt.Println(output) return nil } @@ -272,3 +269,28 @@ func canTryInsecure() bool { _, err := prompt.Run() return err == nil } + +type analysisOutput struct { + Analysis []*analyzer.AnalyzeResult + ArchivePath string +} + +func (a *analysisOutput) FormattedAnalysisOutput() (outputJson []byte, err error) { + type convertedOutput struct { + ConvertedAnalysis []*convert.Result + ArchivePath string + } + + converted := convert.FromAnalyzerResult(a.Analysis) + + o := convertedOutput{ + ConvertedAnalysis: converted, + ArchivePath: a.ArchivePath, + } + + formatted, err := json.MarshalIndent(o, "", " ") + if err != nil { + return nil, fmt.Errorf("\r * Failed to format analysis: %v\n", err) + } + return formatted, nil +} From 867df407eabb0dcb0d7b3da5340dbd3f4401bc53 Mon Sep 17 00:00:00 2001 From: danbudris Date: Fri, 17 Sep 2021 10:50:22 -0400 Subject: [PATCH 4/7] convert output bytearray to string before printing --- cmd/troubleshoot/cli/run.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/troubleshoot/cli/run.go b/cmd/troubleshoot/cli/run.go index f2fd3b73..67e27553 100644 --- a/cmd/troubleshoot/cli/run.go +++ b/cmd/troubleshoot/cli/run.go @@ -275,7 +275,7 @@ type analysisOutput struct { ArchivePath string } -func (a *analysisOutput) FormattedAnalysisOutput() (outputJson []byte, err error) { +func (a *analysisOutput) FormattedAnalysisOutput() (outputJson string, err error) { type convertedOutput struct { ConvertedAnalysis []*convert.Result ArchivePath string @@ -290,7 +290,7 @@ func (a *analysisOutput) FormattedAnalysisOutput() (outputJson []byte, err error formatted, err := json.MarshalIndent(o, "", " ") if err != nil { - return nil, fmt.Errorf("\r * Failed to format analysis: %v\n", err) + return "", fmt.Errorf("\r * Failed to format analysis: %v\n", err) } - return formatted, nil + return string(formatted), nil } From f4e675dae085712171f7b9ab18b7b9e303718715 Mon Sep 17 00:00:00 2001 From: danbudris Date: Fri, 17 Sep 2021 10:57:52 -0400 Subject: [PATCH 5/7] add json tags to output struct for easier unmarshalling --- cmd/troubleshoot/cli/run.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/troubleshoot/cli/run.go b/cmd/troubleshoot/cli/run.go index 67e27553..e1360714 100644 --- a/cmd/troubleshoot/cli/run.go +++ b/cmd/troubleshoot/cli/run.go @@ -277,8 +277,8 @@ type analysisOutput struct { func (a *analysisOutput) FormattedAnalysisOutput() (outputJson string, err error) { type convertedOutput struct { - ConvertedAnalysis []*convert.Result - ArchivePath string + ConvertedAnalysis []*convert.Result `json:"analysis"` + ArchivePath string `json:"archivePath"` } converted := convert.FromAnalyzerResult(a.Analysis) From f2a232d174bc8dc24b3fac2cc8ad1fb74c4faa98 Mon Sep 17 00:00:00 2001 From: Daniel Budris Date: Fri, 17 Sep 2021 11:05:34 -0400 Subject: [PATCH 6/7] use `analyzerResults` not `analysis` for key --- cmd/troubleshoot/cli/run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/troubleshoot/cli/run.go b/cmd/troubleshoot/cli/run.go index e1360714..0624b454 100644 --- a/cmd/troubleshoot/cli/run.go +++ b/cmd/troubleshoot/cli/run.go @@ -277,7 +277,7 @@ type analysisOutput struct { func (a *analysisOutput) FormattedAnalysisOutput() (outputJson string, err error) { type convertedOutput struct { - ConvertedAnalysis []*convert.Result `json:"analysis"` + ConvertedAnalysis []*convert.Result `json:"analyzerResults"` ArchivePath string `json:"archivePath"` } From 5b4b548aa0d61d3b2fe01ca3bf71d19401f69cb5 Mon Sep 17 00:00:00 2001 From: danbudris Date: Fri, 17 Sep 2021 11:20:39 -0400 Subject: [PATCH 7/7] if interactive, only return the print archivePath to stdout; if non-interactive, print whole analysis as json --- cmd/troubleshoot/cli/run.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cmd/troubleshoot/cli/run.go b/cmd/troubleshoot/cli/run.go index e1360714..81084212 100644 --- a/cmd/troubleshoot/cli/run.go +++ b/cmd/troubleshoot/cli/run.go @@ -195,12 +195,17 @@ the %s Admin Console to begin analysis.` return nil } - nonInteractiveOutput.ArchivePath = response.ArchivePath - output, err := nonInteractiveOutput.FormattedAnalysisOutput() - if err != nil { - return errors.Wrap(err, "failed to format non-interactive output") + if !interactive { + nonInteractiveOutput.ArchivePath = response.ArchivePath + output, err := nonInteractiveOutput.FormattedAnalysisOutput() + if err != nil { + return errors.Wrap(err, "failed to format non-interactive output") + } + fmt.Println(output) + return nil } - fmt.Println(output) + + fmt.Printf("%s\n", response.ArchivePath) return nil }