@@ -10,6 +10,8 @@ import (
10
10
"os"
11
11
"os/signal"
12
12
"path/filepath"
13
+ "reflect"
14
+ "strings"
13
15
"sync"
14
16
"time"
15
17
@@ -31,6 +33,7 @@ import (
31
33
"github.com/replicatedhq/troubleshoot/pkg/types"
32
34
"github.com/spf13/viper"
33
35
spin "github.com/tj/go-spin"
36
+ "gopkg.in/yaml.v3"
34
37
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35
38
"k8s.io/client-go/kubernetes"
36
39
"k8s.io/client-go/rest"
@@ -53,22 +56,20 @@ func runTroubleshoot(v *viper.Viper, args []string) error {
53
56
fmt .Println (specYaml )
54
57
return nil
55
58
} else if len (args ) > 1 && args [0 ] == "lint" {
56
- mainBundle , additionalRedactors , err := validateSpecs (args [1 :], "" )
59
+ supportBundles , err := validateSpecs (args [1 :], "" )
57
60
if err != nil {
58
61
return err
59
62
}
63
+
60
64
k := loader.TroubleshootKinds {
61
- SupportBundlesV1Beta2 : []troubleshootv1beta2.SupportBundle {* mainBundle },
62
- }
63
- // If we have redactors, add them to the temp kinds object
64
- if len (additionalRedactors .Spec .Redactors ) > 0 {
65
- k .RedactorsV1Beta2 = []troubleshootv1beta2.Redactor {* additionalRedactors }
65
+ SupportBundlesV1Beta2 : * supportBundles ,
66
66
}
67
67
68
68
out , err := k .ToYaml ()
69
69
if err != nil {
70
70
return types .NewExitCodeError (constants .EXIT_CODE_CATCH_ALL , errors .Wrap (err , "failed to convert specs to yaml" ))
71
71
}
72
+ fmt .Println ("-----------\n " )
72
73
fmt .Printf ("%s" , out )
73
74
return nil
74
75
}
@@ -312,78 +313,124 @@ func loadSupportBundleSpecsFromURIs(ctx context.Context, kinds *loader.Troublesh
312
313
return nil
313
314
}
314
315
315
- func validateSpecs (args []string , specYaml string ) (* troubleshootv1beta2.SupportBundle , * troubleshootv1beta2. Redactor , error ) {
316
+ func validateSpecs (args []string , specYaml string ) (* [] troubleshootv1beta2.SupportBundle , error ) {
316
317
// Append redactor uris to the args
317
318
allArgs := append (args , viper .GetStringSlice ("redactors" )... )
318
- fmt .Println (allArgs )
319
319
kinds , err := specs .LoadFromCLIArgs (context .TODO (), nil , allArgs , viper .GetViper ())
320
320
if err != nil {
321
- return nil , nil , err
321
+ return nil , err
322
322
}
323
323
324
324
// Check if we have any collectors to run in the troubleshoot specs
325
- // TODO: Do we use the RemoteCollectors anymore?
326
325
if len (kinds .CollectorsV1Beta2 ) == 0 &&
327
326
len (kinds .HostCollectorsV1Beta2 ) == 0 &&
328
327
len (kinds .SupportBundlesV1Beta2 ) == 0 {
329
- return nil , nil , errors .New ("no collectors specified to run" )
328
+ return nil , errors .New ("no collectors specified to run" )
330
329
}
331
330
332
- // Merge specs
333
- // We need to add the default type information to the support bundle spec
334
- // since by default these fields would be empty
335
- mainBundle := & troubleshootv1beta2.SupportBundle {
336
- TypeMeta : metav1.TypeMeta {
337
- APIVersion : "troubleshoot.sh/v1beta2" ,
338
- Kind : "SupportBundle" ,
339
- },
340
- ObjectMeta : metav1.ObjectMeta {
341
- Name : "merged-support-bundle-spec" ,
342
- },
331
+ for _ , arg := range args {
332
+ err := checkSpecStructure (arg )
333
+ if err != nil {
334
+ return nil , err
335
+ }
343
336
}
337
+
344
338
for _ , sb := range kinds .SupportBundlesV1Beta2 {
345
339
sb := sb
346
- mainBundle = supportbundle .ConcatSpec (mainBundle , & sb )
340
+ warning := validateTroubleshootSpecsItems (sb .Spec .Collectors , sb .Spec .Analyzers )
341
+ if warning != nil {
342
+ return nil , errors .New (warning .Warning ())
343
+ }
347
344
}
348
345
349
- for _ , c := range kinds .CollectorsV1Beta2 {
350
- mainBundle .Spec .Collectors = util .Append (mainBundle .Spec .Collectors , c .Spec .Collectors )
351
- }
346
+ // for _, c := range kinds.CollectorsV1Beta2 {
347
+ // mainBundle.Spec.Collectors = util.Append(mainBundle.Spec.Collectors, c.Spec.Collectors)
348
+ // }
352
349
353
- for _ , hc := range kinds .HostCollectorsV1Beta2 {
354
- mainBundle .Spec .HostCollectors = util .Append (mainBundle .Spec .HostCollectors , hc .Spec .Collectors )
355
- }
350
+ // for _, hc := range kinds.HostCollectorsV1Beta2 {
351
+ // mainBundle.Spec.HostCollectors = util.Append(mainBundle.Spec.HostCollectors, hc.Spec.Collectors)
352
+ // }
356
353
357
- if ! (len (mainBundle .Spec .HostCollectors ) > 0 && len (mainBundle .Spec .Collectors ) == 0 ) {
358
- // Always add default collectors unless we only have host collectors
359
- // We need to add them here so when we --dry-run, these collectors
360
- // are included. supportbundle.runCollectors duplicates this bit.
361
- // We'll need to refactor it out later when its clearer what other
362
- // code depends on this logic e.g KOTS
363
- mainBundle .Spec .Collectors = collect .EnsureCollectorInList (
364
- mainBundle .Spec .Collectors ,
365
- troubleshootv1beta2.Collect {ClusterInfo : & troubleshootv1beta2.ClusterInfo {}},
366
- )
367
- mainBundle .Spec .Collectors = collect .EnsureCollectorInList (
368
- mainBundle .Spec .Collectors ,
369
- troubleshootv1beta2.Collect {ClusterResources : & troubleshootv1beta2.ClusterResources {}},
370
- )
354
+ return & kinds .SupportBundlesV1Beta2 , nil
355
+ }
356
+
357
+ func validateTroubleshootSpecsItems (collectors []* troubleshootv1beta2.Collect , analyzers []* troubleshootv1beta2.Analyze ) * types.ExitCodeWarning {
358
+ numberOfCollectors := len (collectors )
359
+ numberOfAnalyzers := len (analyzers )
360
+
361
+ if numberOfCollectors > 0 {
362
+ for _ , c := range collectors {
363
+ if isStructEmpty (c ) {
364
+ return types .NewExitCodeWarning ("Wrong collector found" )
365
+ }
366
+ }
367
+ } else {
368
+ return types .NewExitCodeWarning ("No collectors found" )
371
369
}
372
370
373
- additionalRedactors := & troubleshootv1beta2. Redactor {
374
- TypeMeta : metav1. TypeMeta {
375
- APIVersion : "troubleshoot.sh/v1beta2" ,
376
- Kind : "Redactor" ,
377
- },
378
- ObjectMeta : metav1. ObjectMeta {
379
- Name : "merged-redactors-spec" ,
380
- },
371
+ if numberOfAnalyzers > 0 {
372
+ for _ , a := range analyzers {
373
+ if isStructEmpty ( a ) {
374
+ return types . NewExitCodeWarning ( "Wrong analyzer found" )
375
+ }
376
+ }
377
+ } else {
378
+ return types . NewExitCodeWarning ( "No analyzers found" )
381
379
}
382
- for _ , r := range kinds .RedactorsV1Beta2 {
383
- additionalRedactors .Spec .Redactors = util .Append (additionalRedactors .Spec .Redactors , r .Spec .Redactors )
380
+ return nil
381
+ }
382
+
383
+ func checkSpecStructure (path string ) error {
384
+ if _ , err := os .Stat (path ); err == nil {
385
+ rawSpec , err := os .ReadFile (path )
386
+ if err != nil {
387
+ return types .NewExitCodeError (constants .EXIT_CODE_SPEC_ISSUES , err )
388
+ }
389
+
390
+ decoder := yaml .NewDecoder (strings .NewReader (string (rawSpec )))
391
+ var node yaml.Node
392
+ err = decoder .Decode (& node )
393
+ if err != nil {
394
+ return err
395
+ }
396
+
397
+ for _ , n := range node .Content [0 ].Content { // Traverse the root map
398
+ if n .Kind == yaml .MappingNode && n .Tag == "!!map" {
399
+ for i := 0 ; i < len (n .Content ); i += 2 {
400
+ keyNode := n .Content [i ]
401
+ valNode := n .Content [i + 1 ]
402
+ if keyNode .Value == "analyzers" {
403
+ for _ , specNode := range valNode .Content {
404
+ for j := 0 ; j < len (specNode .Content ); j += 2 {
405
+ analyzerKey := specNode .Content [j ]
406
+ analyzerVal := specNode .Content [j + 1 ]
407
+ if analyzerKey .Value == "distribution" {
408
+ if len (analyzerVal .Content ) == 0 {
409
+ fmt .Println ("distribution is empty" )
410
+ if specNode .Content [j + 2 ] != nil && specNode .Content [j + 2 ].Value == "outcomes" {
411
+ fmt .Println ("outcomes is misaligned in distribution" )
412
+ }
413
+ }
414
+ }
415
+ }
416
+ }
417
+ }
418
+ }
419
+ }
420
+ }
384
421
}
385
422
386
- return mainBundle , additionalRedactors , nil
423
+ return nil
424
+ }
425
+
426
+ func isStructEmpty (s interface {}) bool {
427
+ val := reflect .ValueOf (s ).Elem ()
428
+ for i := 0 ; i < val .NumField (); i ++ {
429
+ if ! val .Field (i ).IsNil () {
430
+ return false
431
+ }
432
+ }
433
+ return true
387
434
}
388
435
389
436
func loadSpecs (ctx context.Context , args []string , client kubernetes.Interface ) (* troubleshootv1beta2.SupportBundle , * troubleshootv1beta2.Redactor , error ) {
0 commit comments