Skip to content

Commit

Permalink
Prints all plugins when invoking sonobuoy results by default (#909)
Browse files Browse the repository at this point in the history
If given a tarball, there is not a way to detect which plugins
were actually run without opening it up first. This means that the
`sonobuoy results` command is less useful since you have to have
preexisting knowledge about the tarball/run. You'd also have to
manually execute the command numerous times if you want all the
summaries of the plugins.

This change:
 -  makes the default value for the `--plugin` flag the
empty string
 - when a string value is given, it will print a single report
like the existing behavior
 - when the default, empty string is used, we will list the report
for each plugin
 - adds a new file, meta/info.json which will contain the list of
plugins that were actually run so that it is easier to grab this
list (rather than more complicated logic using the other data in
the tarball)

Fixes #905

Signed-off-by: John Schnake <[email protected]>
  • Loading branch information
johnSchnake authored Sep 27, 2019
1 parent aae48ef commit d9ca4ba
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 3 deletions.
55 changes: 54 additions & 1 deletion cmd/sonobuoy/app/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"strings"

"github.com/heptio/sonobuoy/pkg/client/results"
"github.com/heptio/sonobuoy/pkg/discovery"
"github.com/heptio/sonobuoy/pkg/errlog"
"github.com/pkg/errors"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -66,7 +67,11 @@ func NewCmdResults() *cobra.Command {
},
Args: cobra.ExactArgs(1),
}
AddPluginFlag(&data.plugin, cmd.Flags())

