github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/scripts/juju-inspect/main.go (about)

     1  // Copyright 2021 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package main
     5  
     6  import (
     7  	"bufio"
     8  	"bytes"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"log"
    13  	"os"
    14  	"path/filepath"
    15  
    16  	"github.com/juju/version/v2"
    17  	"gopkg.in/yaml.v2"
    18  
    19  	"github.com/juju/juju/scripts/juju-inspect/rules"
    20  )
    21  
    22  func main() {
    23  	var includeNested bool
    24  	var startCountAmount int
    25  	flag.BoolVar(&includeNested, "include-nested", false, "inlcude nested agents")
    26  	flag.IntVar(&startCountAmount, "start-count-amount", 3, "number of start counts to show")
    27  	flag.Parse()
    28  
    29  	files := flag.Args()
    30  	if len(files) == 0 {
    31  		log.Fatal("expected at least on file")
    32  	}
    33  	allRules := []Rule{
    34  		rules.NewRaftRule(),
    35  		rules.NewMongoRule(),
    36  		rules.NewPubsubRule(),
    37  		rules.NewManifoldsRule(includeNested),
    38  		rules.NewStartCountRule(includeNested, startCountAmount),
    39  	}
    40  
    41  	if len(files) == 1 {
    42  		matches, err := filepath.Glob(files[0])
    43  		if err == nil && len(matches) > 0 {
    44  			files = matches
    45  		}
    46  	}
    47  
    48  	for _, file := range files {
    49  		f, err := os.Open(file)
    50  		if err != nil {
    51  			log.Fatal(err)
    52  		}
    53  
    54  		// Engine reports aren't actually valid yaml files. Instead they have a
    55  		// header that isn't a comment! This code exists to skip that line.
    56  		row1, _, err := bufio.NewReader(f).ReadLine()
    57  		if err != nil {
    58  			log.Fatal(err)
    59  		}
    60  
    61  		_, err = f.Seek(int64(len(row1)), io.SeekStart)
    62  		if err != nil {
    63  			log.Fatal(err)
    64  		}
    65  
    66  		var report rules.Report
    67  		if err := yaml.NewDecoder(f).Decode(&report); err != nil {
    68  			log.Fatal(err)
    69  		}
    70  
    71  		agent := report.Manifolds["agent"]
    72  
    73  		var out AgentReport
    74  		if err := agent.UnmarshalReport(&out); err != nil {
    75  			log.Fatal(err)
    76  		}
    77  		for _, rule := range allRules {
    78  			if err := rule.Run(out.Agent, report); err != nil {
    79  				fmt.Printf("Skipping %T, because of error: %v", rule, err)
    80  			}
    81  		}
    82  	}
    83  
    84  	fmt.Println("")
    85  	fmt.Println("Analysis of Engine Report:")
    86  	fmt.Println("")
    87  
    88  	buf := new(bytes.Buffer)
    89  	for _, rule := range allRules {
    90  		rule.Write(buf)
    91  	}
    92  	fmt.Println(buf)
    93  }
    94  
    95  type Rule interface {
    96  	Run(string, rules.Report) error
    97  	Write(io.Writer)
    98  }
    99  
   100  type AgentReport struct {
   101  	Agent   string         `yaml:"agent"`
   102  	Version version.Number `yaml:"version"`
   103  }