github.com/helmwave/helmwave@v0.36.4-0.20240509190856-b35563eba4c6/pkg/monitor/config.go (about) 1 package monitor 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/helmwave/helmwave/pkg/monitor/http" 9 "github.com/helmwave/helmwave/pkg/monitor/prometheus" 10 log "github.com/sirupsen/logrus" 11 "gopkg.in/yaml.v3" 12 ) 13 14 const ( 15 DefaultTotalTimeout = time.Minute * 5 16 DefaultIterationTimeout = time.Second * 10 17 DefaultInterval = time.Minute 18 DefaultSuccessThreshold = 3 19 DefaultFailureThreshold = 3 20 ) 21 22 // Config is the main monitor Config. 23 type config struct { 24 Prometheus *prometheus.Config `yaml:"prometheus" json:"prometheus" jsonschema:"title=Config for prometheus type,oneof_required=prometheus"` 25 HTTP *http.Config `yaml:"http" json:"http" jsonschema:"title=Config for http type,oneof_required=http"` 26 subConfig SubConfig `yaml:"-" json:"-"` 27 log *log.Entry `yaml:"-" json:"-"` 28 NameF string `yaml:"name" json:"name" jsonschema:"required"` 29 Type string `yaml:"type" json:"type" jsonschema:"enum=prometheus,enum=http,required"` 30 TotalTimeout time.Duration `yaml:"total_timeout" json:"total_timeout" jsonschema:"title=Timeout for the whole monitor,description=After this timeout hits monitor will fail regardless of current streak,default=5m,oneof_type=string;integer"` 31 IterationTimeout time.Duration `yaml:"iteration_timeout" json:"iteration_timeout" jsonschema:"title=Timeout for each timeout execution,description=After this timeout hits monitor iteration will be considered as failed,default=10s,oneof_type=string;integer"` 32 Interval time.Duration `yaml:"interval" json:"interval" jsonschema:"default=1m,oneof_type=string;integer"` 33 SuccessThreshold uint8 `yaml:"success_threshold" json:"success_threshold" jsonschema:"default=3"` 34 FailureThreshold uint8 `yaml:"failure_threshold" json:"failure_threshold" jsonschema:"default=3"` 35 } 36 37 type typeConfig struct { 38 Type string `yaml:"type" json:"type"` 39 } 40 41 type _config config 42 43 func (c *config) setDefaults() { 44 c.TotalTimeout = DefaultTotalTimeout 45 c.IterationTimeout = DefaultIterationTimeout 46 c.Interval = DefaultInterval 47 c.SuccessThreshold = DefaultSuccessThreshold 48 c.FailureThreshold = DefaultFailureThreshold 49 } 50 51 func (c *config) Name() string { 52 return c.NameF 53 } 54 55 func (c *config) Logger() *log.Entry { 56 if c.log == nil { 57 c.log = log.WithField("monitor", c.Name()) 58 } 59 60 return c.log 61 } 62 63 func (c *config) Run(ctx context.Context) error { 64 ctx, cancel := context.WithTimeout(ctx, c.TotalTimeout) 65 defer cancel() 66 67 c.Logger().Debug("initializing monitor") 68 err := c.subConfig.Init(ctx, c.Logger()) 69 if err != nil { 70 return NewMonitorInitError(err) 71 } 72 73 c.Logger().Debug("starting monitor") 74 75 timer := time.NewTimer(c.Interval) 76 defer timer.Stop() 77 78 var successStreak uint8 = 0 79 var failureStreak uint8 = 0 80 81 for (successStreak < c.SuccessThreshold) && (failureStreak < c.FailureThreshold) { 82 select { 83 case <-timer.C: 84 timer.Reset(c.Interval) 85 ctx, cancel := context.WithTimeout(ctx, c.IterationTimeout) 86 err := c.subConfig.Run(ctx) 87 cancel() 88 89 if err == nil { 90 successStreak += 1 91 failureStreak = 0 92 c.Logger(). 93 WithField("streak", fmt.Sprintf("%d/%d", successStreak, c.SuccessThreshold)). 94 Info("monitor succeeded") 95 } else { 96 successStreak = 0 97 failureStreak += 1 98 c.Logger(). 99 WithField("streak", fmt.Sprintf("%d/%d", failureStreak, c.FailureThreshold)). 100 WithField("error", err). 101 Info("monitor did not succeed") 102 } 103 case <-ctx.Done(): 104 return ctx.Err() 105 } 106 } 107 108 if failureStreak > 0 { 109 return ErrFailureStreak 110 } 111 112 return nil 113 } 114 115 // UnmarshalYAML is an unmarshaller for gopkg.in/yaml.v3 to parse subconfig. 116 func (c *config) UnmarshalYAML(node *yaml.Node) error { 117 t := typeConfig{} 118 err := node.Decode(&t) 119 if err != nil { 120 return NewYAMLDecodeError(err) 121 } 122 123 c.setDefaults() 124 125 cfg := (*_config)(c) 126 127 switch t.Type { 128 case prometheus.TYPE: 129 cfg.Prometheus = prometheus.NewConfig() 130 cfg.subConfig = cfg.Prometheus 131 case http.TYPE: 132 cfg.HTTP = http.NewConfig() 133 cfg.subConfig = cfg.HTTP 134 default: 135 return fmt.Errorf("unknown monitor type %q", t.Type) 136 } 137 138 err = node.Decode(cfg) 139 if err != nil { 140 return NewYAMLDecodeError(err) 141 } 142 143 return nil 144 }