mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-02-14 10:19:54 +00:00
feat: Dry run flag to print preflight specs to std out (#1240)
This commit is contained in:
@@ -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")
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package cli
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
2
go.mod
2
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 (
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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{}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ const (
|
||||
flagSince = "since"
|
||||
flagOutput = "output"
|
||||
flagDebug = "debug"
|
||||
flagDryRun = "dry-run"
|
||||
)
|
||||
|
||||
type PreflightFlags struct {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user