From b35b23a5c35b592fa149b0f066237d6f5c42d6c1 Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Tue, 5 Dec 2023 12:04:38 +0100 Subject: [PATCH 1/2] new(cmd,internal,pkg): move `driver config` options to be common to all `driver` commands. This way all driver commands can customize their run with both CLI args or env variables, without actually storing anything in the config file. Signed-off-by: Federico Di Pierro --- cmd/driver/cleanup/cleanup.go | 15 ++-- cmd/driver/config/config.go | 103 +++---------------------- cmd/driver/config/config_test.go | 10 +-- cmd/driver/driver_linux.go | 128 +++++++++++++++++++++++++++++-- cmd/driver/install/install.go | 35 ++++----- cmd/driver/printenv/printenv.go | 21 +++-- internal/config/config.go | 56 +++----------- pkg/options/driver.go | 31 ++++++++ 8 files changed, 210 insertions(+), 189 deletions(-) diff --git a/cmd/driver/cleanup/cleanup.go b/cmd/driver/cleanup/cleanup.go index 342f111d..5a86278c 100644 --- a/cmd/driver/cleanup/cleanup.go +++ b/cmd/driver/cleanup/cleanup.go @@ -19,18 +19,19 @@ import ( "github.com/spf13/cobra" "golang.org/x/net/context" - "github.com/falcosecurity/falcoctl/internal/config" "github.com/falcosecurity/falcoctl/pkg/options" ) type driverCleanupOptions struct { *options.Common + *options.Driver } // NewDriverCleanupCmd cleans a driver up. -func NewDriverCleanupCmd(ctx context.Context, opt *options.Common) *cobra.Command { +func NewDriverCleanupCmd(ctx context.Context, opt *options.Common, driver *options.Driver) *cobra.Command { o := driverCleanupOptions{ Common: opt, + Driver: driver, } cmd := &cobra.Command{ @@ -47,12 +48,8 @@ func NewDriverCleanupCmd(ctx context.Context, opt *options.Common) *cobra.Comman } func (o *driverCleanupOptions) RunDriverCleanup(_ context.Context) error { - driver, err := config.Driverer() - if err != nil { - return err - } o.Printer.Logger.Info("Running falcoctl driver cleanup", o.Printer.Logger.Args( - "driver type", driver.Type, - "driver name", driver.Name)) - return driver.Type.Cleanup(o.Printer, driver.Name) + "driver type", o.Driver.Type, + "driver name", o.Driver.Name)) + return o.Driver.Type.Cleanup(o.Printer, o.Driver.Name) } diff --git a/cmd/driver/config/config.go b/cmd/driver/config/config.go index 63285a61..efcd31ee 100644 --- a/cmd/driver/config/config.go +++ b/cmd/driver/config/config.go @@ -23,7 +23,6 @@ import ( "path/filepath" "strings" - "github.com/pterm/pterm" "github.com/spf13/cobra" "golang.org/x/net/context" "gopkg.in/yaml.v3" @@ -35,8 +34,6 @@ import ( "github.com/falcosecurity/falcoctl/internal/config" "github.com/falcosecurity/falcoctl/internal/utils" - driverdistro "github.com/falcosecurity/falcoctl/pkg/driver/distro" - driverkernel "github.com/falcosecurity/falcoctl/pkg/driver/kernel" drivertype "github.com/falcosecurity/falcoctl/pkg/driver/type" "github.com/falcosecurity/falcoctl/pkg/options" ) @@ -53,21 +50,17 @@ If engine.kind key is set to a non-driver driven engine, Falco configuration won type driverConfigOptions struct { *options.Common - Type *options.DriverTypes - Version string - Repos []string - Name string - HostRoot string + *options.Driver Update bool Namespace string KubeConfig string } // NewDriverConfigCmd configures a driver and stores it in config. -func NewDriverConfigCmd(ctx context.Context, opt *options.Common) *cobra.Command { +func NewDriverConfigCmd(ctx context.Context, opt *options.Common, driver *options.Driver) *cobra.Command { o := driverConfigOptions{ Common: opt, - Type: options.NewDriverTypes(), + Driver: driver, } cmd := &cobra.Command{ @@ -80,11 +73,6 @@ func NewDriverConfigCmd(ctx context.Context, opt *options.Common) *cobra.Command }, } - cmd.Flags().Var(o.Type, "type", "Driver type to be configured "+o.Type.Allowed()) - cmd.Flags().StringVar(&o.Version, "version", config.DefaultDriver.Version, "Driver version to be configured.") - cmd.Flags().StringSliceVar(&o.Repos, "repo", config.DefaultDriver.Repos, "Driver repo to be configured.") - cmd.Flags().StringVar(&o.Name, "name", config.DefaultDriver.Name, "Driver name to be configured.") - cmd.Flags().StringVar(&o.HostRoot, "host-root", config.DefaultDriver.HostRoot, "Driver host root to be configured.") cmd.Flags().BoolVar(&o.Update, "update-falco", true, "Whether to update Falco config/configmap.") cmd.Flags().StringVar(&o.Namespace, "namespace", "", "Kubernetes namespace.") cmd.Flags().StringVar(&o.KubeConfig, "kubeconfig", "", "Kubernetes config.") @@ -98,83 +86,12 @@ func (o *driverConfigOptions) RunDriverConfig(ctx context.Context, cmd *cobra.Co err error ) - driverCfg, err := config.Driverer() - if err != nil { - return err - } - - loggerArgs := make([]pterm.LoggerArgument, 0) - if f := cmd.Flags().Lookup("version"); f != nil && f.Changed { - driverCfg.Version = o.Version - loggerArgs = append(loggerArgs, pterm.LoggerArgument{ - Key: "driver version", - Value: o.Version, - }) - } - if f := cmd.Flags().Lookup("repo"); f != nil && f.Changed { - driverCfg.Repos = o.Repos - loggerArgs = append(loggerArgs, pterm.LoggerArgument{ - Key: "driver repos", - Value: strings.Join(o.Repos, ","), - }) - } - if f := cmd.Flags().Lookup("name"); f != nil && f.Changed { - driverCfg.Name = o.Name - loggerArgs = append(loggerArgs, pterm.LoggerArgument{ - Key: "driver name", - Value: o.Name, - }) - } - if f := cmd.Flags().Lookup("host-root"); f != nil && f.Changed { - if !filepath.IsAbs(o.HostRoot) { - return fmt.Errorf("host-root must be an absolute path: %s", o.HostRoot) - } - driverCfg.HostRoot = o.HostRoot - loggerArgs = append(loggerArgs, pterm.LoggerArgument{ - Key: "driver host root", - Value: o.HostRoot, - }) - } - if f := cmd.Flags().Lookup("type"); f != nil && f.Changed { - loggerArgs = append(loggerArgs, pterm.LoggerArgument{ - Key: "driver type", - Value: o.Type.String(), - }) - if o.Type.String() != "auto" { - // Ok driver type was enforced by the user - dType, err = drivertype.Parse(o.Type.String()) - if err != nil { - return err - } - } else { - // automatic logic - info, err := driverkernel.FetchInfo("", "") - if err != nil { - return err - } - o.Printer.Logger.Debug("Fetched kernel info", o.Printer.Logger.Args( - "arch", info.Architecture.ToNonDeb(), - "kernel release", info.String(), - "kernel version", info.KernelVersion)) - - d, err := driverdistro.Discover(info, driverCfg.HostRoot) - if err != nil { - if !errors.Is(err, driverdistro.ErrUnsupported) { - return err - } - o.Printer.Logger.Info("Detected an unsupported target system; falling back at generic logic.") - } - o.Printer.Logger.Debug("Discovered distro", o.Printer.Logger.Args("target", d)) - - dType = d.PreferredDriver(info) - if dType == nil { - return fmt.Errorf("automatic driver selection failed") - } - } - driverCfg.Type = dType - } - - o.Printer.Logger.Info("Running falcoctl driver config", loggerArgs) + o.Printer.Logger.Info("Running falcoctl driver config", o.Printer.Logger.Args( + "name", o.Driver.Name, + "version", o.Driver.Version, + "type", o.Driver.Type.String(), + "host-root", o.Driver.HostRoot, + "repos", strings.Join(o.Driver.Repos, ","))) if o.Update { err = o.commit(ctx, dType) @@ -182,7 +99,7 @@ func (o *driverConfigOptions) RunDriverConfig(ctx context.Context, cmd *cobra.Co return err } } - return config.StoreDriver(&driverCfg, o.ConfigFile) + return config.StoreDriver(o.Driver.ToDriverConfig(), o.ConfigFile) } func checkFalcoRunsWithDrivers(engineKind string) error { diff --git a/cmd/driver/config/config_test.go b/cmd/driver/config/config_test.go index 4a3b8fdd..34ae301b 100644 --- a/cmd/driver/config/config_test.go +++ b/cmd/driver/config/config_test.go @@ -36,19 +36,19 @@ Usage: Flags: -h, --help help for config - --host-root string Driver host root to be configured. (default "/") --kubeconfig string Kubernetes config. - --name string Driver name to be configured. (default "falco") --namespace string Kubernetes namespace. - --repo strings Driver repo to be configured. (default [https://download.falco.org/driver]) - --type string Driver type to be configured (auto, ebpf, kmod, modern_ebpf) (default "kmod") --update-falco Whether to update Falco config/configmap. (default true) - --version string Driver version to be configured. Global Flags: --config string config file to be used for falcoctl (default "/etc/falcoctl/falcoctl.yaml") + --host-root string Driver host root to be used. (default "/") --log-format string Set formatting for logs (color, text, json) (default "color") --log-level string Set level for logs (info, warn, debug, trace) (default "info") + --name string Driver name to be used. (default "falco") + --repo strings Driver repo to be used. (default [https://download.falco.org/driver]) + --type string Driver type to be used (auto, ebpf, kmod, modern_ebpf) (default "kmod") + --version string Driver version to be used. ` var addAssertFailedBehavior = func(specificError string) { diff --git a/cmd/driver/driver_linux.go b/cmd/driver/driver_linux.go index c36fda14..4da826f2 100644 --- a/cmd/driver/driver_linux.go +++ b/cmd/driver/driver_linux.go @@ -20,19 +20,28 @@ package driver import ( "context" + "errors" + "fmt" "github.com/spf13/cobra" + "github.com/spf13/viper" drivercleanup "github.com/falcosecurity/falcoctl/cmd/driver/cleanup" driverconfig "github.com/falcosecurity/falcoctl/cmd/driver/config" driverinstall "github.com/falcosecurity/falcoctl/cmd/driver/install" driverprintenv "github.com/falcosecurity/falcoctl/cmd/driver/printenv" "github.com/falcosecurity/falcoctl/internal/config" - commonoptions "github.com/falcosecurity/falcoctl/pkg/options" + driverdistro "github.com/falcosecurity/falcoctl/pkg/driver/distro" + driverkernel "github.com/falcosecurity/falcoctl/pkg/driver/kernel" + drivertype "github.com/falcosecurity/falcoctl/pkg/driver/type" + "github.com/falcosecurity/falcoctl/pkg/options" ) // NewDriverCmd returns the driver command. -func NewDriverCmd(ctx context.Context, opt *commonoptions.Common) *cobra.Command { +func NewDriverCmd(ctx context.Context, opt *options.Common) *cobra.Command { + driver := &options.Driver{} + driverTypes := options.NewDriverTypes() + cmd := &cobra.Command{ Use: "driver", DisableFlagsInUseLine: true, @@ -41,13 +50,118 @@ func NewDriverCmd(ctx context.Context, opt *commonoptions.Common) *cobra.Command ** This command is in preview and under development. **`, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { opt.Initialize() - return config.Load(opt.ConfigFile) + if err := config.Load(opt.ConfigFile); err != nil { + return err + } + + // Override "version" flag with viper config if not set by user. + f := cmd.Flags().Lookup("version") + if f == nil { + // should never happen + return fmt.Errorf("unable to retrieve flag version") + } else if !f.Changed && viper.IsSet(config.DriverVersionKey) { + val := viper.Get(config.DriverVersionKey) + if err := cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val)); err != nil { + return fmt.Errorf("unable to overwrite \"version\" flag: %w", err) + } + } + + // Override "repo" flag with viper config if not set by user. + f = cmd.Flags().Lookup("repo") + if f == nil { + // should never happen + return fmt.Errorf("unable to retrieve flag repo") + } else if !f.Changed && viper.IsSet(config.DriverReposKey) { + val, err := config.DriverRepos() + if err != nil { + return err + } + if err := cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val)); err != nil { + return fmt.Errorf("unable to overwrite \"repo\" flag: %w", err) + } + } + + // Override "name" flag with viper config if not set by user. + f = cmd.Flags().Lookup("name") + if f == nil { + // should never happen + return fmt.Errorf("unable to retrieve flag name") + } else if !f.Changed && viper.IsSet(config.DriverNameKey) { + val := viper.Get(config.DriverNameKey) + if err := cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val)); err != nil { + return fmt.Errorf("unable to overwrite \"name\" flag: %w", err) + } + } + + // Override "host-root" flag with viper config if not set by user. + f = cmd.Flags().Lookup("host-root") + if f == nil { + // should never happen + return fmt.Errorf("unable to retrieve flag host-root") + } else if !f.Changed && viper.IsSet(config.DriverHostRootKey) { + val := viper.Get(config.DriverHostRootKey) + if err := cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val)); err != nil { + return fmt.Errorf("unable to overwrite \"host-root\" flag: %w", err) + } + } + + // Override "type" flag with viper config if not set by user. + f = cmd.Flags().Lookup("type") + if f == nil { + // should never happen + return fmt.Errorf("unable to retrieve flag type") + } else if !f.Changed && viper.IsSet(config.DriverTypeKey) { + val := viper.Get(config.DriverTypeKey) + if err := cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val)); err != nil { + return fmt.Errorf("unable to overwrite \"type\" flag: %w", err) + } + } + + if driverTypes.String() != "auto" { + var err error + // Ok driver type was enforced by the user + driver.Type, err = drivertype.Parse(driverTypes.String()) + if err != nil { + return err + } + } else { + // automatic logic + info, err := driverkernel.FetchInfo("", "") + if err != nil { + return err + } + opt.Printer.Logger.Debug("Fetched kernel info", opt.Printer.Logger.Args( + "arch", info.Architecture.ToNonDeb(), + "kernel release", info.String(), + "kernel version", info.KernelVersion)) + + d, err := driverdistro.Discover(info, driver.HostRoot) + if err != nil { + if !errors.Is(err, driverdistro.ErrUnsupported) { + return err + } + opt.Printer.Logger.Info("Detected an unsupported target system; falling back at generic logic.") + } + opt.Printer.Logger.Debug("Discovered distro", opt.Printer.Logger.Args("target", d)) + + driver.Type = d.PreferredDriver(info) + if driver.Type == nil { + return fmt.Errorf("automatic driver selection failed") + } + } + return driver.Validate() }, } - cmd.AddCommand(driverinstall.NewDriverInstallCmd(ctx, opt)) - cmd.AddCommand(driverconfig.NewDriverConfigCmd(ctx, opt)) - cmd.AddCommand(drivercleanup.NewDriverCleanupCmd(ctx, opt)) - cmd.AddCommand(driverprintenv.NewDriverPrintenvCmd(ctx, opt)) + cmd.PersistentFlags().Var(driverTypes, "type", "Driver type to be used "+driverTypes.Allowed()) + cmd.PersistentFlags().StringVar(&driver.Version, "version", config.DefaultDriver.Version, "Driver version to be used.") + cmd.PersistentFlags().StringSliceVar(&driver.Repos, "repo", config.DefaultDriver.Repos, "Driver repo to be used.") + cmd.PersistentFlags().StringVar(&driver.Name, "name", config.DefaultDriver.Name, "Driver name to be used.") + cmd.PersistentFlags().StringVar(&driver.HostRoot, "host-root", config.DefaultDriver.HostRoot, "Driver host root to be used.") + + cmd.AddCommand(driverinstall.NewDriverInstallCmd(ctx, opt, driver)) + cmd.AddCommand(driverconfig.NewDriverConfigCmd(ctx, opt, driver)) + cmd.AddCommand(drivercleanup.NewDriverCleanupCmd(ctx, opt, driver)) + cmd.AddCommand(driverprintenv.NewDriverPrintenvCmd(ctx, opt, driver)) return cmd } diff --git a/cmd/driver/install/install.go b/cmd/driver/install/install.go index 09fb0a63..8db73ade 100644 --- a/cmd/driver/install/install.go +++ b/cmd/driver/install/install.go @@ -28,7 +28,6 @@ import ( "github.com/spf13/cobra" "golang.org/x/net/context" - "github.com/falcosecurity/falcoctl/internal/config" driverdistro "github.com/falcosecurity/falcoctl/pkg/driver/distro" driverkernel "github.com/falcosecurity/falcoctl/pkg/driver/kernel" "github.com/falcosecurity/falcoctl/pkg/options" @@ -41,6 +40,7 @@ type driverDownloadOptions struct { type driverInstallOptions struct { *options.Common + *options.Driver Download bool Compile bool DriverKernelRelease string @@ -49,9 +49,10 @@ type driverInstallOptions struct { } // NewDriverInstallCmd returns the driver install command. -func NewDriverInstallCmd(ctx context.Context, opt *options.Common) *cobra.Command { +func NewDriverInstallCmd(ctx context.Context, opt *options.Common, driver *options.Driver) *cobra.Command { o := driverInstallOptions{ Common: opt, + Driver: driver, // Defaults to downloading or building if needed Download: true, Compile: true, @@ -64,16 +65,12 @@ func NewDriverInstallCmd(ctx context.Context, opt *options.Common) *cobra.Comman Long: `[Preview] Install previously configured driver, either downloading it or attempting a build. ** This command is in preview and under development. **`, RunE: func(cmd *cobra.Command, args []string) error { - driver, err := config.Driverer() - if err != nil { - return err - } // If empty, try to load it automatically from /usr/src sub folders, // using the most recent (ie: the one with greatest semver) driver version. - if driver.Version == "" { - driver.Version = loadDriverVersion() + if o.Driver.Version == "" { + o.Driver.Version = loadDriverVersion() } - dest, err := o.RunDriverInstall(ctx, &driver) + dest, err := o.RunDriverInstall(ctx) if dest != "" { // We don't care about errors at this stage // Fallback: try to load any available driver if leaving with an error. @@ -134,23 +131,23 @@ func setDefaultHTTPClientOpts(downloadOptions driverDownloadOptions) { } // RunDriverInstall implements the driver install command. -func (o *driverInstallOptions) RunDriverInstall(ctx context.Context, driver *config.Driver) (string, error) { +func (o *driverInstallOptions) RunDriverInstall(ctx context.Context) (string, error) { kr, err := driverkernel.FetchInfo(o.DriverKernelRelease, o.DriverKernelVersion) if err != nil { return "", err } o.Printer.Logger.Info("Running falcoctl driver install", o.Printer.Logger.Args( - "driver version", driver.Version, - "driver type", driver.Type, - "driver name", driver.Name, + "driver version", o.Driver.Version, + "driver type", o.Driver.Type, + "driver name", o.Driver.Name, "compile", o.Compile, "download", o.Download, "arch", kr.Architecture.ToNonDeb(), "kernel release", kr.String(), "kernel version", kr.KernelVersion)) - if !driver.Type.HasArtifacts() { + if !o.Driver.Type.HasArtifacts() { o.Printer.Logger.Info("No artifacts needed for the selected driver.") return "", nil } @@ -160,7 +157,7 @@ func (o *driverInstallOptions) RunDriverInstall(ctx context.Context, driver *con return "", nil } - d, err := driverdistro.Discover(kr, driver.HostRoot) + d, err := driverdistro.Discover(kr, o.Driver.HostRoot) if err != nil { if errors.Is(err, driverdistro.ErrUnsupported) && o.Compile { o.Download = false @@ -172,7 +169,7 @@ func (o *driverInstallOptions) RunDriverInstall(ctx context.Context, driver *con } o.Printer.Logger.Info("found distro", o.Printer.Logger.Args("target", d)) - err = driver.Type.Cleanup(o.Printer, driver.Name) + err = o.Driver.Type.Cleanup(o.Printer, o.Driver.Name) if err != nil { return "", err } @@ -181,7 +178,7 @@ func (o *driverInstallOptions) RunDriverInstall(ctx context.Context, driver *con var dest string if o.Download { - dest, err = driverdistro.Download(ctx, d, o.Printer, kr, driver.Name, driver.Type, driver.Version, driver.Repos) + dest, err = driverdistro.Download(ctx, d, o.Printer, kr, o.Driver.Name, o.Driver.Type, o.Driver.Version, o.Driver.Repos) if err == nil { return dest, nil } @@ -191,12 +188,12 @@ func (o *driverInstallOptions) RunDriverInstall(ctx context.Context, driver *con } if o.Compile { - dest, err = driverdistro.Build(ctx, d, o.Printer, kr, driver.Name, driver.Type, driver.Version) + dest, err = driverdistro.Build(ctx, d, o.Printer, kr, o.Driver.Name, o.Driver.Type, o.Driver.Version) if err == nil { return dest, nil } o.Printer.Logger.Warn(err.Error()) } - return driver.Name, fmt.Errorf("failed: %w", err) + return o.Driver.Name, fmt.Errorf("failed: %w", err) } diff --git a/cmd/driver/printenv/printenv.go b/cmd/driver/printenv/printenv.go index 868305cb..3581551d 100644 --- a/cmd/driver/printenv/printenv.go +++ b/cmd/driver/printenv/printenv.go @@ -22,7 +22,6 @@ import ( "github.com/spf13/cobra" "golang.org/x/net/context" - "github.com/falcosecurity/falcoctl/internal/config" driverdistro "github.com/falcosecurity/falcoctl/pkg/driver/distro" driverkernel "github.com/falcosecurity/falcoctl/pkg/driver/kernel" "github.com/falcosecurity/falcoctl/pkg/options" @@ -30,12 +29,14 @@ import ( type driverPrintenvOptions struct { *options.Common + *options.Driver } // NewDriverPrintenvCmd print info about driver falcoctl config as env vars. -func NewDriverPrintenvCmd(ctx context.Context, opt *options.Common) *cobra.Command { +func NewDriverPrintenvCmd(ctx context.Context, opt *options.Common, driver *options.Driver) *cobra.Command { o := driverPrintenvOptions{ Common: opt, + Driver: driver, } cmd := &cobra.Command{ @@ -52,22 +53,18 @@ func NewDriverPrintenvCmd(ctx context.Context, opt *options.Common) *cobra.Comma } func (o *driverPrintenvOptions) RunDriverPrintenv(_ context.Context) error { - driver, err := config.Driverer() - if err != nil { - return err - } - o.Printer.DefaultText.Printf("DRIVER=%q\n", driver.Type.String()) - o.Printer.DefaultText.Printf("DRIVERS_REPO=%q\n", strings.Join(driver.Repos, ", ")) - o.Printer.DefaultText.Printf("DRIVER_VERSION=%q\n", driver.Version) - o.Printer.DefaultText.Printf("DRIVER_NAME=%q\n", driver.Name) - o.Printer.DefaultText.Printf("HOST_ROOT=%q\n", driver.HostRoot) + o.Printer.DefaultText.Printf("DRIVER=%q\n", o.Driver.Type.String()) + o.Printer.DefaultText.Printf("DRIVERS_REPO=%q\n", strings.Join(o.Driver.Repos, ", ")) + o.Printer.DefaultText.Printf("DRIVER_VERSION=%q\n", o.Driver.Version) + o.Printer.DefaultText.Printf("DRIVER_NAME=%q\n", o.Driver.Name) + o.Printer.DefaultText.Printf("HOST_ROOT=%q\n", o.Driver.HostRoot) kr, err := driverkernel.FetchInfo("", "") if err != nil { return err } - d, err := driverdistro.Discover(kr, driver.HostRoot) + d, err := driverdistro.Discover(kr, o.Driver.HostRoot) if err != nil { if !errors.Is(err, driverdistro.ErrUnsupported) { return err diff --git a/internal/config/config.go b/internal/config/config.go index 8cf67e65..c75dcdb6 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -50,7 +50,7 @@ var ( // DefaultRegistryCredentialConfPath is the default path for the credential store configuration file. DefaultRegistryCredentialConfPath = filepath.Join(config.Dir(), "config.json") // DefaultDriver is the default config for the falcosecurity organization. - DefaultDriver driver + DefaultDriver Driver // Useful regexps for parsing. @@ -175,8 +175,8 @@ type Install struct { NoVerify bool `mapstructure:"noVerify"` } -// driver represents the internal driver configuration (with Type string). -type driver struct { +// Driver represents the internal driver configuration (with Type string). +type Driver struct { Type string `mapstructure:"type"` Name string `mapstructure:"name"` Repos []string `mapstructure:"repos"` @@ -184,15 +184,6 @@ type driver struct { HostRoot string `mapstructure:"hostRoot"` } -// Driver represents the resolved driver configuration, exposed to be consumed. -type Driver struct { - Type drivertype.DriverType - Name string - Repos []string - Version string - HostRoot string -} - func init() { ConfigDir = filepath.Join(homedir.Get(), ".config") FalcoctlPath = filepath.Join(ConfigDir, "falcoctl") @@ -203,7 +194,7 @@ func init() { Name: "falcosecurity", URL: "https://falcosecurity.github.io/falcoctl/index.yaml", } - DefaultDriver = driver{ + DefaultDriver = Driver{ Type: drivertype.TypeKmod, Name: "falco", Repos: []string{"https://download.falco.org/driver"}, @@ -236,6 +227,9 @@ func Load(path string) error { viper.SetDefault(DriverNameKey, DefaultDriver.Name) viper.SetDefault(DriverReposKey, DefaultDriver.Repos) viper.SetDefault(DriverVersionKey, DefaultDriver.Version) + // Bind FALCOCTL_DRIVER_HOSTROOT key to HOST_ROOT, + // so that we manage Falco HOST_ROOT variable too. + _ = viper.BindEnv(DriverHostRootKey, falcoHostRootEnvKey) err = viper.ReadInConfig() if errors.As(err, &viper.ConfigFileNotFoundError{}) || os.IsNotExist(err) { @@ -548,48 +542,22 @@ func Installer() (Install, error) { }, nil } -// Driverer retrieves the driver section of the config file. -func Driverer() (Driver, error) { - drvTypeStr := viper.GetString(DriverTypeKey) - drvType, err := drivertype.Parse(drvTypeStr) - if err != nil { - return Driver{}, err - } - +// DriverRepos retrieves the driver section of the config file. +func DriverRepos() ([]string, error) { // manage driver.Repos as ";" separated list. repos := viper.GetStringSlice(DriverReposKey) if len(repos) == 1 { // in this case it might come from the env if !SemicolonSeparatedRegexp.MatchString(repos[0]) { - return Driver{}, fmt.Errorf("env variable not correctly set, should match %q, got %q", SemicolonSeparatedRegexp.String(), repos[0]) + return repos, fmt.Errorf("env variable not correctly set, should match %q, got %q", SemicolonSeparatedRegexp.String(), repos[0]) } repos = strings.Split(repos[0], ";") } - - // Bind FALCOCTL_DRIVER_HOSTROOT key to HOST_ROOT, - // so that we manage Falco HOST_ROOT variable too. - _ = viper.BindEnv(DriverHostRootKey, falcoHostRootEnvKey) - - drvCfg := Driver{ - Type: drvType, - Name: viper.GetString(DriverNameKey), - Repos: repos, - Version: viper.GetString(DriverVersionKey), - HostRoot: viper.GetString(DriverHostRootKey), - } - return drvCfg, nil + return repos, nil } // StoreDriver stores a driver conf in config file. func StoreDriver(driverCfg *Driver, configFile string) error { - drvCfg := driver{ - Type: driverCfg.Type.String(), - Name: driverCfg.Name, - Repos: driverCfg.Repos, - Version: driverCfg.Version, - HostRoot: driverCfg.HostRoot, - } - - if err := UpdateConfigFile(DriverKey, drvCfg, configFile); err != nil { + if err := UpdateConfigFile(DriverKey, driverCfg, configFile); err != nil { return fmt.Errorf("unable to update driver in the config file %q: %w", configFile, err) } return nil diff --git a/pkg/options/driver.go b/pkg/options/driver.go index 629818d6..697dfca1 100644 --- a/pkg/options/driver.go +++ b/pkg/options/driver.go @@ -16,8 +16,11 @@ package options import ( + "fmt" + "path/filepath" "sort" + "github.com/falcosecurity/falcoctl/internal/config" drivertype "github.com/falcosecurity/falcoctl/pkg/driver/type" ) @@ -34,3 +37,31 @@ func NewDriverTypes() *DriverTypes { Enum: NewEnum(types, drivertype.TypeKmod), } } + +// Driver defines options that are common while interacting with driver commands. +type Driver struct { + Type drivertype.DriverType + Name string + Repos []string + Version string + HostRoot string +} + +// ToDriverConfig maps a Driver options to Driver config struct. +func (d *Driver) ToDriverConfig() *config.Driver { + return &config.Driver{ + Type: d.Type.String(), + Name: d.Name, + Repos: d.Repos, + Version: d.Version, + HostRoot: d.HostRoot, + } +} + +// Validate runs all validators steps for Driver options. +func (d *Driver) Validate() error { + if !filepath.IsAbs(d.HostRoot) { + return fmt.Errorf("host-root must be an absolute path: %s", d.HostRoot) + } + return nil +} From 83db87cf6c0f7dd6ec08275631d7715d9b8f92d0 Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Wed, 6 Dec 2023 09:14:01 +0100 Subject: [PATCH 2/2] chore(cmd,pkg): properly preload driver version for all drivers commands. Moreover, enforce that driver version is a semver and repos is a list of requestURI. Signed-off-by: Federico Di Pierro --- cmd/driver/config/config_test.go | 2 +- cmd/driver/driver_linux.go | 31 ++++++++++++++++++++++++++++++- cmd/driver/install/install.go | 29 ----------------------------- pkg/options/driver.go | 17 ++++++++++++++++- 4 files changed, 47 insertions(+), 32 deletions(-) diff --git a/cmd/driver/config/config_test.go b/cmd/driver/config/config_test.go index 34ae301b..1acc1a3e 100644 --- a/cmd/driver/config/config_test.go +++ b/cmd/driver/config/config_test.go @@ -92,7 +92,7 @@ var _ = Describe("config", func() { BeforeEach(func() { args = []string{driverCmd, configCmd, "--config", configFile, "--host-root", "foo/"} }) - addAssertFailedBehavior("ERROR host-root must be an absolute path: foo/") + addAssertFailedBehavior("ERROR host-root must be an absolute path (foo/)") }) When("with invalid driver type", func() { diff --git a/cmd/driver/driver_linux.go b/cmd/driver/driver_linux.go index 4da826f2..5d0d3a90 100644 --- a/cmd/driver/driver_linux.go +++ b/cmd/driver/driver_linux.go @@ -22,7 +22,10 @@ import ( "context" "errors" "fmt" + "path/filepath" + "strings" + "github.com/blang/semver" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -76,7 +79,7 @@ func NewDriverCmd(ctx context.Context, opt *options.Common) *cobra.Command { if err != nil { return err } - if err := cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val)); err != nil { + if err := cmd.Flags().Set(f.Name, strings.Join(val, ",")); err != nil { return fmt.Errorf("unable to overwrite \"repo\" flag: %w", err) } } @@ -149,6 +152,11 @@ func NewDriverCmd(ctx context.Context, opt *options.Common) *cobra.Command { return fmt.Errorf("automatic driver selection failed") } } + // If empty, try to load it automatically from /usr/src sub folders, + // using the most recent (ie: the one with greatest semver) driver version. + if driver.Version == "" { + driver.Version = loadDriverVersion() + } return driver.Validate() }, } @@ -165,3 +173,24 @@ func NewDriverCmd(ctx context.Context, opt *options.Common) *cobra.Command { cmd.AddCommand(driverprintenv.NewDriverPrintenvCmd(ctx, opt, driver)) return cmd } + +func loadDriverVersion() string { + isSet := false + greatestVrs := semver.Version{} + paths, _ := filepath.Glob("/usr/src/falco-*+driver") + for _, path := range paths { + drvVer := strings.TrimPrefix(filepath.Base(path), "falco-") + sv, err := semver.Parse(drvVer) + if err != nil { + continue + } + if sv.GT(greatestVrs) { + greatestVrs = sv + isSet = true + } + } + if isSet { + return greatestVrs.String() + } + return "" +} diff --git a/cmd/driver/install/install.go b/cmd/driver/install/install.go index 8db73ade..3f9f61f3 100644 --- a/cmd/driver/install/install.go +++ b/cmd/driver/install/install.go @@ -20,11 +20,8 @@ import ( "errors" "fmt" "net/http" - "path/filepath" - "strings" "time" - "github.com/blang/semver" "github.com/spf13/cobra" "golang.org/x/net/context" @@ -65,11 +62,6 @@ func NewDriverInstallCmd(ctx context.Context, opt *options.Common, driver *optio Long: `[Preview] Install previously configured driver, either downloading it or attempting a build. ** This command is in preview and under development. **`, RunE: func(cmd *cobra.Command, args []string) error { - // If empty, try to load it automatically from /usr/src sub folders, - // using the most recent (ie: the one with greatest semver) driver version. - if o.Driver.Version == "" { - o.Driver.Version = loadDriverVersion() - } dest, err := o.RunDriverInstall(ctx) if dest != "" { // We don't care about errors at this stage @@ -100,27 +92,6 @@ func NewDriverInstallCmd(ctx context.Context, opt *options.Common, driver *optio return cmd } -func loadDriverVersion() string { - isSet := false - greatestVrs := semver.Version{} - paths, _ := filepath.Glob("/usr/src/falco-*+driver") - for _, path := range paths { - drvVer := strings.TrimPrefix(filepath.Base(path), "falco-") - sv, err := semver.Parse(drvVer) - if err != nil { - continue - } - if sv.GT(greatestVrs) { - greatestVrs = sv - isSet = true - } - } - if isSet { - return greatestVrs.String() - } - return "" -} - //nolint:gosec // this was an existent option in falco-driver-loader that we are porting. func setDefaultHTTPClientOpts(downloadOptions driverDownloadOptions) { // Skip insecure verify diff --git a/pkg/options/driver.go b/pkg/options/driver.go index 697dfca1..780ca6d1 100644 --- a/pkg/options/driver.go +++ b/pkg/options/driver.go @@ -17,9 +17,12 @@ package options import ( "fmt" + "net/url" "path/filepath" "sort" + "github.com/blang/semver" + "github.com/falcosecurity/falcoctl/internal/config" drivertype "github.com/falcosecurity/falcoctl/pkg/driver/type" ) @@ -61,7 +64,19 @@ func (d *Driver) ToDriverConfig() *config.Driver { // Validate runs all validators steps for Driver options. func (d *Driver) Validate() error { if !filepath.IsAbs(d.HostRoot) { - return fmt.Errorf("host-root must be an absolute path: %s", d.HostRoot) + return fmt.Errorf("host-root must be an absolute path (%s)", d.HostRoot) + } + + if _, err := semver.Parse(d.Version); err != nil { + return fmt.Errorf("version must be semver compatible (%s): %w", d.Version, err) } + + for _, repo := range d.Repos { + _, err := url.ParseRequestURI(repo) + if err != nil { + return fmt.Errorf("repo must be a valid url (%s): %w", repo, err) + } + } + return nil }