diff --git a/cmd/analyze/cli/root.go b/cmd/analyze/cli/root.go index 9754351c8..a685cf8ac 100644 --- a/cmd/analyze/cli/root.go +++ b/cmd/analyze/cli/root.go @@ -4,7 +4,7 @@ import ( "os" "strings" - "github.com/replicatedhq/troubleshoot/cmd/util" + "github.com/replicatedhq/troubleshoot/cmd/internal/util" "github.com/replicatedhq/troubleshoot/pkg/k8sutil" "github.com/replicatedhq/troubleshoot/pkg/logger" "github.com/spf13/cobra" @@ -43,6 +43,8 @@ func RootCmd() *cobra.Command { cobra.OnInitialize(initConfig) + cmd.AddCommand(util.VersionCmd()) + cmd.Flags().String("analyzers", "", "filename or url of the analyzers to use") cmd.Flags().Bool("debug", false, "enable debug logging") diff --git a/cmd/collect/cli/root.go b/cmd/collect/cli/root.go index 7dc064008..dd3b27627 100644 --- a/cmd/collect/cli/root.go +++ b/cmd/collect/cli/root.go @@ -4,7 +4,7 @@ import ( "os" "strings" - "github.com/replicatedhq/troubleshoot/cmd/util" + "github.com/replicatedhq/troubleshoot/cmd/internal/util" "github.com/replicatedhq/troubleshoot/pkg/k8sutil" "github.com/replicatedhq/troubleshoot/pkg/logger" "github.com/spf13/cobra" @@ -43,7 +43,7 @@ func RootCmd() *cobra.Command { cobra.OnInitialize(initConfig) - cmd.AddCommand(VersionCmd()) + cmd.AddCommand(util.VersionCmd()) cmd.Flags().StringSlice("redactors", []string{}, "names of the additional redactors to use") cmd.Flags().Bool("redact", true, "enable/disable default redactions") diff --git a/cmd/collect/cli/version.go b/cmd/collect/cli/version.go deleted file mode 100644 index ec8fc8f4f..000000000 --- a/cmd/collect/cli/version.go +++ /dev/null @@ -1,22 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/replicatedhq/troubleshoot/pkg/version" - "github.com/spf13/cobra" -) - -func VersionCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "version", - Short: "Print the current version and exit", - Long: `Print the current version and exit`, - RunE: func(cmd *cobra.Command, args []string) error { - fmt.Printf("Replicated Collect %s\n", version.Version()) - - return nil - }, - } - return cmd -} diff --git a/cmd/util/profilers.go b/cmd/internal/util/profilers.go similarity index 100% rename from cmd/util/profilers.go rename to cmd/internal/util/profilers.go diff --git a/cmd/troubleshoot/cli/version.go b/cmd/internal/util/version.go similarity index 97% rename from cmd/troubleshoot/cli/version.go rename to cmd/internal/util/version.go index 061d39620..11cbc7e27 100644 --- a/cmd/troubleshoot/cli/version.go +++ b/cmd/internal/util/version.go @@ -1,4 +1,4 @@ -package cli +package util import ( "fmt" diff --git a/cmd/preflight/cli/root.go b/cmd/preflight/cli/root.go index 225784b1f..10070b1c1 100644 --- a/cmd/preflight/cli/root.go +++ b/cmd/preflight/cli/root.go @@ -6,7 +6,7 @@ import ( "os" "strings" - "github.com/replicatedhq/troubleshoot/cmd/util" + "github.com/replicatedhq/troubleshoot/cmd/internal/util" "github.com/replicatedhq/troubleshoot/internal/traces" "github.com/replicatedhq/troubleshoot/pkg/constants" "github.com/replicatedhq/troubleshoot/pkg/k8sutil" @@ -64,10 +64,14 @@ that a cluster meets the requirements to run an application.`, cobra.OnInitialize(initConfig) - cmd.AddCommand(VersionCmd()) + cmd.AddCommand(util.VersionCmd()) cmd.AddCommand(OciFetchCmd()) preflight.AddFlags(cmd.PersistentFlags()) + // Dry run flag should be in cmd.PersistentFlags() flags made available to all subcommands + // Adding here to avoid that + cmd.Flags().Bool("dry-run", false, "print the preflight spec without running preflight checks") + k8sutil.AddFlags(cmd.Flags()) // Initialize klog flags diff --git a/cmd/preflight/cli/version.go b/cmd/preflight/cli/version.go deleted file mode 100644 index 3793847ae..000000000 --- a/cmd/preflight/cli/version.go +++ /dev/null @@ -1,23 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/replicatedhq/troubleshoot/pkg/version" -) - -func VersionCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "version", - Short: "Print the current version and exit", - Long: `Print the current version and exit`, - RunE: func(cmd *cobra.Command, args []string) error { - fmt.Printf("Replicated Preflight %s\n", version.Version()) - - return nil - }, - } - return cmd -} diff --git a/cmd/troubleshoot/cli/root.go b/cmd/troubleshoot/cli/root.go index 6c670fcd1..a54c928ec 100644 --- a/cmd/troubleshoot/cli/root.go +++ b/cmd/troubleshoot/cli/root.go @@ -5,7 +5,7 @@ import ( "os" "strings" - "github.com/replicatedhq/troubleshoot/cmd/util" + "github.com/replicatedhq/troubleshoot/cmd/internal/util" "github.com/replicatedhq/troubleshoot/internal/traces" "github.com/replicatedhq/troubleshoot/pkg/k8sutil" "github.com/replicatedhq/troubleshoot/pkg/logger" @@ -62,7 +62,7 @@ from a server that can be used to assist when troubleshooting a Kubernetes clust cmd.AddCommand(Analyze()) cmd.AddCommand(Redact()) - cmd.AddCommand(VersionCmd()) + cmd.AddCommand(util.VersionCmd()) cmd.Flags().StringSlice("redactors", []string{}, "names of the additional redactors to use") cmd.Flags().Bool("redact", true, "enable/disable default redactions") diff --git a/docs/preflight.md b/docs/preflight.md index 6cb24eaa8..02dc7b4d5 100644 --- a/docs/preflight.md +++ b/docs/preflight.md @@ -29,6 +29,7 @@ preflight [url] [flags] --cpuprofile string File path to write cpu profiling data --debug enable debug logging --disable-compression If true, opt-out of response compression for all requests to the server + --dry-run print the preflight spec without running preflight checks --format string output format, one of human, json, yaml. only used when interactive is set to false (default "human") -h, --help help for preflight --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure @@ -53,4 +54,4 @@ preflight [url] [flags] * [preflight oci-fetch](preflight_oci-fetch.md) - Fetch a preflight from an OCI registry and print it to standard out * [preflight version](preflight_version.md) - Print the current version and exit -###### Auto generated by spf13/cobra on 8-Jun-2023 +###### Auto generated by spf13/cobra on 31-Aug-2023 diff --git a/docs/preflight_oci-fetch.md b/docs/preflight_oci-fetch.md index d13bc3bda..37bfb0e40 100644 --- a/docs/preflight_oci-fetch.md +++ b/docs/preflight_oci-fetch.md @@ -33,4 +33,4 @@ preflight oci-fetch [URI] [flags] * [preflight](preflight.md) - Run and retrieve preflight checks in a cluster -###### Auto generated by spf13/cobra on 8-Jun-2023 +###### Auto generated by spf13/cobra on 31-Aug-2023 diff --git a/docs/preflight_version.md b/docs/preflight_version.md index 99cd36973..dab67a424 100644 --- a/docs/preflight_version.md +++ b/docs/preflight_version.md @@ -37,4 +37,4 @@ preflight version [flags] * [preflight](preflight.md) - Run and retrieve preflight checks in a cluster -###### Auto generated by spf13/cobra on 3-Jan-2023 +###### Auto generated by spf13/cobra on 31-Aug-2023 diff --git a/docs/support-bundle.md b/docs/support-bundle.md index c7f53bb39..c6def4288 100644 --- a/docs/support-bundle.md +++ b/docs/support-bundle.md @@ -55,4 +55,4 @@ support-bundle [urls...] [flags] * [support-bundle redact](support-bundle_redact.md) - Redact information from a generated support bundle archive * [support-bundle version](support-bundle_version.md) - Print the current version and exit -###### Auto generated by spf13/cobra on 8-Jun-2023 +###### Auto generated by spf13/cobra on 31-Aug-2023 diff --git a/docs/support-bundle_analyze.md b/docs/support-bundle_analyze.md index 879a32537..c6a21132f 100644 --- a/docs/support-bundle_analyze.md +++ b/docs/support-bundle_analyze.md @@ -30,4 +30,4 @@ support-bundle analyze [url] [flags] * [support-bundle](support-bundle.md) - Generate a support bundle -###### Auto generated by spf13/cobra on 3-Jan-2023 +###### Auto generated by spf13/cobra on 31-Aug-2023 diff --git a/docs/support-bundle_redact.md b/docs/support-bundle_redact.md index bfd5f90da..19e552b8d 100644 --- a/docs/support-bundle_redact.md +++ b/docs/support-bundle_redact.md @@ -39,4 +39,4 @@ support-bundle redact [urls...] [flags] * [support-bundle](support-bundle.md) - Generate a support bundle -###### Auto generated by spf13/cobra on 3-Jan-2023 +###### Auto generated by spf13/cobra on 31-Aug-2023 diff --git a/docs/support-bundle_version.md b/docs/support-bundle_version.md index dbec102bc..148778d6b 100644 --- a/docs/support-bundle_version.md +++ b/docs/support-bundle_version.md @@ -27,4 +27,4 @@ support-bundle version [flags] * [support-bundle](support-bundle.md) - Generate a support bundle -###### Auto generated by spf13/cobra on 3-Jan-2023 +###### Auto generated by spf13/cobra on 31-Aug-2023 diff --git a/go.mod b/go.mod index 71cadde72..812786272 100644 --- a/go.mod +++ b/go.mod @@ -245,7 +245,7 @@ require ( sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.3.0 ) replace ( diff --git a/internal/testutils/utils.go b/internal/testutils/utils.go index c2692d5ea..e743935dd 100644 --- a/internal/testutils/utils.go +++ b/internal/testutils/utils.go @@ -15,7 +15,10 @@ import ( func GetTestFixture(t *testing.T, path string) string { t.Helper() - p := filepath.Join("../../testdata", path) + p := path + if !filepath.IsAbs(path) { + p = filepath.Join("../../testdata", path) + } b, err := os.ReadFile(p) require.NoError(t, err) return string(b) diff --git a/pkg/loader/loader.go b/pkg/loader/loader.go index 7f7e6b195..0244dc319 100644 --- a/pkg/loader/loader.go +++ b/pkg/loader/loader.go @@ -2,6 +2,8 @@ package loader import ( "context" + "reflect" + "strings" "github.com/pkg/errors" "github.com/replicatedhq/troubleshoot/internal/util" @@ -10,10 +12,10 @@ import ( "github.com/replicatedhq/troubleshoot/pkg/constants" "github.com/replicatedhq/troubleshoot/pkg/docrewrite" "github.com/replicatedhq/troubleshoot/pkg/types" - "gopkg.in/yaml.v2" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/klog/v2" + "sigs.k8s.io/yaml" ) var decoder runtime.Decoder @@ -97,6 +99,33 @@ func (kinds *TroubleshootKinds) Add(other *TroubleshootKinds) { kinds.SupportBundlesV1Beta2 = append(kinds.SupportBundlesV1Beta2, other.SupportBundlesV1Beta2...) } +// ToYaml returns a yaml document/multi-doc of all the parsed specs +// This function utilises reflection to iterate over all the fields +// of the TroubleshootKinds object then marshals them to yaml. +func (kinds *TroubleshootKinds) ToYaml() (string, error) { + rawList := []string{} + obj := reflect.ValueOf(*kinds) + + for i := 0; i < obj.NumField(); i++ { + field := obj.Field(i) + if field.Kind() != reflect.Slice { + continue + } + + // skip empty slices to avoid empty yaml documents + for count := 0; count < field.Len(); count++ { + val := field.Index(count) + yamlOut, err := yaml.Marshal(val.Interface()) + if err != nil { + return "", err + } + rawList = append(rawList, string(yamlOut)) + } + } + + return strings.Join(rawList, "---\n"), nil +} + func NewTroubleshootKinds() *TroubleshootKinds { return &TroubleshootKinds{} } diff --git a/pkg/loader/loader_test.go b/pkg/loader/loader_test.go index 3d013b934..5ae629377 100644 --- a/pkg/loader/loader_test.go +++ b/pkg/loader/loader_test.go @@ -522,3 +522,60 @@ func TestAddingKinds(t *testing.T) { } assert.Equal(t, k2, k1) } + +func TestToYaml(t *testing.T) { + k := &TroubleshootKinds{ + AnalyzersV1Beta2: []troubleshootv1beta2.Analyzer{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Analyzer", + APIVersion: "troubleshoot.sh/v1beta2", + }, + Spec: troubleshootv1beta2.AnalyzerSpec{ + Analyzers: []*troubleshootv1beta2.Analyze{ + { + ClusterVersion: &troubleshootv1beta2.ClusterVersion{ + Outcomes: []*troubleshootv1beta2.Outcome{ + { + Pass: &troubleshootv1beta2.SingleOutcome{ + Message: "Cluster is up to date", + }, + }, + }, + }, + }, + }, + }, + }, + }, + SupportBundlesV1Beta2: []troubleshootv1beta2.SupportBundle{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "SupportBundle", + APIVersion: "troubleshoot.sh/v1beta2", + }, + Spec: troubleshootv1beta2.SupportBundleSpec{ + Collectors: []*troubleshootv1beta2.Collect{ + { + ClusterResources: &troubleshootv1beta2.ClusterResources{ + IgnoreRBAC: true, + }, + }, + }, + }, + }, + }, + } + + y, err := k.ToYaml() + require.NoError(t, err) + assert.Contains(t, string(y), `apiVersion: troubleshoot.sh/v1beta2 +kind: SupportBundle +metadata: + creationTimestamp: null +spec: + collectors: + - clusterResources: + ignoreRBAC: true`) + assert.Contains(t, string(y), "message: Cluster is up to date") +} diff --git a/pkg/preflight/flags.go b/pkg/preflight/flags.go index f5c85187a..1ea4e7a65 100644 --- a/pkg/preflight/flags.go +++ b/pkg/preflight/flags.go @@ -16,6 +16,7 @@ const ( flagSince = "since" flagOutput = "output" flagDebug = "debug" + flagDryRun = "dry-run" ) type PreflightFlags struct { diff --git a/pkg/preflight/read_specs.go b/pkg/preflight/read_specs.go index c0a1f47ca..2a1f66b17 100644 --- a/pkg/preflight/read_specs.go +++ b/pkg/preflight/read_specs.go @@ -7,46 +7,55 @@ import ( "github.com/replicatedhq/troubleshoot/internal/specs" troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" "github.com/replicatedhq/troubleshoot/pkg/k8sutil" + "github.com/replicatedhq/troubleshoot/pkg/loader" "github.com/spf13/viper" "k8s.io/client-go/kubernetes" ) -type PreflightSpecs struct { - PreflightSpec *troubleshootv1beta2.Preflight - HostPreflightSpec *troubleshootv1beta2.HostPreflight - UploadResultSpecs []*troubleshootv1beta2.Preflight -} - -func (p *PreflightSpecs) Read(args []string) error { +func readSpecs(args []string) (*loader.TroubleshootKinds, error) { config, err := k8sutil.GetRESTConfig() if err != nil { - return errors.Wrap(err, "failed to convert kube flags to rest config") + return nil, errors.Wrap(err, "failed to convert kube flags to rest config") } client, err := kubernetes.NewForConfig(config) if err != nil { - return errors.Wrap(err, "failed to convert create k8s client") + return nil, errors.Wrap(err, "failed to convert create k8s client") } ctx := context.Background() kinds, err := specs.LoadFromCLIArgs(ctx, client, args, viper.GetViper()) if err != nil { - return err + return nil, err } + ret := loader.NewTroubleshootKinds() + + // Concatenate all preflight inclusterSpecs that don't have an upload destination + inclusterSpecs := []troubleshootv1beta2.Preflight{} + var concatenatedSpec *troubleshootv1beta2.Preflight for _, v := range kinds.PreflightsV1Beta2 { v := v // https://golang.org/doc/faq#closures_and_goroutines if v.Spec.UploadResultsTo == "" { - p.PreflightSpec = ConcatPreflightSpec(p.PreflightSpec, &v) + concatenatedSpec = ConcatPreflightSpec(concatenatedSpec, &v) } else { - p.UploadResultSpecs = append(p.UploadResultSpecs, &v) + inclusterSpecs = append(inclusterSpecs, v) } } + if concatenatedSpec != nil { + inclusterSpecs = append(inclusterSpecs, *concatenatedSpec) + } + ret.PreflightsV1Beta2 = inclusterSpecs + + var hostSpec *troubleshootv1beta2.HostPreflight for _, v := range kinds.HostPreflightsV1Beta2 { v := v // https://golang.org/doc/faq#closures_and_goroutines - p.HostPreflightSpec = ConcatHostPreflightSpec(p.HostPreflightSpec, &v) + hostSpec = ConcatHostPreflightSpec(hostSpec, &v) + } + if hostSpec != nil { + ret.HostPreflightsV1Beta2 = []troubleshootv1beta2.HostPreflight{*hostSpec} } - return nil + return ret, nil } diff --git a/pkg/preflight/read_specs_test.go b/pkg/preflight/read_specs_test.go index c98420b64..69b03d59a 100644 --- a/pkg/preflight/read_specs_test.go +++ b/pkg/preflight/read_specs_test.go @@ -1,13 +1,13 @@ package preflight import ( - "log" "os" "path/filepath" "testing" "github.com/replicatedhq/troubleshoot/internal/testutils" troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" + "github.com/replicatedhq/troubleshoot/pkg/loader" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -26,7 +26,7 @@ type PreflightSpecsReadTest struct { // TODOLATER: tests around this wantHostPreflightSpec *troubleshootv1beta2.HostPreflight // TODOLATER: tests around this - wantUploadResultSpecs []*troubleshootv1beta2.Preflight + wantUploadResultSpecs []troubleshootv1beta2.Preflight } // TODO: Simplify tests and rely on the loader tests @@ -273,6 +273,32 @@ func TestPreflightSpecsRead(t *testing.T) { wantHostPreflightSpec: nil, wantUploadResultSpecs: nil, }, + PreflightSpecsReadTest{ + name: "stdin-secret and support-bundle secret", + args: []string{ + "-", + filepath.Join(testutils.FileDir(), "../../testdata/supportbundle/labelled-specs/sb-spec-1.yaml"), + }, + customStdin: true, + stdinDataFile: preflightSecretFile, + wantErr: false, + wantPreflightSpec: &expectSecretPreflightSpec, + wantHostPreflightSpec: nil, + wantUploadResultSpecs: nil, + }, + PreflightSpecsReadTest{ + name: "stdin-secret and redact secret", + args: []string{ + "-", + filepath.Join(testutils.FileDir(), "../../testdata/supportbundle/labelled-specs/redact-spec-1.yaml"), + }, + customStdin: true, + stdinDataFile: preflightSecretFile, + wantErr: false, + wantPreflightSpec: &expectSecretPreflightSpec, + wantHostPreflightSpec: nil, + wantUploadResultSpecs: nil, + }, /* /* TODOLATER: needs a cluster with a spec installed? PreflightSpecsReadTest{ @@ -290,23 +316,48 @@ func TestPreflightSpecsRead(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt := tt // pin - specs := PreflightSpecs{} - tErr := singleTestPreflightSpecsRead(t, &tt, &specs) + specs, tErr := singleTestPreflightSpecsRead(t, &tt) + require.Equal(t, tt.wantErr, tErr != nil) - if tt.wantErr { - assert.Error(t, tErr) - } else { - require.NoError(t, tErr) + if tt.wantPreflightSpec != nil { + assert.Truef(t, + contains(specs.PreflightsV1Beta2, *tt.wantPreflightSpec), + "expected %v to contain %v", specs.PreflightsV1Beta2, *tt.wantPreflightSpec, + ) + } + for _, wantUploadResultSpec := range tt.wantUploadResultSpecs { + assert.Truef(t, + contains(specs.PreflightsV1Beta2, wantUploadResultSpec), + "expected %v to contain %v", specs.PreflightsV1Beta2, wantUploadResultSpec, + ) + } + if tt.wantHostPreflightSpec != nil { + assert.Truef(t, + contains(specs.HostPreflightsV1Beta2, *tt.wantHostPreflightSpec), + "expected %v to contain %v", testutils.AsJSON(t, specs.HostPreflightsV1Beta2), testutils.AsJSON(t, specs.HostPreflightsV1Beta2), + ) } - assert.Equal(t, specs.PreflightSpec, tt.wantPreflightSpec) - assert.Equal(t, specs.HostPreflightSpec, tt.wantHostPreflightSpec) - assert.Equal(t, specs.UploadResultSpecs, tt.wantUploadResultSpecs) + assert.Len(t, specs.SupportBundlesV1Beta2, 0) + assert.Len(t, specs.RedactorsV1Beta2, 0) + assert.Len(t, specs.AnalyzersV1Beta2, 0) + assert.Len(t, specs.CollectorsV1Beta2, 0) + assert.Len(t, specs.RemoteCollectorsV1Beta2, 0) + assert.Len(t, specs.HostCollectorsV1Beta2, 0) }) } } +func contains[T any](list []T, obj T) bool { + for _, item := range list { + if assert.ObjectsAreEqual(item, obj) { + return true + } + } + return false +} + func concatSpecs(target troubleshootv1beta2.Preflight, source troubleshootv1beta2.Preflight) *troubleshootv1beta2.Preflight { newSpec := target.DeepCopy() newSpec.Spec.Collectors = append(newSpec.Spec.Collectors, source.Spec.Collectors...) @@ -317,7 +368,7 @@ func concatSpecs(target troubleshootv1beta2.Preflight, source troubleshootv1beta } // Structured as a separate function so we can use defer appropriately -func singleTestPreflightSpecsRead(t *testing.T, tt *PreflightSpecsReadTest, specs *PreflightSpecs) error { +func singleTestPreflightSpecsRead(t *testing.T, tt *PreflightSpecsReadTest) (*loader.TroubleshootKinds, error) { var tmpfile *os.File var err error if tt.customStdin == true { @@ -349,13 +400,13 @@ func singleTestPreflightSpecsRead(t *testing.T, tt *PreflightSpecsReadTest, spec os.Stdin = tmpfile } - err = specs.Read(tt.args) + kinds, err := readSpecs(tt.args) if tt.customStdin == true { if err = tmpfile.Close(); err != nil { - log.Fatal(err) + t.Fatal(err) } } - return err + return kinds, err } diff --git a/pkg/preflight/run.go b/pkg/preflight/run.go index 60eb846d9..29a394351 100644 --- a/pkg/preflight/run.go +++ b/pkg/preflight/run.go @@ -41,19 +41,26 @@ func RunPreflights(interactive bool, output string, format string, args []string os.Exit(1) }() - specs := PreflightSpecs{} - err := specs.Read(args) + specs, err := readSpecs(args) if err != nil { - return err + return types.NewExitCodeError(constants.EXIT_CODE_SPEC_ISSUES, err) } warning := validatePreflight(specs) - if warning != nil { fmt.Println(warning.Warning()) return nil } + if viper.GetBool("dry-run") { + out, err := specs.ToYaml() + if err != nil { + return types.NewExitCodeError(constants.EXIT_CODE_CATCH_ALL, errors.Wrap(err, "failed to convert specs to yaml")) + } + fmt.Printf("%s", out) + return nil + } + var collectResults []CollectResult var uploadCollectResults []CollectResult preflightSpecName := "" @@ -74,41 +81,37 @@ func RunPreflights(interactive bool, output string, format string, args []string uploadResultsMap := make(map[string][]CollectResult) - if specs.PreflightSpec != nil { - r, err := collectInCluster(ctx, specs.PreflightSpec, progressCh) + for _, spec := range specs.PreflightsV1Beta2 { + r, err := collectInCluster(ctx, &spec, progressCh) if err != nil { return types.NewExitCodeError(constants.EXIT_CODE_CATCH_ALL, errors.Wrap(err, "failed to collect in cluster")) } - collectResults = append(collectResults, *r) - preflightSpecName = specs.PreflightSpec.Name - } - if specs.UploadResultSpecs != nil { - for _, spec := range specs.UploadResultSpecs { - r, err := collectInCluster(ctx, spec, progressCh) - if err != nil { - return types.NewExitCodeError(constants.EXIT_CODE_CATCH_ALL, errors.Wrap(err, "failed to collect in cluster")) - } + if spec.Spec.UploadResultsTo != "" { uploadResultsMap[spec.Spec.UploadResultsTo] = append(uploadResultsMap[spec.Spec.UploadResultsTo], *r) uploadCollectResults = append(collectResults, *r) - preflightSpecName = spec.Name + } else { + collectResults = append(collectResults, *r) } + // TODO: This spec name will be overwritten by the next spec. Is this intentional? + preflightSpecName = spec.Name } - if specs.HostPreflightSpec != nil { - if len(specs.HostPreflightSpec.Spec.Collectors) > 0 { - r, err := collectHost(ctx, specs.HostPreflightSpec, progressCh) + + for _, spec := range specs.HostPreflightsV1Beta2 { + if len(spec.Spec.Collectors) > 0 { + r, err := collectHost(ctx, &spec, progressCh) if err != nil { return types.NewExitCodeError(constants.EXIT_CODE_CATCH_ALL, errors.Wrap(err, "failed to collect from host")) } collectResults = append(collectResults, *r) } - if len(specs.HostPreflightSpec.Spec.RemoteCollectors) > 0 { - r, err := collectRemote(ctx, specs.HostPreflightSpec, progressCh) + if len(spec.Spec.RemoteCollectors) > 0 { + r, err := collectRemote(ctx, &spec, progressCh) if err != nil { return types.NewExitCodeError(constants.EXIT_CODE_CATCH_ALL, errors.Wrap(err, "failed to collect remotely")) } collectResults = append(collectResults, *r) } - preflightSpecName = specs.HostPreflightSpec.Name + preflightSpecName = spec.Name } if collectResults == nil && uploadCollectResults == nil { diff --git a/pkg/preflight/validate_specs.go b/pkg/preflight/validate_specs.go index e459479cd..fd33b1b29 100644 --- a/pkg/preflight/validate_specs.go +++ b/pkg/preflight/validate_specs.go @@ -4,45 +4,37 @@ import ( "reflect" "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" + "github.com/replicatedhq/troubleshoot/pkg/loader" "github.com/replicatedhq/troubleshoot/pkg/multitype" "github.com/replicatedhq/troubleshoot/pkg/types" ) // validatePreflight validates the preflight spec and returns a warning if there is any -func validatePreflight(specs PreflightSpecs) *types.ExitCodeWarning { +func validatePreflight(kinds *loader.TroubleshootKinds) *types.ExitCodeWarning { - if specs.PreflightSpec == nil && specs.HostPreflightSpec == nil && specs.UploadResultSpecs == nil { + if len(kinds.PreflightsV1Beta2) == 0 && len(kinds.HostPreflightsV1Beta2) == 0 { return types.NewExitCodeWarning("no preflight or host preflight spec was found") } - if specs.PreflightSpec != nil { - warning := validatePreflightSpecItems(specs.PreflightSpec.Spec.Collectors, specs.PreflightSpec.Spec.Analyzers) + for _, spec := range kinds.PreflightsV1Beta2 { + warning := validatePreflightSpecItems(spec.Spec.Collectors, spec.Spec.Analyzers) if warning != nil { return warning } } - if specs.HostPreflightSpec != nil { - warning := validateHostPreflightSpecItems(specs.HostPreflightSpec.Spec.Collectors, specs.HostPreflightSpec.Spec.Analyzers) + for _, spec := range kinds.HostPreflightsV1Beta2 { + warning := validateHostPreflightSpecItems(spec.Spec.Collectors, spec.Spec.Analyzers) if warning != nil { return warning } } - if specs.UploadResultSpecs != nil { - for _, preflight := range specs.UploadResultSpecs { - warning := validatePreflightSpecItems(preflight.Spec.Collectors, preflight.Spec.Analyzers) - if warning != nil { - return warning - } - } - } - return nil } -// validatePreflightSpecItems validates the preflight spec items and returns a warning if there is any -// clusterResources and clusterInfo collectors are added automatically to the preflight spec, cannot be excluded +// validatePreflightSpecItems validates the preflight spec items and returns a warning if there are any +// clusterResources or clusterInfo collectors added automatically to the preflight spec. It cannot be excluded func validatePreflightSpecItems(collectors []*v1beta2.Collect, analyzers []*v1beta2.Analyze) *types.ExitCodeWarning { var numberOfExcludedCollectors, numberOfExcludedAnalyzers int var numberOfExcludedDefaultCollectors int diff --git a/pkg/preflight/validate_specs_test.go b/pkg/preflight/validate_specs_test.go index 3ffa93794..fb819ddea 100644 --- a/pkg/preflight/validate_specs_test.go +++ b/pkg/preflight/validate_specs_test.go @@ -5,8 +5,10 @@ import ( "testing" "github.com/replicatedhq/troubleshoot/internal/testutils" + "github.com/replicatedhq/troubleshoot/pkg/loader" "github.com/replicatedhq/troubleshoot/pkg/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestValidatePreflight(t *testing.T) { @@ -93,10 +95,14 @@ func TestValidatePreflight(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - testFilePath := filepath.Join(testutils.FileDir(), "../../testdata/preflightspec/"+tt.preflightSpec) - specs := PreflightSpecs{} - specs.Read([]string{testFilePath}) - gotWarning := validatePreflight(specs) + kinds := loader.NewTroubleshootKinds() + if tt.preflightSpec != "" { + testFilePath := filepath.Join(testutils.FileDir(), "../../testdata/preflightspec/"+tt.preflightSpec) + var err error + kinds, err = readSpecs([]string{testFilePath}) + require.NoError(t, err) + } + gotWarning := validatePreflight(kinds) assert.Equal(t, tt.wantWarning, gotWarning) }) }