// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package healthcheck import ( "fmt" "time" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/go-secure-stdlib/parseutil" ) type EnableAutoTidy struct { Enabled bool UnsupportedVersion bool IntervalDurationCritical time.Duration IntervalDurationWarning time.Duration PauseDurationCritical time.Duration PauseDurationWarning time.Duration TidyConfig *PathFetch } func NewEnableAutoTidyCheck() Check { return &EnableAutoTidy{} } func (h *EnableAutoTidy) Name() string { return "enable_auto_tidy" } func (h *EnableAutoTidy) IsEnabled() bool { return h.Enabled } func (h *EnableAutoTidy) DefaultConfig() map[string]interface{} { return map[string]interface{}{ "interval_duration_critical": "7d", "interval_duration_warning": "2d", "pause_duration_critical": "1s", "pause_duration_warning": "200ms", } } func (h *EnableAutoTidy) fromConfig(config map[string]interface{}, param string) (time.Duration, error) { value, err := parseutil.ParseDurationSecond(config[param]) if err != nil { return time.Duration(0), fmt.Errorf("failed to parse parameter %v.%v=%v: %w", h.Name(), param, config[param], err) } return value, nil } func (h *EnableAutoTidy) LoadConfig(config map[string]interface{}) error { var err error h.IntervalDurationCritical, err = h.fromConfig(config, "interval_duration_critical") if err != nil { return err } h.IntervalDurationWarning, err = h.fromConfig(config, "interval_duration_warning") if err != nil { return err } h.PauseDurationCritical, err = h.fromConfig(config, "pause_duration_critical") if err != nil { return err } h.PauseDurationWarning, err = h.fromConfig(config, "pause_duration_warning") if err != nil { return err } enabled, err := parseutil.ParseBool(config["enabled"]) if err != nil { return fmt.Errorf("error parsing %v.enabled: %w", h.Name(), err) } h.Enabled = enabled return nil } func (h *EnableAutoTidy) FetchResources(e *Executor) error { var err error h.TidyConfig, err = e.FetchIfNotFetched(logical.ReadOperation, "/{{mount}}/config/auto-tidy") if err != nil { return err } if h.TidyConfig.IsUnsupportedPathError() { h.UnsupportedVersion = true } return nil } func (h *EnableAutoTidy) Evaluate(e *Executor) (results []*Result, err error) { if h.UnsupportedVersion { ret := Result{ Status: ResultInvalidVersion, Endpoint: "/{{mount}}/config/auto-tidy", Message: "This health check requires Vault 1.12+, but an earlier version of Vault Server was contacted, preventing this health check from running.", } return []*Result{&ret}, nil } if h.TidyConfig == nil { return } if h.TidyConfig.IsSecretPermissionsError() { ret := Result{ Status: ResultInsufficientPermissions, Endpoint: "/{{mount}}/config/auto-tidy", Message: "This prevents the health check from functioning at all, as it cannot .", } if e.Client.Token() == "" { ret.Message = "No token available so unable read authenticated auto-tidy configuration for this mount. " + ret.Message } else { ret.Message = "This token lacks permission to read the auto-tidy configuration for this mount. " + ret.Message } return []*Result{&ret}, nil } isEnabled := h.TidyConfig.Secret.Data["enabled"].(bool) intervalDuration, err := parseutil.ParseDurationSecond(h.TidyConfig.Secret.Data["interval_duration"]) if err != nil { return nil, fmt.Errorf("error parsing API response from server for interval_duration: %w", err) } pauseDuration, err := parseutil.ParseDurationSecond(h.TidyConfig.Secret.Data["pause_duration"]) if err != nil { return nil, fmt.Errorf("error parsing API response from server for pause_duration: %w", err) } if !isEnabled { ret := Result{ Status: ResultInformational, Endpoint: "/{{mount}}/config/auto-tidy", Message: "Auto-tidy is currently disabled; consider enabling auto-tidy to execute tidy operations periodically. This helps the health and performance of a mount.", } results = append(results, &ret) } else { baseMsg := "Auto-tidy is configured with too long of a value for %v (%v); this could impact performance as tidies run too infrequently or take too long to execute." if intervalDuration >= h.IntervalDurationCritical { ret := Result{ Status: ResultCritical, Endpoint: "/{{mount}}/config/auto-tidy", Message: fmt.Sprintf(baseMsg, "interval_duration", intervalDuration), } results = append(results, &ret) } else if intervalDuration >= h.IntervalDurationWarning { ret := Result{ Status: ResultWarning, Endpoint: "/{{mount}}/config/auto-tidy", Message: fmt.Sprintf(baseMsg, "interval_duration", intervalDuration), } results = append(results, &ret) } if pauseDuration >= h.PauseDurationCritical { ret := Result{ Status: ResultCritical, Endpoint: "/{{mount}}/config/auto-tidy", Message: fmt.Sprintf(baseMsg, "pause_duration", pauseDuration), } results = append(results, &ret) } else if pauseDuration >= h.PauseDurationWarning { ret := Result{ Status: ResultWarning, Endpoint: "/{{mount}}/config/auto-tidy", Message: fmt.Sprintf(baseMsg, "pause_duration", pauseDuration), } results = append(results, &ret) } if len(results) == 0 { ret := Result{ Status: ResultOK, Endpoint: "/{{mount}}/config/auto-tidy", Message: "Auto-tidy is enabled and configured appropriately.", } results = append(results, &ret) } } return }