Allow feature.yml to change available subcommands (#2156)
This commit is contained in:
parent
3fa555fb25
commit
38ab6be7c2
|
@ -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)
|
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 {
|
if len(os.Args) > 1 {
|
||||||
cobra.OnInitialize(initConfig)
|
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 {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
log.NewEntry(log.StandardLogger()).Log(log.FatalLevel, err)
|
log.Fatal(err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,9 +191,14 @@ func newLogLevel(curLevelPtr *log.Level, f *Flags) *log.Level {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig returns a configuration parsed from configuration file
|
// 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{}) {
|
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)
|
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
|
// Configuration paths are dependency to load crowdsec configuration
|
||||||
if err := cConfig.LoadConfigurationPaths(); err != nil {
|
if err := cConfig.LoadConfigurationPaths(); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.SingleFileType != "" && flags.OneShotDSN != "" {
|
if flags.SingleFileType != "" && flags.OneShotDSN != "" {
|
||||||
|
@ -221,31 +226,31 @@ func LoadConfig(cConfig *csconfig.Config) error {
|
||||||
cConfig.Common.LogMaxSize, cConfig.Common.LogMaxFiles,
|
cConfig.Common.LogMaxSize, cConfig.Common.LogMaxFiles,
|
||||||
cConfig.Common.LogMaxAge, cConfig.Common.CompressLogs,
|
cConfig.Common.LogMaxAge, cConfig.Common.CompressLogs,
|
||||||
cConfig.Common.ForceColorLogs); err != nil {
|
cConfig.Common.ForceColorLogs); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := csconfig.LoadFeatureFlagsFile(cConfig, log.StandardLogger()); err != nil {
|
if err := csconfig.LoadFeatureFlagsFile(configFile, log.StandardLogger()); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !flags.DisableAgent {
|
if !flags.DisableAgent {
|
||||||
if err := cConfig.LoadCrowdsec(); err != nil {
|
if err := cConfig.LoadCrowdsec(); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !flags.DisableAPI {
|
if !flags.DisableAPI {
|
||||||
if err := cConfig.LoadAPIServer(); err != nil {
|
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) {
|
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 {
|
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 {
|
if flags.TestMode && !cConfig.DisableAgent {
|
||||||
|
@ -253,15 +258,15 @@ func LoadConfig(cConfig *csconfig.Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.OneShotDSN != "" && flags.SingleFileType == "" {
|
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 == "" {
|
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 == "" {
|
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 != "" {
|
if flags.SingleFileType != "" && flags.OneShotDSN != "" {
|
||||||
|
@ -290,7 +295,7 @@ func LoadConfig(cConfig *csconfig.Config) error {
|
||||||
log.Infof("Enabled feature flags: %s", fflist)
|
log.Infof("Enabled feature flags: %s", fflist)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return cConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// crowdsecT0 can be used to measure start time of services,
|
// crowdsecT0 can be used to measure start time of services,
|
||||||
|
|
|
@ -34,11 +34,7 @@ func StartRunSvc() error {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
cConfig, err = csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false)
|
if cConfig, err = LoadConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := LoadConfig(cConfig); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,13 +61,10 @@ func WindowsRun() error {
|
||||||
err 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := LoadConfig(cConfig); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Configure logging
|
// Configure logging
|
||||||
log.Infof("Crowdsec %s", cwversion.VersionStr())
|
log.Infof("Crowdsec %s", cwversion.VersionStr())
|
||||||
|
|
||||||
|
|
|
@ -54,15 +54,11 @@ func reloadHandler(sig os.Signal) (*csconfig.Config, error) {
|
||||||
crowdsecTomb = tomb.Tomb{}
|
crowdsecTomb = tomb.Tomb{}
|
||||||
pluginTomb = 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = LoadConfig(cConfig); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cConfig.DisableAPI {
|
if !cConfig.DisableAPI {
|
||||||
if flags.DisableCAPI {
|
if flags.DisableCAPI {
|
||||||
log.Warningf("Communication with CrowdSec Central API disabled from args")
|
log.Warningf("Communication with CrowdSec Central API disabled from args")
|
||||||
|
|
|
@ -97,15 +97,11 @@ func runService(name string) error {
|
||||||
log.Warnf("Failed to open event log: %s", err)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := LoadConfig(cConfig); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("starting %s service", name)
|
log.Infof("starting %s service", name)
|
||||||
winsvc := crowdsec_winservice{config: cConfig}
|
winsvc := crowdsec_winservice{config: cConfig}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package csconfig
|
package csconfig
|
||||||
|
|
||||||
import (
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*cscli specific config, such as hub directory*/
|
/*cscli specific config, such as hub directory*/
|
||||||
type CscliCfg struct {
|
type CscliCfg struct {
|
||||||
Output string `yaml:"output,omitempty"`
|
Output string `yaml:"output,omitempty"`
|
||||||
|
@ -26,9 +22,6 @@ func (c *Config) LoadCSCLI() error {
|
||||||
if err := c.LoadConfigurationPaths(); err != nil {
|
if err := c.LoadConfigurationPaths(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := LoadFeatureFlagsFile(c, log.StandardLogger()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.Cscli.ConfigDir = c.ConfigPaths.ConfigDir
|
c.Cscli.ConfigDir = c.ConfigPaths.ConfigDir
|
||||||
c.Cscli.DataDir = c.ConfigPaths.DataDir
|
c.Cscli.DataDir = c.ConfigPaths.DataDir
|
||||||
c.Cscli.HubDir = c.ConfigPaths.HubDir
|
c.Cscli.HubDir = c.ConfigPaths.HubDir
|
||||||
|
|
|
@ -20,9 +20,12 @@ func LoadFeatureFlagsEnv(logger *log.Logger) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// LoadFeatureFlags parses {ConfigDir}/feature.yaml to enable feature flags.
|
// LoadFeatureFlags parses feature.yaml to enable feature flags.
|
||||||
func LoadFeatureFlagsFile(cConfig *Config, logger *log.Logger) error {
|
// The file is in the same directory as config.yaml, which is provided
|
||||||
featurePath := filepath.Join(cConfig.ConfigPaths.ConfigDir, "feature.yaml")
|
// 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 {
|
if err := fflag.Crowdsec.SetFromYamlFile(featurePath, logger); err != nil {
|
||||||
return fmt.Errorf("file %s: %s", featurePath, err)
|
return fmt.Errorf("file %s: %s", featurePath, err)
|
||||||
|
|
|
@ -282,7 +282,7 @@ teardown() {
|
||||||
assert_output - <"$BATS_TEST_DIRNAME"/testdata/explain/explain-log.txt
|
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'
|
export DB_PASSWORD='P@ssw0rd'
|
||||||
# shellcheck disable=SC2016
|
# shellcheck disable=SC2016
|
||||||
config_set '.db_config.password="$DB_PASSWORD"'
|
config_set '.db_config.password="$DB_PASSWORD"'
|
||||||
|
@ -321,3 +321,14 @@ teardown() {
|
||||||
rune -0 cscli doc
|
rune -0 cscli doc
|
||||||
assert_file_exist "doc/cscli_setup.md"
|
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]'
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue