diff --git a/pkg/env/alert_renotif_debounce.go b/pkg/env/alert_renotif_debounce.go index 2b8d0f9a3314f..5a89a23a82332 100644 --- a/pkg/env/alert_renotif_debounce.go +++ b/pkg/env/alert_renotif_debounce.go @@ -5,5 +5,5 @@ var ( // between an alert being resolved, and a new alert being generated for the same deployment-policy pair, // such that notifications are sent for the new alert. // If it is set to 0 (the default), notifications are always sent, and there is no debouncing. - AlertRenotifDebounceDuration = registerDurationSetting("ROX_ALERT_RENOTIF_DEBOUNCE_DURATION", 0) + AlertRenotifDebounceDuration = registerDurationSetting("ROX_ALERT_RENOTIF_DEBOUNCE_DURATION", 0, WithDurationZeroAllowed()) ) diff --git a/pkg/env/durationsetting.go b/pkg/env/durationsetting.go index 6c10305427d38..289fcdacae001 100644 --- a/pkg/env/durationsetting.go +++ b/pkg/env/durationsetting.go @@ -1,10 +1,12 @@ package env import ( + "fmt" "os" "time" "github.com/stackrox/rox/pkg/logging" + "github.com/stackrox/rox/pkg/utils" ) var ( @@ -15,6 +17,7 @@ var ( type DurationSetting struct { envVar string defaultDuration time.Duration + opts durationSettingOpts } // EnvVar returns the string name of the environment variable @@ -32,20 +35,39 @@ func (d *DurationSetting) DurationSetting() time.Duration { val := os.Getenv(d.envVar) if val != "" { dur, err := time.ParseDuration(val) - if err == nil { + if err == nil && validateDuration(dur, d.opts) == nil { return dur } - log.Warnf("%s is not a valid environment variable for %s, using default value: %s", val, d.envVar, d.defaultDuration.String()) + log.Warnf("%s is not a valid environment variable for %s, using default value: %v", val, d.envVar, d.defaultDuration) } return d.defaultDuration } -func registerDurationSetting(envVar string, defaultDuration time.Duration) *DurationSetting { +func registerDurationSetting(envVar string, defaultDuration time.Duration, options ...DurationSettingOption) *DurationSetting { + var opts durationSettingOpts + for _, o := range options { + o.apply(&opts) + } + + utils.CrashOnError(validateDuration(defaultDuration, opts)) + s := &DurationSetting{ envVar: envVar, defaultDuration: defaultDuration, + opts: opts, } Settings[s.EnvVar()] = s return s } + +func validateDuration(d time.Duration, opts durationSettingOpts) error { + if d < 0 { + return fmt.Errorf("invalid duration: %v < 0", d) + } + if !opts.zeroAllowed && d == 0 { + return fmt.Errorf("invalid duration: %v == 0", d) + } + + return nil +} diff --git a/pkg/env/durationsetting_options.go b/pkg/env/durationsetting_options.go new file mode 100644 index 0000000000000..7cc10fac6b95d --- /dev/null +++ b/pkg/env/durationsetting_options.go @@ -0,0 +1,24 @@ +package env + +type durationSettingOpts struct { + zeroAllowed bool +} + +// DurationSettingOption represents an option which may be specified +// for a DurationSetting environment variable. +type DurationSettingOption interface { + apply(opts *durationSettingOpts) +} + +type durationSettingOptsFunc func(opts *durationSettingOpts) + +func (f durationSettingOptsFunc) apply(opts *durationSettingOpts) { + f(opts) +} + +// WithDurationZeroAllowed specifies the DurationSetting may have a value of 0. +func WithDurationZeroAllowed() DurationSettingOption { + return durationSettingOptsFunc(func(opts *durationSettingOpts) { + opts.zeroAllowed = true + }) +}