cmd.Flags().StringVarP(
&data.plugin, "plugin", "p", "",
"Which plugin to show results for. Defaults to printing them all.",
)
cmd.Flags().StringVarP(
&data.mode, "mode", "m", resultModeReport,
`Modifies the format of the output. Valid options are report, detailed, or dump.`,
Expand Down Expand Up @@ -100,13 +105,52 @@ func getReader(filepath string) (*results.Reader, func(), error) {
return r, func() { gzr.Close(); f.Close() }, nil
}

// result takes the resultsInput and tries to print the requested infromation from the archive.
// If there is an error printing any individual plugin, only the last error is printed and all plugins
// continue to be processed.
func result(input resultsInput) error {
r, cleanup, err := getReader(input.archive)
defer cleanup()
if err != nil {
return err
}

// Report on all plugins or the specified one.
plugins := []string{input.plugin}
if len(input.plugin) == 0 {
plugins, err = getPluginList(r)
if err != nil {
return errors.Wrapf(err, "unable to determine plugins to report on")
}
if len(plugins) == 0 {
return fmt.Errorf("no plugins specified by either the --plugin flag or tarball metadata")
}
}

var lastErr error
for i, plugin := range plugins {
input.plugin = plugin

// Load file with a new reader since we can't assume this reader has rewind
// capabilities.
r, cleanup, err := getReader(input.archive)
defer cleanup()

err = printSinglePlugin(input, r)
if err != nil {
lastErr = err
}

// Seperator line, but don't print a needless one at the end.
if i+1 < len(plugins) {
fmt.Println()
}
}

return lastErr
}

func printSinglePlugin(input resultsInput, r *results.Reader) error {
// If we want to dump the whole file, don't decode to an Item object first.
if input.mode == resultModeDump {
fReader, err := r.PluginResultsReader(input.plugin)
Expand Down Expand Up @@ -136,6 +180,15 @@ func result(input resultsInput) error {
}
}

func getPluginList(r *results.Reader) ([]string, error) {
runInfo := discovery.RunInfo{}
err := r.WalkFiles(func(path string, info os.FileInfo, err error) error {
return results.ExtractFileIntoStruct(r.RunInfoFile(), path, info, &runInfo)
})

return runInfo.LoadedPlugins, errors.Wrap(err, "finding plugin list")
}

func getItemInTree(i *results.Item, root string) *results.Item {
if i == nil {
return nil
Expand Down
7 changes: 5 additions & 2 deletions cmd/sonobuoy/app/results_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import (

func ExampleNewCmdResults() {
cmd := NewCmdResults()
cmd.SetArgs([]string{filepath.Join("testdata", "testResultsOutput.tar.gz")})
cmd.SetArgs([]string{
filepath.Join("testdata", "testResultsOutput.tar.gz"),
"--plugin=e2e",
})
cmd.Execute()
// Output:
// Plugin: e2e
Expand All @@ -39,7 +42,7 @@ func ExampleNewCmdResults_detailed() {
cmd := NewCmdResults()
cmd.SetArgs([]string{
filepath.Join("testdata", "testResultsOutput.tar.gz"),
"--mode", "detailed",
"--mode", "detailed", "--plugin=e2e",
})
cmd.Execute()
// Output:
Expand Down
11 changes: 11 additions & 0 deletions pkg/client/results/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ const (
defaultNodesFile = "Nodes.json"
defaultServerVersionFile = "serverversion.json"
defaultServerGroupsFile = "servergroups.json"

// InfoFile contains data not that isn't strictly in another location
// but still relevent to post-processing or understanding the run in some way.
InfoFile = "info.json"
)

// Versions corresponding to Kubernetes minor version values. We used to
Expand Down Expand Up @@ -323,6 +327,13 @@ func ConfigFile(version string) string {
}
}

// RunInfoFile returns the path to the Sonobuoy RunInfo file which is extra metadata about the run.
// This was added in v0.16.1. The function will return the same string even for earlier
// versions where that file does not exist.
func (r *Reader) RunInfoFile() string {
return path.Join(metadataDir, InfoFile)
}

// PluginResultsItem returns the results file from the given plugin if found, error otherwise.
func (r *Reader) PluginResultsItem(plugin string) (*Item, error) {
resultObj := &Item{}
Expand Down
18 changes: 18 additions & 0 deletions pkg/discovery/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ const (
pluginDefinitionFilename = "defintion.json"
)

type RunInfo struct {
LoadedPlugins []string `json:"plugins,omitempty"`
}

// Run is the main entrypoint for discovery.
func Run(restConf *rest.Config, cfg *config.Config) (errCount int) {
// Adjust QPS/Burst so that the queries execute as quickly as possible.
Expand Down Expand Up @@ -130,6 +134,11 @@ func Run(restConf *rest.Config, cfg *config.Config) (errCount int) {
}
}

// runInfo is for dumping additional information to help enable processing of the resulting tarball.
runInfo := RunInfo{
LoadedPlugins: []string{},
}

// 4. Run the plugin aggregator
trackErrorsFor("running plugins")(
pluginaggregation.Run(kubeClient, cfg.LoadedPlugins, cfg.Aggregation, cfg.ProgressUpdatesPort, cfg.Namespace, outpath),
Expand Down Expand Up @@ -207,11 +216,20 @@ func Run(restConf *rest.Config, cfg *config.Config) (errCount int) {

// Saving plugin definitions in their respective folders for easy reference.
for _, p := range cfg.LoadedPlugins {
runInfo.LoadedPlugins = append(runInfo.LoadedPlugins, p.GetName())
trackErrorsFor("saving plugin info")(
dumpPlugin(p, outpath),
)
}

// Dump extra metadata that may be useful to postprocessors or analysis.
blob, err := json.Marshal(runInfo)
trackErrorsFor("marshalling run info")(err)
if err == nil {
err = ioutil.WriteFile(path.Join(metapath, results.InfoFile), blob, 0644)
trackErrorsFor("saving" + results.InfoFile)(err)
}

// 8. tarball up results YYYYMMDDHHMM_sonobuoy_UID.tar.gz
tb := cfg.ResultsDir + "/" + t.Format("200601021504") + "_sonobuoy_" + cfg.UUID + ".tar.gz"
err = tarx.Compress(tb, outpath, &tarx.CompressOptions{Compression: tarx.Gzip})
Expand Down

0 comments on commit d9ca4ba

Please sign in to comment.