Skip to content

Commit

Permalink
tetra: fix getevents --output flag
Browse files Browse the repository at this point in the history
When using same local flag for different subcommands, binding to the
global configuration will erase previous values with the value of the
last command's flag registered. See spf13/viper#233.

Using a global set of variables to store the flags value of the
command solves the issue. Also add a local variable to store the value
of the output flag of the tracingpolicy list subcommand.

We may want to avoid the usage of the global configuration and using
viper.BindPFlags in the future to avoid this issue to appear again.

Also add checks on the value of flags that are restricted to certain
values.

Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
  • Loading branch information
mtardy committed Jun 21, 2023
1 parent dbf8f0c commit da795ea
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 34 deletions.
57 changes: 33 additions & 24 deletions cmd/tetra/getevents/getevents.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ redirection of events to the stdin. Examples:
# Include only process and parent.pod fields
%[1]s getevents -f process,parent.pod`

var (
output string
color string
includeFields []string
excludeFields []string
namespaces []string
processes []string
pods []string
host bool
timestamps bool
ttyEncode string
)

// GetEncoder returns an encoder for an event stream based on configuration options.
var GetEncoder = func(w io.Writer, colorMode encoder.ColorMode, timestamps bool, compact bool, tty string) encoder.EventEncoder {
if tty != "" {
Expand All @@ -51,11 +64,6 @@ var GetEncoder = func(w io.Writer, colorMode encoder.ColorMode, timestamps bool,

// GetFilter returns a filter for an event stream based on configuration options.
var GetFilter = func() *tetragon.Filter {
host := viper.GetBool("host")
namespaces := viper.GetStringSlice("namespace")
processes := viper.GetStringSlice("process")
pods := viper.GetStringSlice("pod")

if host {
// Host events can be matched by an empty namespace string.
namespaces = append(namespaces, "")
Expand Down Expand Up @@ -106,19 +114,12 @@ func getRequest(includeFields, excludeFields []string, filter *tetragon.Filter)
}

func getEvents(ctx context.Context, client tetragon.FineGuidanceSensorsClient) {
timestamps := viper.GetBool("timestamps")
compact := viper.GetString(common.KeyOutput) == "compact"
colorMode := encoder.ColorMode(viper.GetString(common.KeyColor))
includeFields := viper.GetStringSlice("include-fields")
excludeFields := viper.GetStringSlice("exclude-fields")
tty := viper.GetString(common.KeyTty)

request := getRequest(includeFields, excludeFields, GetFilter())
stream, err := client.GetEvents(ctx, request)
if err != nil {
logger.GetLogger().WithError(err).Fatal("Failed to call GetEvents")
}
eventEncoder := GetEncoder(os.Stdout, colorMode, timestamps, compact, tty)
eventEncoder := GetEncoder(os.Stdout, encoder.ColorMode(color), timestamps, output == "compact", ttyEncode)
for {
res, err := stream.Recv()
if err != nil {
Expand All @@ -138,6 +139,15 @@ func New() *cobra.Command {
Use: "getevents",
Short: "Print events",
Long: fmt.Sprintf(DocLong, "tetra"),
PreRunE: func(cmd *cobra.Command, args []string) error {
if output != "json" && output != "compact" {
return fmt.Errorf("invalid value for %q flag: %s", common.KeyOutput, output)
}
if color != "auto" && color != "always" && color != "never" {
return fmt.Errorf("invalid value for %q flag: %s", "color", color)
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
fi, _ := os.Stdin.Stat()
if fi.Mode()&os.ModeNamedPipe != 0 {
Expand All @@ -151,16 +161,15 @@ func New() *cobra.Command {
}

flags := cmd.Flags()
flags.StringP(common.KeyOutput, "o", "json", "Output format. json or compact")
flags.String("color", "auto", "Colorize compact output. auto, always, or never")
flags.StringSliceP("include-fields", "f", nil, "Include only fields in events")
flags.StringSliceP("exclude-fields", "F", nil, "Exclude fields from events")
flags.StringSliceP("namespace", "n", nil, "Get events by Kubernetes namespaces")
flags.StringSlice("process", nil, "Get events by process name regex")
flags.StringSlice("pod", nil, "Get events by pod name regex")
flags.Bool("host", false, "Get host events")
flags.Bool("timestamps", false, "Include timestamps in compact output")
flags.StringP("tty-encode", "t", "", "Encode terminal data by file path (all other events will be ignored)")
viper.BindPFlags(flags)
flags.StringVarP(&output, common.KeyOutput, "o", "json", "Output format. json or compact")
flags.StringVar(&color, "color", "auto", "Colorize compact output. auto, always, or never")
flags.StringSliceVarP(&includeFields, "include-fields", "f", nil, "Include only fields in events")
flags.StringSliceVarP(&excludeFields, "exclude-fields", "F", nil, "Exclude fields from events")
flags.StringSliceVarP(&namespaces, "namespace", "n", nil, "Get events by Kubernetes namespaces")
flags.StringSliceVar(&processes, "process", nil, "Get events by process name regex")
flags.StringSliceVar(&pods, "pod", nil, "Get events by pod name regex")
flags.BoolVar(&host, "host", false, "Get host events")
flags.BoolVar(&timestamps, "timestamps", false, "Include timestamps in compact output")
flags.StringVarP(&ttyEncode, "tty-encode", "t", "", "Encode terminal data by file path (all other events will be ignored)")
return &cmd
}
19 changes: 9 additions & 10 deletions cmd/tetra/tracingpolicy/tracingpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,25 @@ func New() *cobra.Command {
},
}

var tpListOutputFlag string
tpListCmd := &cobra.Command{
Use: "list",
Short: "list tracing policies",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
output := viper.GetString(common.KeyOutput)
switch output {
case "json", "text":
// valid
default:
logger.GetLogger().WithField(common.KeyOutput, output).Fatal("invalid output flag")
PreRunE: func(cmd *cobra.Command, args []string) error {
if tpListOutputFlag != "json" && tpListOutputFlag != "text" {
return fmt.Errorf("invalid value for %q flag: %s", common.KeyOutput, tpListOutputFlag)
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
common.CliRun(func(ctx context.Context, cli tetragon.FineGuidanceSensorsClient) {
listTracingPolicies(ctx, cli, output)
listTracingPolicies(ctx, cli, tpListOutputFlag)
})
},
}
tpListFlags := tpListCmd.Flags()
tpListFlags.StringP(common.KeyOutput, "o", "text", "Output format. json or text")
viper.BindPFlags(tpListFlags)
tpListFlags.StringVarP(&tpListOutputFlag, common.KeyOutput, "o", "text", "Output format. text or json")

tpGenerateCmd := &cobra.Command{
Use: "generate",
Expand Down

0 comments on commit da795ea

Please sign in to comment.