mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-09-03 00:47:17 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6a17951d3 | ||
|
|
9f527ee6a5 | ||
|
|
2c9a37a4f1 | ||
|
|
e6e9df1773 | ||
|
|
755220cd4c | ||
|
|
7289134757 | ||
|
|
63362d32ee | ||
|
|
6cdcb36127 | ||
|
|
dfe5538132 | ||
|
|
42902405cd | ||
|
|
2516924a92 | ||
|
|
ce4165f69e | ||
|
|
648f9b8d35 | ||
|
|
aeb89e57a7 | ||
|
|
8d1a0f6d24 | ||
|
|
0cfd431274 | ||
|
|
fe5dd3ee8f | ||
|
|
7eb1d5a5fb | ||
|
|
40cdc6805e | ||
|
|
3d7a255e32 | ||
|
|
77a2475bd2 | ||
|
|
7bfb54360c | ||
|
|
ca0b3c31c1 | ||
|
|
2b774e16d7 | ||
|
|
9d41d4a7be | ||
|
|
e248ab0f97 | ||
|
|
942234da80 | ||
|
|
0a2ed01a46 |
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -12,6 +11,7 @@ import (
|
||||
"github.com/replicatedhq/termui/v3/widgets"
|
||||
"github.com/replicatedhq/troubleshoot/cmd/util"
|
||||
analyzerunner "github.com/replicatedhq/troubleshoot/pkg/analyze"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/convert"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -20,7 +20,7 @@ var (
|
||||
isShowingSaved = false
|
||||
)
|
||||
|
||||
func showInteractiveResults(preflightName string, analyzeResults []*analyzerunner.AnalyzeResult) error {
|
||||
func showInteractiveResults(preflightName string, outputPath string, analyzeResults []*analyzerunner.AnalyzeResult) error {
|
||||
if err := ui.Init(); err != nil {
|
||||
return errors.Wrap(err, "failed to create terminal ui")
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func showInteractiveResults(preflightName string, analyzeResults []*analyzerunne
|
||||
return nil
|
||||
}
|
||||
case "s":
|
||||
filename, err := save(preflightName, analyzeResults)
|
||||
filename, err := save(preflightName, outputPath, analyzeResults)
|
||||
if err != nil {
|
||||
// show
|
||||
} else {
|
||||
@@ -139,6 +139,9 @@ func drawPreflightTable(analyzeResults []*analyzerunner.AnalyzeResult) {
|
||||
|
||||
for i, analyzeResult := range analyzeResults {
|
||||
title := analyzeResult.Title
|
||||
if analyzeResult.Strict {
|
||||
title = title + fmt.Sprintf(" (Strict: %t)", analyzeResult.Strict)
|
||||
}
|
||||
if analyzeResult.IsPass {
|
||||
title = fmt.Sprintf("✔ %s", title)
|
||||
} else if analyzeResult.IsWarn {
|
||||
@@ -217,8 +220,20 @@ func estimateNumberOfLines(text string, width int) int {
|
||||
return lines
|
||||
}
|
||||
|
||||
func save(preflightName string, analyzeResults []*analyzerunner.AnalyzeResult) (string, error) {
|
||||
filename := path.Join(util.HomeDir(), fmt.Sprintf("%s-results.txt", preflightName))
|
||||
func save(preflightName string, outputPath string, analyzeResults []*analyzerunner.AnalyzeResult) (string, error) {
|
||||
filename := ""
|
||||
if outputPath != "" {
|
||||
// use override output path
|
||||
overridePath, err := convert.ValidateOutputPath(outputPath)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "override output file path")
|
||||
}
|
||||
filename = overridePath
|
||||
} else {
|
||||
// use default output path
|
||||
filename = fmt.Sprintf("%s-results-%s.txt", preflightName, time.Now().Format("2006-01-02T15_04_05"))
|
||||
}
|
||||
|
||||
_, err := os.Stat(filename)
|
||||
if err == nil {
|
||||
os.Remove(filename)
|
||||
@@ -243,6 +258,10 @@ func save(preflightName string, analyzeResults []*analyzerunner.AnalyzeResult) (
|
||||
result = result + fmt.Sprintf("URI: %s\n", analyzeResult.URI)
|
||||
}
|
||||
|
||||
if analyzeResult.Strict {
|
||||
result = result + fmt.Sprintf("Strict: %t\n", analyzeResult.Strict)
|
||||
}
|
||||
|
||||
result = result + "\n------------\n"
|
||||
|
||||
results = results + result
|
||||
|
||||
@@ -38,6 +38,7 @@ that a cluster meets the requirements to run an application.`,
|
||||
cmd.Flags().String("selector", "", "selector (label query) to filter remote collection nodes on.")
|
||||
cmd.Flags().String("since-time", "", "force pod logs collectors to return logs after a specific date (RFC3339)")
|
||||
cmd.Flags().String("since", "", "force pod logs collectors to return logs newer than a relative duration like 5s, 2m, or 3h.")
|
||||
cmd.Flags().StringP("output", "o", "", "specify the output file path for the preflight checks")
|
||||
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ func runPreflights(v *viper.Viper, arg string) error {
|
||||
if len(analyzeResults) == 0 {
|
||||
return errors.New("no data has been collected")
|
||||
}
|
||||
return showInteractiveResults(preflightSpecName, analyzeResults)
|
||||
return showInteractiveResults(preflightSpecName, v.GetString("output"), analyzeResults)
|
||||
}
|
||||
|
||||
return showStdoutResults(v.GetString("format"), preflightSpecName, analyzeResults)
|
||||
|
||||
@@ -42,6 +42,7 @@ func showStdoutResultsJSON(preflightName string, analyzeResults []*analyzerunner
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
||||
URI string `json:"uri,omitempty"`
|
||||
Strict bool `json:"strict,omitempty"`
|
||||
}
|
||||
type Output struct {
|
||||
Pass []ResultOutput `json:"pass,omitempty"`
|
||||
@@ -62,6 +63,10 @@ func showStdoutResultsJSON(preflightName string, analyzeResults []*analyzerunner
|
||||
URI: analyzeResult.URI,
|
||||
}
|
||||
|
||||
if analyzeResult.Strict {
|
||||
resultOutput.Strict = analyzeResult.Strict
|
||||
}
|
||||
|
||||
if analyzeResult.IsPass {
|
||||
output.Pass = append(output.Pass, resultOutput)
|
||||
} else if analyzeResult.IsWarn {
|
||||
@@ -91,6 +96,13 @@ func outputResult(analyzeResult *analyzerunner.AnalyzeResult) bool {
|
||||
} else if analyzeResult.IsFail {
|
||||
fmt.Printf(" --- FAIL: %s\n", analyzeResult.Title)
|
||||
fmt.Printf(" --- %s\n", analyzeResult.Message)
|
||||
}
|
||||
|
||||
if analyzeResult.Strict {
|
||||
fmt.Printf(" --- Strict: %t\n", analyzeResult.Strict)
|
||||
}
|
||||
|
||||
if analyzeResult.IsFail {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -17,6 +17,7 @@ func uploadResults(uri string, analyzeResults []*analyzerunner.AnalyzeResult) er
|
||||
}
|
||||
for _, analyzeResult := range analyzeResults {
|
||||
uploadPreflightResult := &preflight.UploadPreflightResult{
|
||||
Strict: analyzeResult.Strict,
|
||||
IsFail: analyzeResult.IsFail,
|
||||
IsWarn: analyzeResult.IsWarn,
|
||||
IsPass: analyzeResult.IsPass,
|
||||
|
||||
@@ -42,6 +42,7 @@ from a server that can be used to assist when troubleshooting a Kubernetes clust
|
||||
cmd.Flags().Bool("collect-without-permissions", true, "always generate a support bundle, even if it some require additional permissions")
|
||||
cmd.Flags().String("since-time", "", "force pod logs collectors to return logs after a specific date (RFC3339)")
|
||||
cmd.Flags().String("since", "", "force pod logs collectors to return logs newer than a relative duration like 5s, 2m, or 3h.")
|
||||
cmd.Flags().StringP("output", "o", "", "specify the output file path for the support bundle")
|
||||
|
||||
// hidden in favor of the `insecure-skip-tls-verify` flag
|
||||
cmd.Flags().Bool("allow-insecure-connections", false, "when set, do not verify TLS certs when retrieving spec and reporting results")
|
||||
|
||||
@@ -181,6 +181,7 @@ func runTroubleshoot(v *viper.Viper, arg string) error {
|
||||
Namespace: v.GetString("namespace"),
|
||||
ProgressChan: progressChan,
|
||||
SinceTime: sinceTime,
|
||||
OutputPath: v.GetString("output"),
|
||||
Redact: v.GetBool("redact"),
|
||||
FromCLI: true,
|
||||
}
|
||||
|
||||
@@ -81,6 +81,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
@@ -127,6 +129,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -168,6 +172,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -215,6 +221,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- configMapName
|
||||
- namespace
|
||||
@@ -258,6 +266,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -301,6 +311,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- customResourceDefinitionName
|
||||
- outcomes
|
||||
@@ -351,6 +363,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -393,6 +407,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -436,6 +452,8 @@ spec:
|
||||
type: array
|
||||
registryName:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
- registryName
|
||||
@@ -482,6 +500,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- ingressName
|
||||
- namespace
|
||||
@@ -533,6 +553,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -579,6 +601,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
@@ -625,6 +649,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -693,6 +719,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -738,6 +766,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -784,6 +814,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -828,6 +860,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -882,6 +916,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -931,6 +967,8 @@ spec:
|
||||
type: array
|
||||
secretName:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
@@ -982,6 +1020,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -1026,6 +1066,8 @@ spec:
|
||||
type: array
|
||||
storageClassName:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
- storageClassName
|
||||
@@ -1068,6 +1110,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -1119,6 +1163,8 @@ spec:
|
||||
type: string
|
||||
regexGroups:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -1130,6 +1176,8 @@ spec:
|
||||
type: BoolString
|
||||
reportFileGlob:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- reportFileGlob
|
||||
type: object
|
||||
|
||||
@@ -82,6 +82,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- includeUnmountedPartitions
|
||||
- minimumAcceptableSize
|
||||
@@ -127,6 +129,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -168,6 +172,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -211,6 +217,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -254,6 +262,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -295,6 +305,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -336,6 +348,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -379,6 +393,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -422,6 +438,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -463,6 +481,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -504,6 +524,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -545,6 +567,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -588,6 +612,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -631,6 +657,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -674,6 +702,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -717,6 +747,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -758,6 +790,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
|
||||
@@ -82,6 +82,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- includeUnmountedPartitions
|
||||
- minimumAcceptableSize
|
||||
@@ -127,6 +129,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -168,6 +172,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -211,6 +217,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -254,6 +262,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -295,6 +305,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -336,6 +348,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -379,6 +393,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -422,6 +438,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -463,6 +481,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -504,6 +524,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -545,6 +567,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -588,6 +612,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -631,6 +657,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -674,6 +702,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -717,6 +747,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -758,6 +790,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
|
||||
@@ -81,6 +81,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
@@ -127,6 +129,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -168,6 +172,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -215,6 +221,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- configMapName
|
||||
- namespace
|
||||
@@ -258,6 +266,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -301,6 +311,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- customResourceDefinitionName
|
||||
- outcomes
|
||||
@@ -351,6 +363,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -393,6 +407,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -436,6 +452,8 @@ spec:
|
||||
type: array
|
||||
registryName:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
- registryName
|
||||
@@ -482,6 +500,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- ingressName
|
||||
- namespace
|
||||
@@ -533,6 +553,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -579,6 +601,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
@@ -625,6 +649,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -693,6 +719,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -738,6 +766,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -784,6 +814,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -828,6 +860,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -882,6 +916,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -931,6 +967,8 @@ spec:
|
||||
type: array
|
||||
secretName:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
@@ -982,6 +1020,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -1026,6 +1066,8 @@ spec:
|
||||
type: array
|
||||
storageClassName:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
- storageClassName
|
||||
@@ -1068,6 +1110,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -1119,6 +1163,8 @@ spec:
|
||||
type: string
|
||||
regexGroups:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -1130,6 +1176,8 @@ spec:
|
||||
type: BoolString
|
||||
reportFileGlob:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- reportFileGlob
|
||||
type: object
|
||||
|
||||
@@ -112,6 +112,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
@@ -158,6 +160,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -199,6 +203,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -246,6 +252,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- configMapName
|
||||
- namespace
|
||||
@@ -289,6 +297,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -332,6 +342,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- customResourceDefinitionName
|
||||
- outcomes
|
||||
@@ -382,6 +394,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -424,6 +438,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -467,6 +483,8 @@ spec:
|
||||
type: array
|
||||
registryName:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
- registryName
|
||||
@@ -513,6 +531,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- ingressName
|
||||
- namespace
|
||||
@@ -564,6 +584,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -610,6 +632,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
@@ -656,6 +680,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -724,6 +750,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -769,6 +797,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -815,6 +845,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -859,6 +891,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- collectorName
|
||||
- outcomes
|
||||
@@ -913,6 +947,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -962,6 +998,8 @@ spec:
|
||||
type: array
|
||||
secretName:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- namespace
|
||||
- outcomes
|
||||
@@ -1013,6 +1051,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- name
|
||||
- outcomes
|
||||
@@ -1057,6 +1097,8 @@ spec:
|
||||
type: array
|
||||
storageClassName:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
- storageClassName
|
||||
@@ -1099,6 +1141,8 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -1150,6 +1194,8 @@ spec:
|
||||
type: string
|
||||
regexGroups:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- outcomes
|
||||
type: object
|
||||
@@ -1161,6 +1207,8 @@ spec:
|
||||
type: BoolString
|
||||
reportFileGlob:
|
||||
type: string
|
||||
strict:
|
||||
type: BoolString
|
||||
required:
|
||||
- reportFileGlob
|
||||
type: object
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
name: mysql
|
||||
spec:
|
||||
collectors:
|
||||
- mysql:
|
||||
collectorName: mysql
|
||||
uri: 'root:my-secret-pw@tcp(localhost:3306)/mysql'
|
||||
parameters:
|
||||
- character_set_server
|
||||
- collation_server
|
||||
- init_connect
|
||||
- innodb_file_format
|
||||
- innodb_large_prefix
|
||||
- innodb_strict_mode
|
||||
- log_bin_trust_function_creators
|
||||
+4
-1
@@ -75,7 +75,10 @@ func (c *Clientset) Tracker() testing.ObjectTracker {
|
||||
return c.tracker
|
||||
}
|
||||
|
||||
var _ clientset.Interface = &Clientset{}
|
||||
var (
|
||||
_ clientset.Interface = &Clientset{}
|
||||
_ testing.FakeClient = &Clientset{}
|
||||
)
|
||||
|
||||
// TroubleshootV1beta1 retrieves the TroubleshootV1beta1Client
|
||||
func (c *Clientset) TroubleshootV1beta1() troubleshootv1beta1.TroubleshootV1beta1Interface {
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import (
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var codecs = serializer.NewCodecFactory(scheme)
|
||||
var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
troubleshootv1beta1.AddToScheme,
|
||||
troubleshootv1beta2.AddToScheme,
|
||||
|
||||
+53
-4
@@ -14,6 +14,7 @@ type AnalyzeResult struct {
|
||||
IsPass bool
|
||||
IsFail bool
|
||||
IsWarn bool
|
||||
Strict bool
|
||||
|
||||
Title string
|
||||
Message string
|
||||
@@ -27,7 +28,11 @@ type AnalyzeResult struct {
|
||||
type getCollectedFileContents func(string) ([]byte, error)
|
||||
type getChildCollectedFileContents func(string) (map[string][]byte, error)
|
||||
|
||||
func isExcluded(excludeVal multitype.BoolOrString) (bool, error) {
|
||||
func isExcluded(excludeVal *multitype.BoolOrString) (bool, error) {
|
||||
if excludeVal == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if excludeVal.Type == multitype.Bool {
|
||||
return excludeVal.BoolVal, nil
|
||||
}
|
||||
@@ -94,6 +99,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.ClusterVersion.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.StorageClass != nil {
|
||||
@@ -108,6 +114,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.StorageClass.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.CustomResourceDefinition != nil {
|
||||
@@ -122,6 +129,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.CustomResourceDefinition.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Ingress != nil {
|
||||
@@ -136,6 +144,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.Ingress.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Secret != nil {
|
||||
@@ -150,6 +159,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.Secret.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.ConfigMap != nil {
|
||||
@@ -164,6 +174,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.ConfigMap.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.ImagePullSecret != nil {
|
||||
@@ -178,6 +189,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.ImagePullSecret.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.DeploymentStatus != nil {
|
||||
@@ -192,6 +204,9 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range results {
|
||||
results[i].Strict = analyzer.DeploymentStatus.Strict.BoolOrDefaultFalse()
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
if analyzer.StatefulsetStatus != nil {
|
||||
@@ -206,6 +221,9 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range results {
|
||||
results[i].Strict = analyzer.StatefulsetStatus.Strict.BoolOrDefaultFalse()
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
if analyzer.JobStatus != nil {
|
||||
@@ -220,6 +238,9 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range results {
|
||||
results[i].Strict = analyzer.JobStatus.Strict.BoolOrDefaultFalse()
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
if analyzer.ReplicaSetStatus != nil {
|
||||
@@ -234,6 +255,9 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range results {
|
||||
results[i].Strict = analyzer.ReplicaSetStatus.Strict.BoolOrDefaultFalse()
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
if analyzer.ClusterPodStatuses != nil {
|
||||
@@ -248,6 +272,9 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range results {
|
||||
results[i].Strict = analyzer.ClusterPodStatuses.Strict.BoolOrDefaultFalse()
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
if analyzer.ContainerRuntime != nil {
|
||||
@@ -262,6 +289,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.ContainerRuntime.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Distribution != nil {
|
||||
@@ -276,6 +304,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.Distribution.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.NodeResources != nil {
|
||||
@@ -290,6 +319,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.NodeResources.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.TextAnalyze != nil {
|
||||
@@ -300,11 +330,14 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
multiResult, err := analyzeTextAnalyze(analyzer.TextAnalyze, findFiles)
|
||||
results, err := analyzeTextAnalyze(analyzer.TextAnalyze, findFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return multiResult, nil
|
||||
for i := range results {
|
||||
results[i].Strict = analyzer.TextAnalyze.Strict.BoolOrDefaultFalse()
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
if analyzer.Postgres != nil {
|
||||
isExcluded, err := isExcluded(analyzer.Postgres.Exclude)
|
||||
@@ -318,6 +351,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.Postgres.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Mysql != nil {
|
||||
@@ -332,6 +366,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.Mysql.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Redis != nil {
|
||||
@@ -346,6 +381,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.Redis.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.CephStatus != nil {
|
||||
@@ -360,6 +396,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.CephStatus.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
if analyzer.Longhorn != nil {
|
||||
@@ -370,7 +407,14 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if isExcluded {
|
||||
return nil, nil
|
||||
}
|
||||
return longhorn(analyzer.Longhorn, getFile, findFiles)
|
||||
results, err := longhorn(analyzer.Longhorn, getFile, findFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range results {
|
||||
results[i].Strict = analyzer.Longhorn.Strict.BoolOrDefaultFalse()
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
if analyzer.RegistryImages != nil {
|
||||
@@ -385,6 +429,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Strict = analyzer.RegistryImages.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
|
||||
@@ -400,6 +445,9 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range results {
|
||||
results[i].Strict = analyzer.WeaveReport.Strict.BoolOrDefaultFalse()
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
@@ -418,6 +466,7 @@ func Analyze(analyzer *troubleshootv1beta2.Analyze, getFile getCollectedFileCont
|
||||
if result == nil {
|
||||
return []*AnalyzeResult{}, nil
|
||||
}
|
||||
result.Strict = analyzer.Sysctl.Strict.BoolOrDefaultFalse()
|
||||
return []*AnalyzeResult{result}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ func clusterPodStatuses(analyzer *troubleshootv1beta2.ClusterPodStatuses, getChi
|
||||
|
||||
var pods []corev1.Pod
|
||||
for fileName, fileContent := range collected {
|
||||
podsNs := strings.TrimSuffix(fileName, ".json")
|
||||
podsNs := strings.TrimSuffix(filepath.Base(fileName), ".json")
|
||||
include := len(analyzer.Namespaces) == 0
|
||||
for _, ns := range analyzer.Namespaces {
|
||||
if ns == podsNs {
|
||||
@@ -33,9 +33,14 @@ func clusterPodStatuses(analyzer *troubleshootv1beta2.ClusterPodStatuses, getChi
|
||||
if include {
|
||||
var nsPods corev1.PodList
|
||||
if err := json.Unmarshal(fileContent, &nsPods); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unmarshal pods list for namespace %s", podsNs)
|
||||
var nsPodsArr []corev1.Pod
|
||||
if err := json.Unmarshal(fileContent, &nsPodsArr); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unmarshal pods list for namespace %s", podsNs)
|
||||
}
|
||||
pods = append(pods, nsPodsArr...)
|
||||
} else {
|
||||
pods = append(pods, nsPods.Items...)
|
||||
}
|
||||
pods = append(pods, nsPods.Items...)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,8 +116,8 @@ type DatabaseAnalyze struct {
|
||||
}
|
||||
|
||||
type AnalyzeMeta struct {
|
||||
CheckName string `json:"checkName,omitempty" yaml:"checkName,omitempty"`
|
||||
Exclude multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
CheckName string `json:"checkName,omitempty" yaml:"checkName,omitempty"`
|
||||
Exclude *multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
type Analyze struct {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
type CollectorMeta struct {
|
||||
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
|
||||
// +optional
|
||||
Exclude multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
Exclude *multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
type ClusterInfo struct {
|
||||
|
||||
@@ -22,6 +22,7 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/multitype"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
@@ -143,7 +144,11 @@ func (in *Analyze) DeepCopy() *Analyze {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AnalyzeMeta) DeepCopyInto(out *AnalyzeMeta) {
|
||||
*out = *in
|
||||
out.Exclude = in.Exclude
|
||||
if in.Exclude != nil {
|
||||
in, out := &in.Exclude, &out.Exclude
|
||||
*out = new(multitype.BoolOrString)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnalyzeMeta.
|
||||
@@ -159,7 +164,7 @@ func (in *AnalyzeMeta) DeepCopy() *AnalyzeMeta {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AnalyzeSecret) DeepCopyInto(out *AnalyzeSecret) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -286,7 +291,7 @@ func (in *AnalyzerStatus) DeepCopy() *AnalyzerStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClusterInfo) DeepCopyInto(out *ClusterInfo) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterInfo.
|
||||
@@ -302,7 +307,7 @@ func (in *ClusterInfo) DeepCopy() *ClusterInfo {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClusterResources) DeepCopyInto(out *ClusterResources) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterResources.
|
||||
@@ -318,7 +323,7 @@ func (in *ClusterResources) DeepCopy() *ClusterResources {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClusterVersion) DeepCopyInto(out *ClusterVersion) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -348,17 +353,17 @@ func (in *Collect) DeepCopyInto(out *Collect) {
|
||||
if in.ClusterInfo != nil {
|
||||
in, out := &in.ClusterInfo, &out.ClusterInfo
|
||||
*out = new(ClusterInfo)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ClusterResources != nil {
|
||||
in, out := &in.ClusterResources, &out.ClusterResources
|
||||
*out = new(ClusterResources)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Secret != nil {
|
||||
in, out := &in.Secret, &out.Secret
|
||||
*out = new(Secret)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Logs != nil {
|
||||
in, out := &in.Logs, &out.Logs
|
||||
@@ -378,7 +383,7 @@ func (in *Collect) DeepCopyInto(out *Collect) {
|
||||
if in.Data != nil {
|
||||
in, out := &in.Data, &out.Data
|
||||
*out = new(Data)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Copy != nil {
|
||||
in, out := &in.Copy, &out.Copy
|
||||
@@ -393,17 +398,17 @@ func (in *Collect) DeepCopyInto(out *Collect) {
|
||||
if in.Postgres != nil {
|
||||
in, out := &in.Postgres, &out.Postgres
|
||||
*out = new(Database)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Mysql != nil {
|
||||
in, out := &in.Mysql, &out.Mysql
|
||||
*out = new(Database)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Redis != nil {
|
||||
in, out := &in.Redis, &out.Redis
|
||||
*out = new(Database)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,7 +484,11 @@ func (in *CollectorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CollectorMeta) DeepCopyInto(out *CollectorMeta) {
|
||||
*out = *in
|
||||
out.Exclude = in.Exclude
|
||||
if in.Exclude != nil {
|
||||
in, out := &in.Exclude, &out.Exclude
|
||||
*out = new(multitype.BoolOrString)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectorMeta.
|
||||
@@ -547,7 +556,7 @@ func (in *CollectorStatus) DeepCopy() *CollectorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ContainerRuntime) DeepCopyInto(out *ContainerRuntime) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -574,7 +583,7 @@ func (in *ContainerRuntime) DeepCopy() *ContainerRuntime {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Copy) DeepCopyInto(out *Copy) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = make([]string, len(*in))
|
||||
@@ -595,7 +604,7 @@ func (in *Copy) DeepCopy() *Copy {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceDefinition) DeepCopyInto(out *CustomResourceDefinition) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -622,7 +631,7 @@ func (in *CustomResourceDefinition) DeepCopy() *CustomResourceDefinition {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Data) DeepCopyInto(out *Data) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Data.
|
||||
@@ -638,7 +647,7 @@ func (in *Data) DeepCopy() *Data {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Database) DeepCopyInto(out *Database) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Database.
|
||||
@@ -654,7 +663,7 @@ func (in *Database) DeepCopy() *Database {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DatabaseAnalyze) DeepCopyInto(out *DatabaseAnalyze) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -681,7 +690,7 @@ func (in *DatabaseAnalyze) DeepCopy() *DatabaseAnalyze {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentStatus) DeepCopyInto(out *DeploymentStatus) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -708,7 +717,7 @@ func (in *DeploymentStatus) DeepCopy() *DeploymentStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Distribution) DeepCopyInto(out *Distribution) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -735,7 +744,7 @@ func (in *Distribution) DeepCopy() *Distribution {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Exec) DeepCopyInto(out *Exec) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = make([]string, len(*in))
|
||||
@@ -808,7 +817,7 @@ func (in *Get) DeepCopy() *Get {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTP) DeepCopyInto(out *HTTP) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Get != nil {
|
||||
in, out := &in.Get, &out.Get
|
||||
*out = new(Get)
|
||||
@@ -839,7 +848,7 @@ func (in *HTTP) DeepCopy() *HTTP {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ImagePullSecret) DeepCopyInto(out *ImagePullSecret) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -888,7 +897,7 @@ func (in *ImagePullSecrets) DeepCopy() *ImagePullSecrets {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Ingress) DeepCopyInto(out *Ingress) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -930,7 +939,7 @@ func (in *LogLimits) DeepCopy() *LogLimits {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Logs) DeepCopyInto(out *Logs) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = make([]string, len(*in))
|
||||
@@ -1003,7 +1012,7 @@ func (in *NodeResourceSelectors) DeepCopy() *NodeResourceSelectors {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeResources) DeepCopyInto(out *NodeResources) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -1397,7 +1406,7 @@ func (in *ResultRequest) DeepCopy() *ResultRequest {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Run) DeepCopyInto(out *Run) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Command != nil {
|
||||
in, out := &in.Command, &out.Command
|
||||
*out = make([]string, len(*in))
|
||||
@@ -1428,7 +1437,7 @@ func (in *Run) DeepCopy() *Run {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Secret) DeepCopyInto(out *Secret) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Secret.
|
||||
@@ -1459,7 +1468,7 @@ func (in *SingleOutcome) DeepCopy() *SingleOutcome {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StatefulsetStatus) DeepCopyInto(out *StatefulsetStatus) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -1486,7 +1495,7 @@ func (in *StatefulsetStatus) DeepCopy() *StatefulsetStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StorageClass) DeepCopyInto(out *StorageClass) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
@@ -1666,7 +1675,7 @@ func (in *SupportBundleVersionSpec) DeepCopy() *SupportBundleVersionSpec {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TextAnalyze) DeepCopyInto(out *TextAnalyze) {
|
||||
*out = *in
|
||||
out.AnalyzeMeta = in.AnalyzeMeta
|
||||
in.AnalyzeMeta.DeepCopyInto(&out.AnalyzeMeta)
|
||||
if in.Outcomes != nil {
|
||||
in, out := &in.Outcomes, &out.Outcomes
|
||||
*out = make([]*Outcome, len(*in))
|
||||
|
||||
@@ -175,8 +175,9 @@ type SysctlAnalyze struct {
|
||||
}
|
||||
|
||||
type AnalyzeMeta struct {
|
||||
CheckName string `json:"checkName,omitempty" yaml:"checkName,omitempty"`
|
||||
Exclude multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
CheckName string `json:"checkName,omitempty" yaml:"checkName,omitempty"`
|
||||
Exclude *multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
Strict *multitype.BoolOrString `json:"strict,omitempty" yaml:"strict,omitempty"`
|
||||
}
|
||||
|
||||
type Analyze struct {
|
||||
|
||||
@@ -6,13 +6,14 @@ import (
|
||||
|
||||
"github.com/replicatedhq/troubleshoot/pkg/multitype"
|
||||
authorizationv1 "k8s.io/api/authorization/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type CollectorMeta struct {
|
||||
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
|
||||
// +optional
|
||||
Exclude multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
Exclude *multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
type ClusterInfo struct {
|
||||
@@ -65,15 +66,25 @@ type Data struct {
|
||||
}
|
||||
|
||||
type Run struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Image string `json:"image" yaml:"image"`
|
||||
Command []string `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"`
|
||||
ImagePullSecret *ImagePullSecrets `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"`
|
||||
ServiceAccountName string `json:"serviceAccountName,omitempty" yaml:"serviceAccountName,omitempty"`
|
||||
}
|
||||
|
||||
type RunPod struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace" yaml:"namespace"`
|
||||
Image string `json:"image" yaml:"image"`
|
||||
Command []string `json:"command,omitempty" yaml:"command,omitempty"`
|
||||
Args []string `json:"args,omitempty" yaml:"args,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
|
||||
ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"`
|
||||
ImagePullSecret *ImagePullSecrets `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"`
|
||||
PodSpec corev1.PodSpec `json:"podSpec,omitempty" yaml:"podSpec,omitempty"`
|
||||
}
|
||||
|
||||
type ImagePullSecrets struct {
|
||||
@@ -155,7 +166,8 @@ type Put struct {
|
||||
|
||||
type Database struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
URI string `json:"uri" yaml:"uri"`
|
||||
URI string `json:"uri" yaml:"uri"`
|
||||
Parameters []string `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
type Collectd struct {
|
||||
@@ -194,6 +206,7 @@ type Collect struct {
|
||||
ConfigMap *ConfigMap `json:"configMap,omitempty" yaml:"configMap,omitempty"`
|
||||
Logs *Logs `json:"logs,omitempty" yaml:"logs,omitempty"`
|
||||
Run *Run `json:"run,omitempty" yaml:"run,omitempty"`
|
||||
RunPod *RunPod `json:"runPod,omitempty" yaml:"runPod,omitempty"`
|
||||
Exec *Exec `json:"exec,omitempty" yaml:"exec,omitempty"`
|
||||
Data *Data `json:"data,omitempty" yaml:"data,omitempty"`
|
||||
Copy *Copy `json:"copy,omitempty" yaml:"copy,omitempty"`
|
||||
@@ -327,6 +340,19 @@ func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSub
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.RunPod != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
Namespace: pickNamespaceOrDefault(c.RunPod.Namespace, overrideNS),
|
||||
Verb: "create",
|
||||
Group: "",
|
||||
Version: "",
|
||||
Resource: "pods",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
},
|
||||
NonResourceAttributes: nil,
|
||||
})
|
||||
} else if c.Exec != nil {
|
||||
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||
@@ -432,6 +458,10 @@ func (c *Collect) GetName() string {
|
||||
collector = "run"
|
||||
name = c.Run.CollectorName
|
||||
}
|
||||
if c.RunPod != nil {
|
||||
collector = "run-pod"
|
||||
name = c.RunPod.CollectorName
|
||||
}
|
||||
if c.Exec != nil {
|
||||
collector = "exec"
|
||||
name = c.Exec.CollectorName
|
||||
@@ -454,6 +484,18 @@ func (c *Collect) GetName() string {
|
||||
collector = "http"
|
||||
name = c.HTTP.CollectorName
|
||||
}
|
||||
if c.Postgres != nil {
|
||||
collector = "postgres"
|
||||
name = c.Postgres.CollectorName
|
||||
}
|
||||
if c.Mysql != nil {
|
||||
collector = "mysql"
|
||||
name = c.Mysql.CollectorName
|
||||
}
|
||||
if c.Redis != nil {
|
||||
collector = "redis"
|
||||
name = c.Redis.CollectorName
|
||||
}
|
||||
if c.Collectd != nil {
|
||||
collector = "collectd"
|
||||
name = c.Collectd.CollectorName
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
type HostCollectorMeta struct {
|
||||
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
|
||||
// +optional
|
||||
Exclude multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
Exclude *multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
type CPU struct {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
type RemoteCollectorMeta struct {
|
||||
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
|
||||
// +optional
|
||||
Exclude multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
Exclude *multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
type RemoteCPU struct {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+54
-42
@@ -3,7 +3,6 @@ package collect
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
@@ -28,52 +27,60 @@ type CephCommand struct {
|
||||
|
||||
var CephCommands = []CephCommand{
|
||||
{
|
||||
ID: "status",
|
||||
Command: []string{"ceph", "status"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
ID: "status",
|
||||
Command: []string{"ceph", "status"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
{
|
||||
ID: "fs",
|
||||
Command: []string{"ceph", "fs", "status"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
ID: "fs",
|
||||
Command: []string{"ceph", "fs", "status"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
{
|
||||
ID: "fs-ls",
|
||||
Command: []string{"ceph", "fs", "ls"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
ID: "fs-ls",
|
||||
Command: []string{"ceph", "fs", "ls"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
{
|
||||
ID: "osd-status",
|
||||
Command: []string{"ceph", "osd", "status"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "txt",
|
||||
ID: "osd-status",
|
||||
Command: []string{"ceph", "osd", "status"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "txt",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
{
|
||||
ID: "osd-tree",
|
||||
Command: []string{"ceph", "osd", "tree"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
ID: "osd-tree",
|
||||
Command: []string{"ceph", "osd", "tree"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
{
|
||||
ID: "osd-pool",
|
||||
Command: []string{"ceph", "osd", "pool", "ls", "detail"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
ID: "osd-pool",
|
||||
Command: []string{"ceph", "osd", "pool", "ls", "detail"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
{
|
||||
ID: "health",
|
||||
Command: []string{"ceph", "health", "detail"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
ID: "health",
|
||||
Command: []string{"ceph", "health", "detail"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
{
|
||||
ID: "auth",
|
||||
Command: []string{"ceph", "auth", "ls"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
ID: "auth",
|
||||
Command: []string{"ceph", "auth", "ls"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
{
|
||||
ID: "rgw-stats", // the disk usage (and other stats) of each object store bucket
|
||||
@@ -83,10 +90,18 @@ var CephCommands = []CephCommand{
|
||||
DefaultTimeout: "30s", // include a default timeout because this command will hang if the RGW daemon isn't running/is unhealthy
|
||||
},
|
||||
{
|
||||
ID: "rbd-du", // the disk usage of each PVC
|
||||
Command: []string{"rbd", "du"},
|
||||
Args: []string{"--pool=replicapool"},
|
||||
Format: "txt",
|
||||
ID: "rbd-du", // the disk usage of each PVC
|
||||
Command: []string{"rbd", "du"},
|
||||
Args: []string{"--pool=replicapool"},
|
||||
Format: "txt",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
{
|
||||
ID: "osd-df",
|
||||
Command: []string{"ceph", "osd", "df"},
|
||||
Args: []string{"-f", "json-pretty"},
|
||||
Format: "json",
|
||||
DefaultTimeout: "30s",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -133,8 +148,8 @@ func cephCommandExec(ctx context.Context, c *Collector, cephCollector *troublesh
|
||||
return errors.Wrap(err, "failed to exec command")
|
||||
}
|
||||
|
||||
pathPrefix := GetCephCollectorFilepath(cephCollector.CollectorName, cephCollector.Namespace)
|
||||
for srcFilename, _ := range results {
|
||||
pathPrefix := GetCephCollectorFilepath(cephCollector.CollectorName, cephCollector.Namespace)
|
||||
var dstFileName string
|
||||
switch {
|
||||
case strings.HasSuffix(srcFilename, "-stdout.txt"):
|
||||
@@ -203,10 +218,7 @@ func copyResult(srcResult CollectorResult, dstResult CollectorResult, bundlePath
|
||||
}
|
||||
return errors.Wrap(err, "failed to get reader")
|
||||
}
|
||||
|
||||
if reader, ok := reader.(io.ReadCloser); ok {
|
||||
defer reader.Close()
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
err = dstResult.SaveResult(bundlePath, dstKey, reader)
|
||||
if err != nil {
|
||||
|
||||
@@ -26,7 +26,11 @@ type Collector struct {
|
||||
|
||||
type Collectors []*Collector
|
||||
|
||||
func isExcluded(excludeVal multitype.BoolOrString) (bool, error) {
|
||||
func isExcluded(excludeVal *multitype.BoolOrString) (bool, error) {
|
||||
if excludeVal == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if excludeVal.Type == multitype.Bool {
|
||||
return excludeVal.BoolVal, nil
|
||||
}
|
||||
@@ -93,6 +97,14 @@ func (c *Collector) IsExcluded() bool {
|
||||
if isExcludedResult {
|
||||
return true
|
||||
}
|
||||
} else if c.Collect.RunPod != nil {
|
||||
isExcludedResult, err := isExcluded(c.Collect.RunPod.Exclude)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
if isExcludedResult {
|
||||
return true
|
||||
}
|
||||
} else if c.Collect.Exec != nil {
|
||||
isExcludedResult, err := isExcluded(c.Collect.Exec.Exclude)
|
||||
if err != nil {
|
||||
@@ -221,6 +233,8 @@ func (c *Collector) RunCollectorSync(clientConfig *rest.Config, client kubernete
|
||||
result, err = Logs(c, c.Collect.Logs)
|
||||
} else if c.Collect.Run != nil {
|
||||
result, err = Run(c, c.Collect.Run)
|
||||
} else if c.Collect.RunPod != nil {
|
||||
result, err = RunPod(c, c.Collect.RunPod)
|
||||
} else if c.Collect.Exec != nil {
|
||||
result, err = Exec(c, c.Collect.Exec)
|
||||
} else if c.Collect.Data != nil {
|
||||
|
||||
@@ -21,7 +21,6 @@ func TestCollector_RunCollectorSyncNoRedact(t *testing.T) {
|
||||
Data: &troubleshootv1beta2.Data{
|
||||
CollectorMeta: troubleshootv1beta2.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
@@ -54,7 +53,6 @@ pwd=***HIDDEN***;
|
||||
Data: &troubleshootv1beta2.Data{
|
||||
CollectorMeta: troubleshootv1beta2.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
@@ -89,7 +87,6 @@ pwd=***HIDDEN***;
|
||||
Data: &troubleshootv1beta2.Data{
|
||||
CollectorMeta: troubleshootv1beta2.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
@@ -124,7 +121,6 @@ pwd=***HIDDEN***;
|
||||
Data: &troubleshootv1beta2.Data{
|
||||
CollectorMeta: troubleshootv1beta2.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
@@ -162,7 +158,6 @@ pwd=***HIDDEN***;
|
||||
Data: &troubleshootv1beta2.Data{
|
||||
CollectorMeta: troubleshootv1beta2.CollectorMeta{
|
||||
CollectorName: "data/collectorname",
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
@@ -200,7 +195,6 @@ pwd=***HIDDEN***;
|
||||
Data: &troubleshootv1beta2.Data{
|
||||
CollectorMeta: troubleshootv1beta2.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
@@ -228,7 +222,6 @@ another line here
|
||||
Data: &troubleshootv1beta2.Data{
|
||||
CollectorMeta: troubleshootv1beta2.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `xyz123
|
||||
@@ -265,7 +258,7 @@ abc
|
||||
Data: &troubleshootv1beta2.Data{
|
||||
CollectorMeta: troubleshootv1beta2.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Exclude: multitype.BoolOrString{Type: multitype.String, StrVal: "true"},
|
||||
Exclude: multitype.FromString("true"),
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
@@ -310,7 +303,6 @@ func TestCollector_RunCollectorSync(t *testing.T) {
|
||||
Data: &troubleshootv1beta2.Data{
|
||||
CollectorMeta: troubleshootv1beta2.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package collect
|
||||
|
||||
type DatabaseConnection struct {
|
||||
IsConnected bool `json:"isConnected"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
IsConnected bool `json:"isConnected"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Variables map[string]string `json:"variables,omitempty"`
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sync"
|
||||
@@ -205,9 +206,12 @@ func Longhorn(c *Collector, longhornCollector *troubleshootv1beta2.Longhorn) (Co
|
||||
return nil, errors.Wrap(err, "collect longhorn logs")
|
||||
}
|
||||
logsDir := GetLonghornLogsDirectory(ns)
|
||||
for key, log := range logs {
|
||||
key = filepath.Join(logsDir, key)
|
||||
output.SaveResult(c.BundlePath, key, bytes.NewBuffer(log))
|
||||
for srcFilename, _ := range logs {
|
||||
dstFileName := path.Join(logsDir, srcFilename)
|
||||
err := copyResult(logs, output, c.BundlePath, srcFilename, dstFileName)
|
||||
if err != nil {
|
||||
logger.Printf("Failed to copy file %s; %v", srcFilename, err)
|
||||
}
|
||||
}
|
||||
|
||||
// https://longhorn.io/docs/1.1.1/advanced-resources/data-recovery/corrupted-replica/
|
||||
|
||||
@@ -18,8 +18,10 @@ func Mysql(c *Collector, databaseCollector *troubleshootv1beta2.Database) (Colle
|
||||
if err != nil {
|
||||
databaseConnection.Error = err.Error()
|
||||
} else {
|
||||
defer db.Close()
|
||||
query := `select version()`
|
||||
row := db.QueryRow(query)
|
||||
|
||||
version := ""
|
||||
if err := row.Scan(&version); err != nil {
|
||||
databaseConnection.Error = err.Error()
|
||||
@@ -27,6 +29,38 @@ func Mysql(c *Collector, databaseCollector *troubleshootv1beta2.Database) (Colle
|
||||
databaseConnection.IsConnected = true
|
||||
databaseConnection.Version = version
|
||||
}
|
||||
|
||||
requestedParameters := databaseCollector.Parameters
|
||||
if len(requestedParameters) > 0 {
|
||||
rows, err := db.Query("SHOW VARIABLES")
|
||||
|
||||
if err != nil {
|
||||
databaseConnection.Error = err.Error()
|
||||
} else {
|
||||
defer rows.Close()
|
||||
|
||||
variables := map[string]string{}
|
||||
for rows.Next() {
|
||||
var key, value string
|
||||
err = rows.Scan(&key, &value)
|
||||
if err != nil {
|
||||
databaseConnection.Error = err.Error()
|
||||
break
|
||||
}
|
||||
variables[key] = value
|
||||
}
|
||||
filteredVariables := map[string]string{}
|
||||
|
||||
for _, key := range requestedParameters {
|
||||
if value, ok := variables[key]; ok {
|
||||
filteredVariables[key] = value
|
||||
}
|
||||
|
||||
}
|
||||
databaseConnection.Variables = filteredVariables
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
b, err := json.Marshal(databaseConnection)
|
||||
|
||||
@@ -26,9 +26,7 @@ func redactResult(bundlePath string, input CollectorResult, additionalRedactors
|
||||
}
|
||||
return errors.Wrap(err, "failed to get reader")
|
||||
}
|
||||
if r, ok := r.(io.ReadCloser); ok {
|
||||
defer r.Close()
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
reader = r
|
||||
} else {
|
||||
|
||||
@@ -85,9 +85,9 @@ func (r CollectorResult) ReplaceResult(bundlePath string, relativePath string, r
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r CollectorResult) GetReader(bundlePath string, relativePath string) (io.Reader, error) {
|
||||
func (r CollectorResult) GetReader(bundlePath string, relativePath string) (io.ReadCloser, error) {
|
||||
if r[relativePath] != nil {
|
||||
return bytes.NewReader(r[relativePath]), nil
|
||||
return ioutil.NopCloser(bytes.NewReader(r[relativePath])), nil
|
||||
}
|
||||
|
||||
if bundlePath == "" {
|
||||
|
||||
+97
-63
@@ -16,6 +16,45 @@ import (
|
||||
)
|
||||
|
||||
func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult, error) {
|
||||
pullPolicy := corev1.PullIfNotPresent
|
||||
if runCollector.ImagePullPolicy != "" {
|
||||
pullPolicy = corev1.PullPolicy(runCollector.ImagePullPolicy)
|
||||
}
|
||||
|
||||
namespace := "default"
|
||||
if runCollector.Namespace != "" {
|
||||
namespace = runCollector.Namespace
|
||||
}
|
||||
|
||||
serviceAccountName := "default"
|
||||
if runCollector.ServiceAccountName != "" {
|
||||
serviceAccountName = runCollector.ServiceAccountName
|
||||
}
|
||||
|
||||
runPodCollector := &troubleshootv1beta2.RunPod{
|
||||
Name: runCollector.CollectorName,
|
||||
Namespace: namespace,
|
||||
Timeout: runCollector.Timeout,
|
||||
ImagePullSecret: runCollector.ImagePullSecret,
|
||||
PodSpec: corev1.PodSpec{
|
||||
RestartPolicy: corev1.RestartPolicyNever,
|
||||
ServiceAccountName: serviceAccountName,
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Image: runCollector.Image,
|
||||
ImagePullPolicy: pullPolicy,
|
||||
Name: "collector",
|
||||
Command: runCollector.Command,
|
||||
Args: runCollector.Args,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return RunPod(c, runPodCollector)
|
||||
}
|
||||
|
||||
func RunPod(c *Collector, runPodCollector *troubleshootv1beta2.RunPod) (CollectorResult, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := kubernetes.NewForConfig(c.ClientConfig)
|
||||
@@ -23,7 +62,7 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult,
|
||||
return nil, errors.Wrap(err, "failed to create client from config")
|
||||
}
|
||||
|
||||
pod, err := runPod(ctx, client, runCollector, c.Namespace)
|
||||
pod, err := runPodWithSpec(ctx, client, runPodCollector)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to run pod")
|
||||
}
|
||||
@@ -33,7 +72,7 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult,
|
||||
logger.Printf("Failed to delete pod %s: %v", pod.Name, err)
|
||||
}
|
||||
}()
|
||||
if runCollector.ImagePullSecret != nil && runCollector.ImagePullSecret.Data != nil {
|
||||
if runPodCollector.ImagePullSecret != nil && runPodCollector.ImagePullSecret.Data != nil {
|
||||
defer func() {
|
||||
for _, k := range pod.Spec.ImagePullSecrets {
|
||||
if err := client.CoreV1().Secrets(pod.Namespace).Delete(ctx, k.Name, metav1.DeleteOptions{}); err != nil {
|
||||
@@ -42,11 +81,11 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult,
|
||||
}
|
||||
}()
|
||||
}
|
||||
if runCollector.Timeout == "" {
|
||||
return runWithoutTimeout(ctx, c, pod, runCollector)
|
||||
if runPodCollector.Timeout == "" {
|
||||
return runWithoutTimeout(ctx, c, pod, runPodCollector)
|
||||
}
|
||||
|
||||
timeout, err := time.ParseDuration(runCollector.Timeout)
|
||||
timeout, err := time.ParseDuration(runPodCollector.Timeout)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse timeout")
|
||||
}
|
||||
@@ -58,7 +97,7 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult,
|
||||
defer cancel()
|
||||
|
||||
go func() {
|
||||
b, err := runWithoutTimeout(timeoutCtx, c, pod, runCollector)
|
||||
b, err := runWithoutTimeout(timeoutCtx, c, pod, runPodCollector)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
} else {
|
||||
@@ -76,7 +115,52 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult,
|
||||
}
|
||||
}
|
||||
|
||||
func runWithoutTimeout(ctx context.Context, c *Collector, pod *corev1.Pod, runCollector *troubleshootv1beta2.Run) (CollectorResult, error) {
|
||||
func runPodWithSpec(ctx context.Context, client *kubernetes.Clientset, runPodCollector *troubleshootv1beta2.RunPod) (*corev1.Pod, error) {
|
||||
podLabels := make(map[string]string)
|
||||
podLabels["troubleshoot-role"] = "run-collector"
|
||||
|
||||
namespace := "default"
|
||||
if runPodCollector.Namespace != "" {
|
||||
namespace = runPodCollector.Namespace
|
||||
}
|
||||
|
||||
podName := "run-pod"
|
||||
if runPodCollector.CollectorName != "" {
|
||||
podName = runPodCollector.CollectorName
|
||||
} else if runPodCollector.Name != "" {
|
||||
podName = runPodCollector.Name
|
||||
}
|
||||
|
||||
pod := corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
Namespace: namespace,
|
||||
Labels: podLabels,
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
Spec: runPodCollector.PodSpec,
|
||||
}
|
||||
|
||||
if runPodCollector.ImagePullSecret != nil && runPodCollector.ImagePullSecret.Data != nil {
|
||||
secretName, err := createSecret(ctx, client, pod.Namespace, runPodCollector.ImagePullSecret)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create secret")
|
||||
}
|
||||
pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, corev1.LocalObjectReference{Name: secretName})
|
||||
}
|
||||
|
||||
created, err := client.CoreV1().Pods(namespace).Create(ctx, &pod, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create pod")
|
||||
}
|
||||
|
||||
return created, nil
|
||||
}
|
||||
|
||||
func runWithoutTimeout(ctx context.Context, c *Collector, pod *corev1.Pod, runPodCollector *troubleshootv1beta2.RunPod) (CollectorResult, error) {
|
||||
client, err := kubernetes.NewForConfig(c.ClientConfig)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed create client from config")
|
||||
@@ -104,10 +188,15 @@ func runWithoutTimeout(ctx context.Context, c *Collector, pod *corev1.Pod, runCo
|
||||
|
||||
output := NewResult()
|
||||
|
||||
collectorName := runPodCollector.Name
|
||||
if collectorName == "" {
|
||||
collectorName = runPodCollector.CollectorName
|
||||
}
|
||||
|
||||
limits := troubleshootv1beta2.LogLimits{
|
||||
MaxLines: 10000,
|
||||
}
|
||||
podLogs, err := savePodLogs(ctx, c.BundlePath, client, *pod, runCollector.Name, "", &limits, true)
|
||||
podLogs, err := savePodLogs(ctx, c.BundlePath, client, *pod, collectorName, "", &limits, true)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get pod logs")
|
||||
}
|
||||
@@ -119,61 +208,6 @@ func runWithoutTimeout(ctx context.Context, c *Collector, pod *corev1.Pod, runCo
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func runPod(ctx context.Context, client *kubernetes.Clientset, runCollector *troubleshootv1beta2.Run, namespace string) (*corev1.Pod, error) {
|
||||
podLabels := make(map[string]string)
|
||||
podLabels["troubleshoot-role"] = "run-collector"
|
||||
|
||||
pullPolicy := corev1.PullIfNotPresent
|
||||
if runCollector.ImagePullPolicy != "" {
|
||||
pullPolicy = corev1.PullPolicy(runCollector.ImagePullPolicy)
|
||||
}
|
||||
|
||||
if namespace == "" {
|
||||
namespace = runCollector.Namespace
|
||||
}
|
||||
if namespace == "" {
|
||||
namespace = "default"
|
||||
}
|
||||
|
||||
pod := corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: runCollector.CollectorName,
|
||||
Namespace: namespace,
|
||||
Labels: podLabels,
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
RestartPolicy: corev1.RestartPolicyNever,
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Image: runCollector.Image,
|
||||
ImagePullPolicy: pullPolicy,
|
||||
Name: "collector",
|
||||
Command: runCollector.Command,
|
||||
Args: runCollector.Args,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if runCollector.ImagePullSecret != nil && runCollector.ImagePullSecret.Data != nil {
|
||||
secretName, err := createSecret(ctx, client, pod.Namespace, runCollector.ImagePullSecret)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create secret")
|
||||
}
|
||||
pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, corev1.LocalObjectReference{Name: secretName})
|
||||
}
|
||||
created, err := client.CoreV1().Pods(namespace).Create(ctx, &pod, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create pod")
|
||||
}
|
||||
|
||||
return created, nil
|
||||
}
|
||||
|
||||
func createSecret(ctx context.Context, client kubernetes.Interface, namespace string, imagePullSecret *troubleshootv1beta2.ImagePullSecrets) (string, error) {
|
||||
if imagePullSecret.Data == nil {
|
||||
return "", nil
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// ValidateOutputPath takes an output file path and returns it as an absolute path.
|
||||
// It returns an error if the absolute path cannot be determined or if the parent directory does not exist.
|
||||
func ValidateOutputPath(outputPath string) (string, error) {
|
||||
outputPath, err := filepath.Abs(outputPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err := os.Stat(filepath.Dir(outputPath)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return outputPath, nil
|
||||
}
|
||||
+14
-7
@@ -114,13 +114,20 @@ func IsPodUnhealthy(pod *corev1.Pod) bool {
|
||||
}
|
||||
|
||||
reason := GetPodStatusReason(pod)
|
||||
|
||||
switch PodStatusReason(reason) {
|
||||
case PodStatusReasonRunning:
|
||||
fallthrough
|
||||
case PodStatusReasonCompleted:
|
||||
return false
|
||||
if PodStatusReason(reason) == PodStatusReasonCompleted {
|
||||
return false // completed pods are healthy pods
|
||||
}
|
||||
|
||||
return true
|
||||
if PodStatusReason(reason) != PodStatusReasonRunning {
|
||||
return true // pods that are not completed or running are unhealthy
|
||||
}
|
||||
|
||||
// running pods with unready containers are not healthy
|
||||
for _, containerStatus := range pod.Status.ContainerStatuses {
|
||||
if !containerStatus.Ready {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package k8sutil
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsPodUnhealthy(t *testing.T) {
|
||||
andTrue := true
|
||||
tests := []struct {
|
||||
name string
|
||||
pod *corev1.Pod
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "healthy pod with init containers",
|
||||
want: false,
|
||||
pod: &corev1.Pod{
|
||||
Status: corev1.PodStatus{
|
||||
Phase: "Running",
|
||||
Conditions: []corev1.PodCondition{
|
||||
// ignored here
|
||||
},
|
||||
InitContainerStatuses: []corev1.ContainerStatus{
|
||||
{
|
||||
Name: "init",
|
||||
State: corev1.ContainerState{
|
||||
Terminated: &corev1.ContainerStateTerminated{
|
||||
ExitCode: 0,
|
||||
Reason: "Completed",
|
||||
},
|
||||
},
|
||||
Ready: true,
|
||||
RestartCount: 2,
|
||||
Image: "projectcontour/contour:v1.11.0",
|
||||
ImageID: "docker://sha256:12878e02b6f969de1456b51b0093f289fd195db956837ccd75aa679e9dac24d9",
|
||||
ContainerID: "docker://50fc0794fa1402b1a48521e2fd380a92521a69db70ad25c9699c91fccd839d70",
|
||||
},
|
||||
},
|
||||
ContainerStatuses: []corev1.ContainerStatus{
|
||||
{
|
||||
Name: "contour",
|
||||
State: corev1.ContainerState{
|
||||
Running: &corev1.ContainerStateRunning{},
|
||||
},
|
||||
Ready: true,
|
||||
RestartCount: 5,
|
||||
Image: "projectcontour/contour:v1.11.0",
|
||||
ImageID: "docker://sha256:12878e02b6f969de1456b51b0093f289fd195db956837ccd75aa679e9dac24d9",
|
||||
ContainerID: "docker://50fc0794fa1402b1a48521e2fd380a92521a69db70ad25c9699c91fccd839d70",
|
||||
Started: &andTrue,
|
||||
},
|
||||
},
|
||||
QOSClass: corev1.PodQOSBestEffort,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "running pod with one unhealthy container",
|
||||
want: true,
|
||||
pod: &corev1.Pod{
|
||||
Status: corev1.PodStatus{
|
||||
Phase: "Running",
|
||||
Conditions: []corev1.PodCondition{
|
||||
// ignored here
|
||||
},
|
||||
ContainerStatuses: []corev1.ContainerStatus{
|
||||
{
|
||||
Name: "envoy",
|
||||
State: corev1.ContainerState{
|
||||
Running: &corev1.ContainerStateRunning{},
|
||||
},
|
||||
Ready: false,
|
||||
RestartCount: 5,
|
||||
Started: &andTrue,
|
||||
},
|
||||
{
|
||||
Name: "shutdown-manager",
|
||||
State: corev1.ContainerState{
|
||||
Running: &corev1.ContainerStateRunning{},
|
||||
},
|
||||
Ready: true,
|
||||
RestartCount: 5,
|
||||
Started: &andTrue,
|
||||
},
|
||||
},
|
||||
QOSClass: corev1.PodQOSBestEffort,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
|
||||
got := IsPodUnhealthy(tt.pod)
|
||||
req.Equal(tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ package multitype
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
)
|
||||
@@ -33,22 +34,25 @@ const (
|
||||
)
|
||||
|
||||
// FromBool creates an BoolOrString object with a bool value.
|
||||
func FromBool(val bool) BoolOrString {
|
||||
return BoolOrString{Type: Bool, BoolVal: val}
|
||||
func FromBool(val bool) *BoolOrString {
|
||||
return &BoolOrString{Type: Bool, BoolVal: val}
|
||||
}
|
||||
|
||||
// FromString creates an BoolOrString object with a string value.
|
||||
func FromString(val string) BoolOrString {
|
||||
return BoolOrString{Type: String, StrVal: val}
|
||||
func FromString(val string) *BoolOrString {
|
||||
return &BoolOrString{Type: String, StrVal: val}
|
||||
}
|
||||
|
||||
// Parse the given string
|
||||
func Parse(val string) BoolOrString {
|
||||
func Parse(val string) *BoolOrString {
|
||||
return FromString(val)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaller boolerface.
|
||||
func (boolstr *BoolOrString) UnmarshalJSON(value []byte) error {
|
||||
if boolstr == nil {
|
||||
return nil
|
||||
}
|
||||
if value[0] == '"' {
|
||||
boolstr.Type = String
|
||||
return json.Unmarshal(value, &boolstr.StrVal)
|
||||
@@ -59,6 +63,9 @@ func (boolstr *BoolOrString) UnmarshalJSON(value []byte) error {
|
||||
|
||||
// String returns the string value, '1' for true, or '0' for false.
|
||||
func (boolstr *BoolOrString) String() string {
|
||||
if boolstr == nil {
|
||||
return "0"
|
||||
}
|
||||
if boolstr.Type == String {
|
||||
return boolstr.StrVal
|
||||
} else if boolstr.BoolVal {
|
||||
@@ -69,7 +76,10 @@ func (boolstr *BoolOrString) String() string {
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaller interface.
|
||||
func (boolstr BoolOrString) MarshalJSON() ([]byte, error) {
|
||||
func (boolstr *BoolOrString) MarshalJSON() ([]byte, error) {
|
||||
if boolstr == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
switch boolstr.Type {
|
||||
case Bool:
|
||||
return json.Marshal(boolstr.BoolVal)
|
||||
@@ -81,7 +91,10 @@ func (boolstr BoolOrString) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
// MarshalYAML implements the yaml.Marshaller interface https://godoc.org/gopkg.in/yaml.v3#Marshaler
|
||||
func (boolstr BoolOrString) MarshalYAML() (interface{}, error) {
|
||||
func (boolstr *BoolOrString) MarshalYAML() (interface{}, error) {
|
||||
if boolstr == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
switch boolstr.Type {
|
||||
case Bool:
|
||||
return boolstr.BoolVal, nil
|
||||
@@ -116,3 +129,30 @@ func (boolstr *BoolOrString) Fuzz(c fuzz.Continue) {
|
||||
c.Fuzz(&boolstr.StrVal)
|
||||
}
|
||||
}
|
||||
|
||||
// BoolOrDefaultFalse returns bool val, if strValu is parsed returns parsed value else false as default when parse error
|
||||
func (boolstr *BoolOrString) BoolOrDefaultFalse() bool {
|
||||
if boolstr == nil {
|
||||
return false
|
||||
}
|
||||
val, err := boolstr.Bool()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Bool returns bool val, if strValu is parsed returns parsed value else false with parse error
|
||||
func (boolstr *BoolOrString) Bool() (bool, error) {
|
||||
if boolstr == nil {
|
||||
return false, nil
|
||||
}
|
||||
if boolstr.Type == Bool {
|
||||
return boolstr.BoolVal, nil
|
||||
}
|
||||
parsed, err := strconv.ParseBool(boolstr.StrVal)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to parse bool string(err: %v)", err)
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
// Based on https://github.com/kubernetes/apimachinery/blob/455a99f/pkg/util/intstr/intstr.go
|
||||
|
||||
package multitype
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func TestBoolOrString_Bool(t *testing.T) {
|
||||
type fields struct {
|
||||
Type BoolOrStringType
|
||||
BoolVal bool
|
||||
StrVal string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "expect true when BoolVal is true",
|
||||
fields: fields{Type: Bool, BoolVal: true},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when BoolVal is false",
|
||||
fields: fields{Type: Bool, BoolVal: false},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when StrVal is 'false'",
|
||||
fields: fields{Type: String, StrVal: "false"},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect true when StrVal is 'true'",
|
||||
fields: fields{Type: String, StrVal: "true"},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false, error when StrVal is ''",
|
||||
fields: fields{Type: String, StrVal: "''"},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "expect false, error when StrVal is '123'",
|
||||
fields: fields{Type: String, StrVal: "123"},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
}, {
|
||||
name: "expect true, nil when Type is not specified, StrVal is 'true'",
|
||||
fields: fields{StrVal: "true"},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false, nil when Type is not specified, StrVal is 'false'",
|
||||
fields: fields{StrVal: "false"},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false, nil when Type is not specified, StrVal is 'false' and BoolVal is true",
|
||||
fields: fields{StrVal: "false", BoolVal: true},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
boolstr := &BoolOrString{
|
||||
Type: tt.fields.Type,
|
||||
BoolVal: tt.fields.BoolVal,
|
||||
StrVal: tt.fields.StrVal,
|
||||
}
|
||||
got, err := boolstr.Bool()
|
||||
req.Equal(tt.want, boolstr.BoolOrDefaultFalse())
|
||||
if tt.wantErr {
|
||||
req.Error(err)
|
||||
return
|
||||
}
|
||||
req.NoError(err)
|
||||
req.Equal(tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolOrString_MarshalOmitempty(t *testing.T) {
|
||||
type S struct {
|
||||
String string `json:"string,omitempty" yaml:"string,omitempty"`
|
||||
Multi *BoolOrString `json:"multi,omitempty" yaml:"multi,omitempty"`
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
wantJSON string
|
||||
wantYAML string
|
||||
}{
|
||||
{
|
||||
wantJSON: `{"string":"string"}`,
|
||||
wantYAML: "string: string",
|
||||
},
|
||||
{
|
||||
wantJSON: `{"string":"string","multi":false}`,
|
||||
wantYAML: "string: string\nmulti: false",
|
||||
},
|
||||
{
|
||||
wantJSON: `{"string":"string","multi":"false"}`,
|
||||
wantYAML: "string: string\nmulti: \"false\"",
|
||||
},
|
||||
{
|
||||
wantJSON: `{"string":"string","multi":true}`,
|
||||
wantYAML: "string: string\nmulti: true",
|
||||
},
|
||||
{
|
||||
wantJSON: `{"string":"string","multi":"true"}`,
|
||||
wantYAML: "string: string\nmulti: \"true\"",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
ass := require.New(t)
|
||||
|
||||
var sJSON S
|
||||
err := json.Unmarshal([]byte(tt.wantJSON), &sJSON)
|
||||
req.NoError(err)
|
||||
|
||||
out, err := json.Marshal(sJSON)
|
||||
req.NoError(err)
|
||||
ass.Equal(tt.wantJSON, strings.TrimSpace(string(out)))
|
||||
|
||||
var sYAML S
|
||||
err = json.Unmarshal([]byte(tt.wantJSON), &sYAML)
|
||||
req.NoError(err)
|
||||
|
||||
out, err = yaml.Marshal(sYAML)
|
||||
req.NoError(err)
|
||||
ass.Equal(tt.wantYAML, strings.TrimSpace(string(out)))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
analyze "github.com/replicatedhq/troubleshoot/pkg/analyze"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/logger"
|
||||
)
|
||||
|
||||
// Analyze runs the analyze phase of preflight checks
|
||||
@@ -77,8 +78,14 @@ func doAnalyze(allCollectedData map[string][]byte, analyzers []*troubleshootv1be
|
||||
for _, analyzer := range analyzers {
|
||||
analyzeResult, err := analyze.Analyze(analyzer, getCollectedFileContents, getChildCollectedFileContents)
|
||||
if err != nil {
|
||||
strict, strictErr := HasStrictAnalyzer(analyzer)
|
||||
if strictErr != nil {
|
||||
logger.Printf("failed to determine if analyzer %v is strict: %s", analyzer, strictErr)
|
||||
}
|
||||
|
||||
analyzeResult = []*analyze.AnalyzeResult{
|
||||
{
|
||||
Strict: strict,
|
||||
IsFail: true,
|
||||
Title: "Analyzer Failed",
|
||||
Message: err.Error(),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package preflight
|
||||
|
||||
type UploadPreflightResult struct {
|
||||
Strict bool `json:"strict,omitempty"`
|
||||
IsFail bool `json:"isFail,omitempty"`
|
||||
IsWarn bool `json:"isWarn,omitempty"`
|
||||
IsPass bool `json:"isPass,omitempty"`
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package preflight
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
)
|
||||
|
||||
// HasStrictAnalyzers - checks and returns true if a preflight's analyzer has strict:true, else false
|
||||
func HasStrictAnalyzers(preflight *troubleshootv1beta2.Preflight) (bool, error) {
|
||||
if preflight == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
marshalledAnalyzers, err := json.Marshal(preflight.Spec.Analyzers) // marshall and remove nil Analyzers eg result: "[{\"clusterVersion\":{\"exclude\":\"\",\"strict\":\"false\",\"outcomes\":null}}]"
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to marshal analyzers")
|
||||
}
|
||||
|
||||
analyzersMap := []map[string]interface{}{}
|
||||
err = json.Unmarshal(marshalledAnalyzers, &analyzersMap) // Unmarshall again so we can loop over non nil analyzers
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to unmarshal analyzers")
|
||||
}
|
||||
|
||||
// analyzerMap will ignore empty Analyzers and loop around Analyzer with data
|
||||
for _, analyzers := range analyzersMap { // for each analyzer: map["clusterVersion": map[string]interface{} ["exclude": "", "strict": "true", "outcomes": nil]
|
||||
hasStrictAnalyzer, err := hasStrictAnalyzer(analyzers)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to check if analyzer has strict:true")
|
||||
}
|
||||
if hasStrictAnalyzer {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// HasStrictAnalyzers - checks and returns true if a preflight's analyzer has strict:true, else false
|
||||
func HasStrictAnalyzer(analyzer *troubleshootv1beta2.Analyze) (bool, error) {
|
||||
marshalledAnalyzer, err := json.Marshal(analyzer)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "error while marshalling analyzer")
|
||||
}
|
||||
|
||||
analyzerMap := make(map[string]interface{})
|
||||
err = json.Unmarshal(marshalledAnalyzer, &analyzerMap) // Unmarshall again so we can loop over non nil analyzers
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to unmarshal analyzers")
|
||||
}
|
||||
return hasStrictAnalyzer(analyzerMap)
|
||||
}
|
||||
|
||||
func hasStrictAnalyzer(analyzerMap map[string]interface{}) (bool, error) {
|
||||
for _, analyzer := range analyzerMap { // for each analyzerMeta: map[string]interface{} ["exclude": "", "strict": "true", "outcomes": nil]
|
||||
marshalledAnalyzer, err := json.Marshal(analyzer)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "error while marshalling analyzer")
|
||||
}
|
||||
// return Analyzer.Strict which can be extracted from AnalyzeMeta
|
||||
analyzeMeta := troubleshootv1beta2.AnalyzeMeta{}
|
||||
err = json.Unmarshal(marshalledAnalyzer, &analyzeMeta)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "error while un-marshalling marshalledAnalyzers")
|
||||
}
|
||||
if analyzeMeta.Strict.BoolOrDefaultFalse() {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// HasStrictAnalyzersFailed - checks if preflight analyzer's result is strict:true and isFail:true, then returns true else false
|
||||
func HasStrictAnalyzersFailed(preflightResult *UploadPreflightResults) bool {
|
||||
hasStrictAnalyzersFailed := false
|
||||
// if results are empty, treat as failure
|
||||
if preflightResult == nil || len(preflightResult.Results) == 0 {
|
||||
hasStrictAnalyzersFailed = true
|
||||
} else {
|
||||
for _, result := range preflightResult.Results {
|
||||
if result.IsFail && result.Strict {
|
||||
hasStrictAnalyzersFailed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasStrictAnalyzersFailed
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
package preflight
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/multitype"
|
||||
)
|
||||
|
||||
var (
|
||||
analyzeMetaStrictFalseStr = troubleshootv1beta2.AnalyzeMeta{
|
||||
Strict: &multitype.BoolOrString{
|
||||
StrVal: "false",
|
||||
},
|
||||
}
|
||||
analyzeMetaStrictInvalidStr = troubleshootv1beta2.AnalyzeMeta{
|
||||
Strict: &multitype.BoolOrString{
|
||||
StrVal: "invalid",
|
||||
},
|
||||
}
|
||||
analyzeMetaStrictTrueStr = troubleshootv1beta2.AnalyzeMeta{
|
||||
Strict: &multitype.BoolOrString{
|
||||
StrVal: "true",
|
||||
},
|
||||
}
|
||||
analyzeMetaStrictFalseBool = troubleshootv1beta2.AnalyzeMeta{
|
||||
Strict: &multitype.BoolOrString{
|
||||
Type: multitype.Bool,
|
||||
BoolVal: false,
|
||||
},
|
||||
}
|
||||
analyzeMetaStrictTrueBool = troubleshootv1beta2.AnalyzeMeta{
|
||||
Strict: &multitype.BoolOrString{
|
||||
Type: multitype.Bool,
|
||||
BoolVal: true,
|
||||
},
|
||||
}
|
||||
analyzeMetaStrictFalseInt = troubleshootv1beta2.AnalyzeMeta{
|
||||
Strict: &multitype.BoolOrString{
|
||||
StrVal: "0",
|
||||
},
|
||||
}
|
||||
analyzeMetaStrictTrueInt = troubleshootv1beta2.AnalyzeMeta{
|
||||
Strict: &multitype.BoolOrString{
|
||||
Type: multitype.String,
|
||||
StrVal: "1",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestHasStrictAnalyzers(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
preflight *troubleshootv1beta2.Preflight
|
||||
want bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "expect false when preflight is nil",
|
||||
preflight: nil,
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when preflight spec is empty",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when preflight spec's analyzers is nil",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: nil,
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when preflight spec's analyzers is empty",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{},
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when preflight spec's analyzer has nil analyzer",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when preflight spec's analyzer has analyzer with strict str: false",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictFalseStr},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when preflight spec's analyzer has analyzer with strict bool: false",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictFalseBool},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when preflight spec's analyzer has analyzer with strict str: invalid",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictInvalidStr},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect true when preflight spec's analyzer has analyzer with strict str: true",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictTrueStr},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect true when preflight spec's analyzer has analyzer with strict bool: true",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictTrueBool},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect true when preflight spec's analyzer has analyzer with strict int: 1",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictTrueInt},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect false when preflight spec's analyzer has analyzer with strict int: 0",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictFalseInt},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect true when preflight spec's analyzer has analyzer with strict true in one of multiple analyzers",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictFalseInt},
|
||||
}, {
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictTrueBool},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect true when preflight spec's analyzer has analyzer with strict true in one of multiple analyzers",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictFalseInt},
|
||||
}, {
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictTrueBool},
|
||||
}, {
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictInvalidStr},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect true when preflight spec's analyzer has analyzer with strict true in one of multiple analyzers",
|
||||
preflight: &troubleshootv1beta2.Preflight{
|
||||
Spec: troubleshootv1beta2.PreflightSpec{
|
||||
Analyzers: []*troubleshootv1beta2.Analyze{
|
||||
{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictFalseInt},
|
||||
StorageClass: &troubleshootv1beta2.StorageClass{AnalyzeMeta: analyzeMetaStrictFalseInt},
|
||||
Secret: &troubleshootv1beta2.AnalyzeSecret{AnalyzeMeta: analyzeMetaStrictTrueBool},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := HasStrictAnalyzers(tt.preflight)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("HasStrictAnalyzers error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("HasStrictAnalyzers() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasStrictAnalyzerFailed(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
preflightResult *UploadPreflightResults
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "expect true when preflightResult is nil",
|
||||
preflightResult: nil,
|
||||
want: true,
|
||||
}, {
|
||||
name: "expect true when preflightResult.Results is nil",
|
||||
preflightResult: &UploadPreflightResults{
|
||||
Results: nil,
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "expect true when preflightResult.Results is empty",
|
||||
preflightResult: &UploadPreflightResults{
|
||||
Results: []*UploadPreflightResult{},
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "expect false when preflightResult.Results has result with strict false, IsFail false",
|
||||
preflightResult: &UploadPreflightResults{
|
||||
Results: []*UploadPreflightResult{
|
||||
{Strict: false, IsFail: false},
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
}, {
|
||||
name: "expect false when preflightResult.Results has result with strict false, IsFail true",
|
||||
preflightResult: &UploadPreflightResults{
|
||||
Results: []*UploadPreflightResult{
|
||||
{Strict: false, IsFail: true},
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
}, {
|
||||
name: "expect true when preflightResult.Results has result with strict true, IsFail true",
|
||||
preflightResult: &UploadPreflightResults{
|
||||
Results: []*UploadPreflightResult{
|
||||
{Strict: true, IsFail: true},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "expect true when preflightResult.Results has multiple results where atleast result has strict true, IsFail true",
|
||||
preflightResult: &UploadPreflightResults{
|
||||
Results: []*UploadPreflightResult{
|
||||
{Strict: true, IsFail: true},
|
||||
{Strict: false, IsFail: true},
|
||||
{Strict: true, IsFail: false},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := HasStrictAnalyzersFailed(tt.preflightResult); got != tt.want {
|
||||
t.Errorf("HasStrictAnalyzersFailed() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasStrictAnalyzer(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
analyzer *troubleshootv1beta2.Analyze
|
||||
want bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "expect strict=false, err=nil when analyzer is nil",
|
||||
analyzer: nil,
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect strict=false, err=nil when analyzer is empty",
|
||||
analyzer: &troubleshootv1beta2.Analyze{},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect strict=false, err=nil when ClusterVersion analyzer has strict=1",
|
||||
analyzer: &troubleshootv1beta2.Analyze{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictFalseInt},
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect strict=true, err=nil when ClusterVersion analyzer has strict=true",
|
||||
analyzer: &troubleshootv1beta2.Analyze{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictTrueInt},
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect strict=false, err=nil when ClusterVersion analyzer is nil",
|
||||
analyzer: &troubleshootv1beta2.Analyze{
|
||||
ClusterVersion: nil,
|
||||
},
|
||||
want: false,
|
||||
wantErr: false,
|
||||
}, {
|
||||
name: "expect strict=true, err=nil when one of the analyzers has strict=true",
|
||||
analyzer: &troubleshootv1beta2.Analyze{
|
||||
ClusterVersion: &troubleshootv1beta2.ClusterVersion{AnalyzeMeta: analyzeMetaStrictFalseInt},
|
||||
StorageClass: &troubleshootv1beta2.StorageClass{AnalyzeMeta: analyzeMetaStrictFalseInt},
|
||||
Secret: &troubleshootv1beta2.AnalyzeSecret{AnalyzeMeta: analyzeMetaStrictTrueBool},
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := HasStrictAnalyzer(tt.analyzer)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("HasStrictAnalyzer() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("HasStrictAnalyzer() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -19,20 +19,44 @@ var (
|
||||
SupportBundleNameRegex = regexp.MustCompile(`^\/?support-bundle-(\d{4})-(\d{2})-(\d{2})T(\d{2})_(\d{2})_(\d{2})\/?`)
|
||||
)
|
||||
|
||||
func GetPodDetails(bundleArchive string, podNamespace string, podName string) (*types.PodDetails, error) {
|
||||
podDetails := types.PodDetails{}
|
||||
func getPodsFilePath(namespace string) string {
|
||||
return filepath.Join("cluster-resources", "pods", fmt.Sprintf("%s.json", namespace))
|
||||
}
|
||||
|
||||
nsPodsFilePath := filepath.Join("cluster-resources", "pods", fmt.Sprintf("%s.json", podNamespace))
|
||||
nsEventsFilePath := filepath.Join("cluster-resources", "events", fmt.Sprintf("%s.json", podNamespace))
|
||||
func getContainerLogsFilePath(namespace string, podName string, containerName string) string {
|
||||
return filepath.Join("cluster-resources", "pods", "logs", namespace, podName, fmt.Sprintf("%s.log", containerName))
|
||||
}
|
||||
|
||||
func getEventsFilePath(namespace string) string {
|
||||
return filepath.Join("cluster-resources", "events", fmt.Sprintf("%s.json", namespace))
|
||||
}
|
||||
|
||||
func GetPodDetails(bundleArchive string, podNamespace string, podName string) (*types.PodDetails, error) {
|
||||
nsPodsFilePath := getPodsFilePath(podNamespace)
|
||||
nsEventsFilePath := getEventsFilePath(podNamespace)
|
||||
|
||||
files, err := GetFilesContents(bundleArchive, []string{nsPodsFilePath, nsEventsFilePath})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get files contents")
|
||||
}
|
||||
|
||||
return getPodDetailsFromFiles(files, podNamespace, podName)
|
||||
}
|
||||
|
||||
func getPodDetailsFromFiles(files map[string][]byte, podNamespace string, podName string) (*types.PodDetails, error) {
|
||||
podDetails := types.PodDetails{}
|
||||
|
||||
nsPodsFilePath := getPodsFilePath(podNamespace)
|
||||
nsEventsFilePath := getEventsFilePath(podNamespace)
|
||||
|
||||
var nsEvents []corev1.Event
|
||||
if err := json.Unmarshal(files[nsEventsFilePath], &nsEvents); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal events")
|
||||
// try new format
|
||||
var nsEventsList corev1.EventList
|
||||
if err := json.Unmarshal(files[nsEventsFilePath], &nsEventsList); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal events")
|
||||
}
|
||||
nsEvents = nsEventsList.Items
|
||||
}
|
||||
podEvents := []corev1.Event{}
|
||||
for _, event := range nsEvents {
|
||||
@@ -44,7 +68,12 @@ func GetPodDetails(bundleArchive string, podNamespace string, podName string) (*
|
||||
|
||||
var podsArr []corev1.Pod
|
||||
if err := json.Unmarshal(files[nsPodsFilePath], &podsArr); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal pods")
|
||||
// try new format
|
||||
var podsList corev1.PodList
|
||||
if err := json.Unmarshal(files[nsPodsFilePath], &podsList); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal pods")
|
||||
}
|
||||
podsArr = podsList.Items
|
||||
}
|
||||
for _, pod := range podsArr {
|
||||
if pod.Name == podName && pod.Namespace == podNamespace {
|
||||
@@ -53,14 +82,14 @@ func GetPodDetails(bundleArchive string, podNamespace string, podName string) (*
|
||||
for _, i := range pod.Spec.InitContainers {
|
||||
podDetails.PodContainers = append(podDetails.PodContainers, types.PodContainer{
|
||||
Name: i.Name,
|
||||
LogsFilePath: filepath.Join("cluster-resources", "pods", "logs", pod.Namespace, pod.Name, fmt.Sprintf("%s.log", i.Name)),
|
||||
LogsFilePath: getContainerLogsFilePath(pod.Namespace, pod.Name, i.Name),
|
||||
IsInitContainer: true,
|
||||
})
|
||||
}
|
||||
for _, c := range pod.Spec.Containers {
|
||||
podDetails.PodContainers = append(podDetails.PodContainers, types.PodContainer{
|
||||
Name: c.Name,
|
||||
LogsFilePath: filepath.Join("cluster-resources", "pods", "logs", pod.Namespace, pod.Name, fmt.Sprintf("%s.log", c.Name)),
|
||||
LogsFilePath: getContainerLogsFilePath(pod.Namespace, pod.Name, c.Name),
|
||||
IsInitContainer: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
package supportbundle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
types "github.com/replicatedhq/troubleshoot/pkg/supportbundle/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func Test_getPodDetails(t *testing.T) {
|
||||
podNamespace := "default"
|
||||
podName := "hello-27436131-pxhk9"
|
||||
|
||||
podsFileContentOldFormat := `[
|
||||
{
|
||||
"kind": "Pod",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "hello-27436131-pxhk9",
|
||||
"namespace": "default"
|
||||
},
|
||||
"spec": {
|
||||
"initContainers": [
|
||||
{
|
||||
"name": "remove-lost-found"
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
{
|
||||
"name": "hello"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]`
|
||||
|
||||
podsFileContentNewFormat := fmt.Sprintf(`{
|
||||
"kind": "PodList",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"resourceVersion": "5389414"
|
||||
},
|
||||
"items": %s
|
||||
}`, podsFileContentOldFormat)
|
||||
|
||||
eventsFileContentOldFormat := `[
|
||||
{
|
||||
"kind": "Event",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "example-nginx.16d85cebe302a9b1",
|
||||
"namespace": "default"
|
||||
},
|
||||
"involvedObject": {
|
||||
"kind": "Deployment",
|
||||
"namespace": "default",
|
||||
"name": "example-nginx"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Event",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "hello-27436131-pxhk9.16d85cf27380b4fa",
|
||||
"namespace": "default"
|
||||
},
|
||||
"involvedObject": {
|
||||
"kind": "Pod",
|
||||
"namespace": "default",
|
||||
"name": "hello-27436131-pxhk9"
|
||||
}
|
||||
}
|
||||
]`
|
||||
|
||||
eventsFileContentNewFormat := fmt.Sprintf(`{
|
||||
"kind": "EventList",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"resourceVersion": "5389515"
|
||||
},
|
||||
"items": %s
|
||||
}`, eventsFileContentOldFormat)
|
||||
|
||||
removeLostAndFoundInitContainerLogs := `some logs here`
|
||||
helloContainerLogs := `Tue Mar 1 20:53:00 UTC 2022 Hello`
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
files map[string][]byte
|
||||
expect *types.PodDetails
|
||||
}{
|
||||
{
|
||||
name: "old support bundle format",
|
||||
files: map[string][]byte{
|
||||
getPodsFilePath(podNamespace): []byte(podsFileContentOldFormat),
|
||||
getEventsFilePath(podNamespace): []byte(eventsFileContentOldFormat),
|
||||
getContainerLogsFilePath(podNamespace, podName, "remove-lost-found"): []byte(removeLostAndFoundInitContainerLogs),
|
||||
getContainerLogsFilePath(podNamespace, podName, "hello"): []byte(helloContainerLogs),
|
||||
},
|
||||
expect: &types.PodDetails{
|
||||
PodDefinition: corev1.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
Namespace: podNamespace,
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
InitContainers: []corev1.Container{
|
||||
{
|
||||
Name: "remove-lost-found",
|
||||
},
|
||||
},
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "hello",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
PodEvents: []corev1.Event{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Event",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "hello-27436131-pxhk9.16d85cf27380b4fa",
|
||||
Namespace: podNamespace,
|
||||
},
|
||||
InvolvedObject: corev1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Namespace: podNamespace,
|
||||
Name: podName,
|
||||
},
|
||||
},
|
||||
},
|
||||
PodContainers: []types.PodContainer{
|
||||
{
|
||||
Name: "remove-lost-found",
|
||||
LogsFilePath: getContainerLogsFilePath(podNamespace, podName, "remove-lost-found"),
|
||||
IsInitContainer: true,
|
||||
},
|
||||
{
|
||||
Name: "hello",
|
||||
LogsFilePath: getContainerLogsFilePath(podNamespace, podName, "hello"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "new support bundle format",
|
||||
files: map[string][]byte{
|
||||
getPodsFilePath(podNamespace): []byte(podsFileContentNewFormat),
|
||||
getEventsFilePath(podNamespace): []byte(eventsFileContentNewFormat),
|
||||
getContainerLogsFilePath(podNamespace, podName, "remove-lost-found"): []byte(removeLostAndFoundInitContainerLogs),
|
||||
getContainerLogsFilePath(podNamespace, podName, "hello"): []byte(helloContainerLogs),
|
||||
},
|
||||
expect: &types.PodDetails{
|
||||
PodDefinition: corev1.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
Namespace: podNamespace,
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
InitContainers: []corev1.Container{
|
||||
{
|
||||
Name: "remove-lost-found",
|
||||
},
|
||||
},
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "hello",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
PodEvents: []corev1.Event{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Event",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "hello-27436131-pxhk9.16d85cf27380b4fa",
|
||||
Namespace: podNamespace,
|
||||
},
|
||||
InvolvedObject: corev1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Namespace: podNamespace,
|
||||
Name: podName,
|
||||
},
|
||||
},
|
||||
},
|
||||
PodContainers: []types.PodContainer{
|
||||
{
|
||||
Name: "remove-lost-found",
|
||||
LogsFilePath: getContainerLogsFilePath(podNamespace, podName, "remove-lost-found"),
|
||||
IsInitContainer: true,
|
||||
},
|
||||
{
|
||||
Name: "hello",
|
||||
LogsFilePath: getContainerLogsFilePath(podNamespace, podName, "hello"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
|
||||
actual, err := getPodDetailsFromFiles(test.files, podNamespace, podName)
|
||||
req.NoError(err)
|
||||
|
||||
assert.Equal(t, test.expect, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
analyzer "github.com/replicatedhq/troubleshoot/pkg/analyze"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/convert"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
@@ -26,6 +27,7 @@ type SupportBundleCreateOpts struct {
|
||||
Namespace string
|
||||
ProgressChan chan interface{}
|
||||
SinceTime *time.Time
|
||||
OutputPath string
|
||||
Redact bool
|
||||
FromCLI bool
|
||||
}
|
||||
@@ -57,9 +59,20 @@ func CollectSupportBundleFromSpec(spec *troubleshootv1beta2.SupportBundleSpec, a
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
basename := fmt.Sprintf("support-bundle-%s", time.Now().Format("2006-01-02T15_04_05"))
|
||||
if !opts.FromCLI {
|
||||
basename = filepath.Join(os.TempDir(), basename)
|
||||
basename := ""
|
||||
if opts.OutputPath != "" {
|
||||
// use override output path
|
||||
overridePath, err := convert.ValidateOutputPath(opts.OutputPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "override output file path")
|
||||
}
|
||||
basename = strings.TrimSuffix(overridePath, ".tar.gz")
|
||||
} else {
|
||||
// use default output path
|
||||
basename = fmt.Sprintf("support-bundle-%s", time.Now().Format("2006-01-02T15_04_05"))
|
||||
if !opts.FromCLI {
|
||||
basename = filepath.Join(os.TempDir(), basename)
|
||||
}
|
||||
}
|
||||
|
||||
filename, err := findFileName(basename, "tar.gz")
|
||||
|
||||
@@ -90,13 +90,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"clusterPodStatuses": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"namespaces",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -161,6 +163,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -225,6 +230,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -300,6 +308,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -364,6 +375,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -432,6 +446,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -439,7 +456,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -455,6 +471,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -504,6 +526,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -568,6 +593,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -636,6 +664,9 @@
|
||||
},
|
||||
"registryName": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -708,6 +739,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -715,7 +749,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -731,6 +764,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -780,6 +819,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -851,6 +893,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -922,6 +967,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1026,6 +1074,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1097,6 +1148,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1168,6 +1222,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1236,6 +1293,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1243,7 +1303,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes",
|
||||
"selector"
|
||||
],
|
||||
@@ -1260,6 +1319,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1315,6 +1380,9 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1390,6 +1458,9 @@
|
||||
},
|
||||
"secretName": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1397,7 +1468,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -1413,6 +1483,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1462,6 +1538,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1530,6 +1609,9 @@
|
||||
},
|
||||
"storageClassName": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1594,6 +1676,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1673,6 +1758,9 @@
|
||||
},
|
||||
"regexGroups": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1690,6 +1778,9 @@
|
||||
},
|
||||
"reportFileGlob": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,13 +90,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"clusterPodStatuses": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"namespaces",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -161,6 +163,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -225,6 +230,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -300,6 +308,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -364,6 +375,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -432,6 +446,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -439,7 +456,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -455,6 +471,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -504,6 +526,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -568,6 +593,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -636,6 +664,9 @@
|
||||
},
|
||||
"registryName": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -708,6 +739,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -715,7 +749,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -731,6 +764,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -780,6 +819,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -851,6 +893,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -922,6 +967,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1026,6 +1074,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1097,6 +1148,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1168,6 +1222,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1236,6 +1293,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1243,7 +1303,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes",
|
||||
"selector"
|
||||
],
|
||||
@@ -1260,6 +1319,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1315,6 +1380,9 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1390,6 +1458,9 @@
|
||||
},
|
||||
"secretName": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1397,7 +1468,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -1413,6 +1483,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1462,6 +1538,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1530,6 +1609,9 @@
|
||||
},
|
||||
"storageClassName": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1594,6 +1676,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1673,6 +1758,9 @@
|
||||
},
|
||||
"regexGroups": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1690,6 +1778,9 @@
|
||||
},
|
||||
"reportFileGlob": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,13 +136,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"clusterPodStatuses": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"namespaces",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -207,6 +209,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -271,6 +276,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -346,6 +354,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -410,6 +421,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -478,6 +492,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -485,7 +502,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -501,6 +517,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -550,6 +572,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -614,6 +639,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -682,6 +710,9 @@
|
||||
},
|
||||
"registryName": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -754,6 +785,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -761,7 +795,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -777,6 +810,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -826,6 +865,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -897,6 +939,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -968,6 +1013,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1072,6 +1120,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1143,6 +1194,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1214,6 +1268,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1282,6 +1339,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1289,7 +1349,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes",
|
||||
"selector"
|
||||
],
|
||||
@@ -1306,6 +1365,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1361,6 +1426,9 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1436,6 +1504,9 @@
|
||||
},
|
||||
"secretName": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1443,7 +1514,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"namespace",
|
||||
"outcomes"
|
||||
],
|
||||
"properties": {
|
||||
@@ -1459,6 +1529,12 @@
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcomes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -1508,6 +1584,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1576,6 +1655,9 @@
|
||||
},
|
||||
"storageClassName": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1640,6 +1722,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1719,6 +1804,9 @@
|
||||
},
|
||||
"regexGroups": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1736,6 +1824,9 @@
|
||||
},
|
||||
"reportFileGlob": {
|
||||
"type": "string"
|
||||
},
|
||||
"strict": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user