Allow feature.yml to change available subcommands (#2156)

This commit is contained in:
mmetc 2023-04-03 10:11:56 +02:00 committed by GitHub
parent 3fa555fb25
commit 38ab6be7c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 57 additions and 46 deletions

View file

@ -209,6 +209,21 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
log.Fatalf("failed to hide flag: %s", err)
}
// Look for "-c /path/to/config.yaml"
// This duplicates the logic in cobra, but we need to do it before
// because feature flags can change which subcommands are available.
for i, arg := range os.Args {
if arg == "-c" || arg == "--config" {
if len(os.Args) > i+1 {
ConfigFilePath = os.Args[i+1]
}
}
}
if err := csconfig.LoadFeatureFlagsFile(ConfigFilePath, log.StandardLogger()); err != nil {
log.Fatal(err)
}
if len(os.Args) > 1 {
cobra.OnInitialize(initConfig)
}
@ -249,7 +264,6 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
}
if err := rootCmd.Execute(); err != nil {
log.NewEntry(log.StandardLogger()).Log(log.FatalLevel, err)
os.Exit(1)
log.Fatal(err)
}
}

View file

@ -191,9 +191,14 @@ func newLogLevel(curLevelPtr *log.Level, f *Flags) *log.Level {
}
// LoadConfig returns a configuration parsed from configuration file
func LoadConfig(cConfig *csconfig.Config) error {
func LoadConfig(configFile string, disableAgent bool, disableAPI bool, quiet bool) (*csconfig.Config, error) {
cConfig, err := csconfig.NewConfig(configFile, disableAgent, disableAPI, quiet)
if err != nil {
return nil, err
}
if (cConfig.Common == nil || *cConfig.Common == csconfig.CommonCfg{}) {
return fmt.Errorf("unable to load configuration: common section is empty")
return nil, fmt.Errorf("unable to load configuration: common section is empty")
}
cConfig.Common.LogLevel = newLogLevel(cConfig.Common.LogLevel, flags)
@ -207,7 +212,7 @@ func LoadConfig(cConfig *csconfig.Config) error {
// Configuration paths are dependency to load crowdsec configuration
if err := cConfig.LoadConfigurationPaths(); err != nil {
return err
return nil, err
}
if flags.SingleFileType != "" && flags.OneShotDSN != "" {
@ -221,31 +226,31 @@ func LoadConfig(cConfig *csconfig.Config) error {
cConfig.Common.LogMaxSize, cConfig.Common.LogMaxFiles,
cConfig.Common.LogMaxAge, cConfig.Common.CompressLogs,
cConfig.Common.ForceColorLogs); err != nil {
return err
return nil, err
}
if err := csconfig.LoadFeatureFlagsFile(cConfig, log.StandardLogger()); err != nil {
return err
if err := csconfig.LoadFeatureFlagsFile(configFile, log.StandardLogger()); err != nil {
return nil, err
}
if !flags.DisableAgent {
if err := cConfig.LoadCrowdsec(); err != nil {
return err
return nil, err
}
}
if !flags.DisableAPI {
if err := cConfig.LoadAPIServer(); err != nil {
return err
return nil, err
}
}
if !cConfig.DisableAgent && (cConfig.API == nil || cConfig.API.Client == nil || cConfig.API.Client.Credentials == nil) {
return errors.New("missing local API credentials for crowdsec agent, abort")
return nil, errors.New("missing local API credentials for crowdsec agent, abort")
}
if cConfig.DisableAPI && cConfig.DisableAgent {
return errors.New("You must run at least the API Server or crowdsec")
return nil, errors.New("You must run at least the API Server or crowdsec")
}
if flags.TestMode && !cConfig.DisableAgent {
@ -253,15 +258,15 @@ func LoadConfig(cConfig *csconfig.Config) error {
}
if flags.OneShotDSN != "" && flags.SingleFileType == "" {
return errors.New("-dsn requires a -type argument")
return nil, errors.New("-dsn requires a -type argument")
}
if flags.Transform != "" && flags.OneShotDSN == "" {
return errors.New("-transform requires a -dsn argument")
return nil, errors.New("-transform requires a -dsn argument")
}
if flags.SingleFileType != "" && flags.OneShotDSN == "" {
return errors.New("-type requires a -dsn argument")
return nil, errors.New("-type requires a -dsn argument")
}
if flags.SingleFileType != "" && flags.OneShotDSN != "" {
@ -290,7 +295,7 @@ func LoadConfig(cConfig *csconfig.Config) error {
log.Infof("Enabled feature flags: %s", fflist)
}
return nil
return cConfig, nil
}
// crowdsecT0 can be used to measure start time of services,

View file

@ -34,11 +34,7 @@ func StartRunSvc() error {
},
})
cConfig, err = csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false)
if err != nil {
return err
}
if err := LoadConfig(cConfig); err != nil {
if cConfig, err = LoadConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false); err != nil {
return err
}

View file

@ -61,13 +61,10 @@ func WindowsRun() error {
err error
)
cConfig, err = csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false)
cConfig, err = LoadConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false)
if err != nil {
return err
}
if err := LoadConfig(cConfig); err != nil {
return err
}
// Configure logging
log.Infof("Crowdsec %s", cwversion.VersionStr())

View file

@ -54,15 +54,11 @@ func reloadHandler(sig os.Signal) (*csconfig.Config, error) {
crowdsecTomb = tomb.Tomb{}
pluginTomb = tomb.Tomb{}
cConfig, err := csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false)
cConfig, err := LoadConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false)
if err != nil {
return nil, err
}
if err = LoadConfig(cConfig); err != nil {
return nil, err
}
if !cConfig.DisableAPI {
if flags.DisableCAPI {
log.Warningf("Communication with CrowdSec Central API disabled from args")

View file

@ -97,15 +97,11 @@ func runService(name string) error {
log.Warnf("Failed to open event log: %s", err)
}
cConfig, err := csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false)
cConfig, err := LoadConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false)
if err != nil {
return err
}
if err := LoadConfig(cConfig); err != nil {
return err
}
log.Infof("starting %s service", name)
winsvc := crowdsec_winservice{config: cConfig}

View file

@ -1,9 +1,5 @@
package csconfig
import (
log "github.com/sirupsen/logrus"
)
/*cscli specific config, such as hub directory*/
type CscliCfg struct {
Output string `yaml:"output,omitempty"`
@ -26,9 +22,6 @@ func (c *Config) LoadCSCLI() error {
if err := c.LoadConfigurationPaths(); err != nil {
return err
}
if err := LoadFeatureFlagsFile(c, log.StandardLogger()); err != nil {
return err
}
c.Cscli.ConfigDir = c.ConfigPaths.ConfigDir
c.Cscli.DataDir = c.ConfigPaths.DataDir
c.Cscli.HubDir = c.ConfigPaths.HubDir

View file

@ -20,9 +20,12 @@ func LoadFeatureFlagsEnv(logger *log.Logger) error {
}
// LoadFeatureFlags parses {ConfigDir}/feature.yaml to enable feature flags.
func LoadFeatureFlagsFile(cConfig *Config, logger *log.Logger) error {
featurePath := filepath.Join(cConfig.ConfigPaths.ConfigDir, "feature.yaml")
// LoadFeatureFlags parses feature.yaml to enable feature flags.
// The file is in the same directory as config.yaml, which is provided
// as the fist parameter. This can be different than ConfigPaths.ConfigDir
func LoadFeatureFlagsFile(configPath string, logger *log.Logger) error {
dir := filepath.Dir(configPath)
featurePath := filepath.Join(dir, "feature.yaml")
if err := fflag.Crowdsec.SetFromYamlFile(featurePath, logger); err != nil {
return fmt.Errorf("file %s: %s", featurePath, err)

View file

@ -282,7 +282,7 @@ teardown() {
assert_output - <"$BATS_TEST_DIRNAME"/testdata/explain/explain-log.txt
}
@test "Allow variable expansion and literal \$ characters in passwords' {
@test 'Allow variable expansion and literal $ characters in passwords' {
export DB_PASSWORD='P@ssw0rd'
# shellcheck disable=SC2016
config_set '.db_config.password="$DB_PASSWORD"'
@ -321,3 +321,14 @@ teardown() {
rune -0 cscli doc
assert_file_exist "doc/cscli_setup.md"
}
@test "feature.yaml for subcommands" {
# it is possible to enable subcommands with feature flags defined in feature.yaml
rune -1 cscli setup
assert_stderr --partial 'unknown command \"setup\" for \"cscli\"'
CONFIG_DIR=$(dirname "$CONFIG_YAML")
echo ' - cscli_setup' >> "$CONFIG_DIR"/feature.yaml
rune -0 cscli setup
assert_output --partial 'cscli setup [command]'
}