generated from falcosecurity/template-repository
-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
- Loading branch information
Showing
8 changed files
with
507 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/creasty/defaults" | ||
"github.com/falcosecurity/event-generator/cmd/internal/validate" | ||
"github.com/go-playground/validator/v10" | ||
logger "github.com/sirupsen/logrus" | ||
) | ||
|
||
// ConfigOptions represent the persistent configuration flags of event-generator. | ||
type ConfigOptions struct { | ||
ConfigFile string | ||
LogLevel string `validate:"logrus" name:"log level" default:"info"` | ||
} | ||
|
||
// NewConfigOptions creates an instance of ConfigOptions. | ||
func NewConfigOptions() *ConfigOptions { | ||
o := &ConfigOptions{} | ||
if err := defaults.Set(o); err != nil { | ||
logger.WithError(err).WithField("options", "ConfigOptions").Fatal("error setting event-generator options defaults") | ||
} | ||
return o | ||
} | ||
|
||
// Validate validates the ConfigOptions fields. | ||
func (co *ConfigOptions) Validate() []error { | ||
if err := validate.V.Struct(co); err != nil { | ||
errors := err.(validator.ValidationErrors) | ||
errArr := []error{} | ||
for _, e := range errors { | ||
// Translate each error one at a time | ||
errArr = append(errArr, fmt.Errorf(e.Translate(validate.T))) | ||
} | ||
return errArr | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package validate | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"reflect" | ||
|
||
"github.com/go-playground/validator/v10" | ||
) | ||
|
||
func isFilePath(fl validator.FieldLevel) bool { | ||
field := fl.Field() | ||
|
||
switch field.Kind() { | ||
case reflect.String: | ||
fileInfo, err := os.Stat(field.String()) | ||
if err != nil { | ||
if !os.IsNotExist(err) { | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
return !fileInfo.IsDir() | ||
} | ||
|
||
panic(fmt.Sprintf("Bad field type %T", field.Interface())) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package validate | ||
|
||
import ( | ||
"github.com/go-playground/validator/v10" | ||
logger "github.com/sirupsen/logrus" | ||
) | ||
|
||
func isLogrusLevel(fl validator.FieldLevel) bool { | ||
level := fl.Field().String() | ||
lvl, err := logger.ParseLevel(level) | ||
if err != nil { | ||
return false | ||
} | ||
logger.SetLevel(lvl) | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package validate | ||
|
||
import ( | ||
"reflect" | ||
"strings" | ||
|
||
"github.com/go-playground/locales/en" | ||
ut "github.com/go-playground/universal-translator" | ||
"github.com/go-playground/validator/v10" | ||
en_translations "github.com/go-playground/validator/v10/translations/en" | ||
) | ||
|
||
// V is the validator single instance. | ||
// | ||
// It is a singleton so to cache the structs info. | ||
var V *validator.Validate | ||
|
||
// T is the universal translator for validatiors. | ||
var T ut.Translator | ||
|
||
func init() { | ||
V = validator.New() | ||
|
||
// Register a function to get the field name from "name" tags. | ||
V.RegisterTagNameFunc(func(fld reflect.StructField) string { | ||
name := strings.SplitN(fld.Tag.Get("name"), ",", 2)[0] | ||
if name == "-" { | ||
return "" | ||
} | ||
return name | ||
}) | ||
|
||
V.RegisterValidation("logrus", isLogrusLevel) | ||
V.RegisterValidation("filepath", isFilePath) | ||
|
||
eng := en.New() | ||
uni := ut.New(eng, eng) | ||
T, _ = uni.GetTranslator("en") | ||
en_translations.RegisterDefaultTranslations(V, T) | ||
|
||
V.RegisterTranslation( | ||
"filepath", | ||
T, | ||
func(ut ut.Translator) error { | ||
return ut.Add("filepath", "{0} must be a valid file path", true) | ||
}, | ||
func(ut ut.Translator, fe validator.FieldError) string { | ||
t, _ := ut.T("filepath", fe.Field()) | ||
|
||
return t | ||
}, | ||
) | ||
|
||
V.RegisterTranslation( | ||
"logrus", | ||
T, | ||
func(ut ut.Translator) error { | ||
return ut.Add("logrus", "{0} must be a valid logrus level", true) | ||
}, | ||
func(ut ut.Translator, fe validator.FieldError) string { | ||
t, _ := ut.T("logrus", fe.Field()) | ||
|
||
return t | ||
}, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package cmd | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/spf13/pflag" | ||
|
||
homedir "github.com/mitchellh/go-homedir" | ||
logger "github.com/sirupsen/logrus" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func init() { | ||
logger.SetFormatter(&logger.TextFormatter{ | ||
ForceColors: true, | ||
DisableLevelTruncation: true, | ||
DisableTimestamp: true, | ||
}) | ||
} | ||
|
||
// New instantiates the root command. | ||
func New(configOptions *ConfigOptions) *cobra.Command { | ||
if configOptions == nil { | ||
configOptions = NewConfigOptions() | ||
} | ||
rootCmd := &cobra.Command{ | ||
Use: "event-generator", | ||
Short: "A command line tool to perform a variety of suspect actions.", | ||
PersistentPreRun: func(c *cobra.Command, args []string) { | ||
// PersistentPreRun runs before flags validation but after args validation. | ||
// Do not assume initialization completed during args validation. | ||
|
||
// at this stage configOptions is bound to command line flags only | ||
validateConfig(*configOptions) | ||
initLogger(configOptions.LogLevel) | ||
initConfig(configOptions.ConfigFile) | ||
|
||
// then bind all flags to ENV and config file | ||
flags := c.Flags() | ||
initEnv() | ||
initFlags(flags, map[string]bool{ | ||
// exclude flags to be not bound to ENV and config file | ||
"config": true, | ||
"loglevel": true, | ||
"help": true, | ||
}) | ||
// validateConfig(*configOptions) // enable if other flags were bound to configOptions | ||
debugFlags(flags) | ||
}, | ||
Run: func(c *cobra.Command, args []string) { | ||
c.Help() | ||
}, | ||
} | ||
|
||
flags := rootCmd.PersistentFlags() | ||
flags.StringVarP(&configOptions.ConfigFile, "config", "c", configOptions.ConfigFile, "config file path (default $HOME/.falco-event-generator.yaml if exists)") | ||
flags.StringVarP(&configOptions.LogLevel, "loglevel", "l", configOptions.LogLevel, "log level") | ||
|
||
return rootCmd | ||
} | ||
|
||
// Execute creates the root command and runs it. | ||
func Execute() { | ||
if err := New(nil).Execute(); err != nil { | ||
logger.WithError(err).Fatal("error executing event-generator") | ||
} | ||
} | ||
|
||
// validateConfig | ||
func validateConfig(configOptions ConfigOptions) { | ||
if errs := configOptions.Validate(); errs != nil { | ||
for _, err := range errs { | ||
logger.WithError(err).Error("error validating config options") | ||
} | ||
logger.Fatal("exiting for validation errors") | ||
} | ||
} | ||
|
||
// initEnv enables automatic ENV variables lookup | ||
func initEnv() { | ||
viper.AutomaticEnv() | ||
viper.SetEnvPrefix("falco_event_generator") | ||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) | ||
} | ||
|
||
// initLogger configures the logger | ||
func initLogger(logLevel string) { | ||
lvl, err := logger.ParseLevel(logLevel) | ||
if err != nil { | ||
logger.Fatal(err) | ||
} | ||
logger.SetLevel(lvl) | ||
} | ||
|
||
// initConfig reads in config file, if any | ||
func initConfig(configFile string) { | ||
if configFile != "" { | ||
viper.SetConfigFile(configFile) | ||
} else { | ||
// Find home directory. | ||
home, err := homedir.Dir() | ||
if err != nil { | ||
logger.WithError(err).Fatal("error getting the home directory") | ||
} | ||
|
||
viper.AddConfigPath(home) | ||
viper.SetConfigName(".falco-event-generator") | ||
} | ||
|
||
// If a config file is found, read it in. | ||
if err := viper.ReadInConfig(); err == nil { | ||
logger.WithField("file", viper.ConfigFileUsed()).Info("using config file") | ||
} else { | ||
if _, ok := err.(viper.ConfigFileNotFoundError); ok { | ||
// Config file not found, ignore ... | ||
logger.Debug("running without a configuration file") | ||
} else { | ||
// Config file was found but another error was produced | ||
logger.WithField("file", viper.ConfigFileUsed()).WithError(err).Fatal("error running with config file") | ||
} | ||
} | ||
} | ||
|
||
// initFlags binds a full flag set to the configuration, using each flag's long name as the config key. | ||
// | ||
// Assuming viper's `AutomaticEnv` is enabled, when a flag is not present in the command line | ||
// will fallback to one of (in order of precedence): | ||
// - ENV (with FALCO_EVENT_GENERATOR prefix) | ||
// - config file (e.g. ~/.falco-event-generator.yaml) | ||
// - its default | ||
func initFlags(flags *pflag.FlagSet, exclude map[string]bool) { | ||
viper.BindPFlags(flags) | ||
flags.VisitAll(func(f *pflag.Flag) { | ||
if exclude[f.Name] { | ||
return | ||
} | ||
if v := viper.GetString(f.Name); v != f.DefValue { | ||
flags.Set(f.Name, v) | ||
} | ||
}) | ||
} | ||
|
||
func debugFlags(flags *pflag.FlagSet) { | ||
fields := logger.Fields{} | ||
flags.VisitAll(func(f *pflag.Flag) { | ||
if f.Changed { | ||
fields[f.Name] = f.Value | ||
} | ||
}) | ||
logger.WithFields(fields).Debug("running with options") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,15 @@ | ||
module github.com/falcosecurity/event-generator | ||
|
||
go 1.14 | ||
|
||
require ( | ||
github.com/creasty/defaults v1.3.0 | ||
github.com/go-playground/locales v0.13.0 | ||
github.com/go-playground/universal-translator v0.17.0 | ||
github.com/go-playground/validator/v10 v10.2.0 | ||
github.com/mitchellh/go-homedir v1.1.0 | ||
github.com/sirupsen/logrus v1.5.0 | ||
github.com/spf13/cobra v0.0.7 | ||
github.com/spf13/pflag v1.0.5 | ||
github.com/spf13/viper v1.6.2 | ||
) |
Oops, something went wrong.