forked from letsencrypt/boulder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobs_conf.go
137 lines (122 loc) · 3.6 KB
/
obs_conf.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package observer
import (
"errors"
"fmt"
"net"
"strconv"
"github.com/letsencrypt/boulder/cmd"
"github.com/prometheus/client_golang/prometheus"
)
var (
countMonitors = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "obs_monitors",
Help: "details of each configured monitor",
},
[]string{"kind", "valid"},
)
histObservations *prometheus.HistogramVec
)
// ObsConf is exported to receive YAML configuration.
type ObsConf struct {
DebugAddr string `yaml:"debugaddr"`
Buckets []float64 `yaml:"buckets"`
Syslog cmd.SyslogConfig `yaml:"syslog"`
MonConfs []*MonConf `yaml:"monitors"`
}
// validateSyslog ensures the the `Syslog` field received by `ObsConf`
// contains valid log levels.
func (c *ObsConf) validateSyslog() error {
syslog, stdout := c.Syslog.SyslogLevel, c.Syslog.StdoutLevel
if stdout < 0 || stdout > 7 || syslog < 0 || syslog > 7 {
return fmt.Errorf(
"invalid 'syslog', '%+v', valid log levels are 0-7", c.Syslog)
}
return nil
}
// validateDebugAddr ensures the `debugAddr` received by `ObsConf` is
// properly formatted and a valid port.
func (c *ObsConf) validateDebugAddr() error {
_, p, err := net.SplitHostPort(c.DebugAddr)
if err != nil {
return fmt.Errorf(
"invalid 'debugaddr', %q, not expected format", c.DebugAddr)
}
port, _ := strconv.Atoi(p)
if port <= 0 || port > 65535 {
return fmt.Errorf(
"invalid 'debugaddr','%d' is not a valid port", port)
}
return nil
}
func (c *ObsConf) makeMonitors() ([]*monitor, []error, error) {
var errs []error
var monitors []*monitor
for e, m := range c.MonConfs {
entry := strconv.Itoa(e + 1)
monitor, err := m.makeMonitor()
if err != nil {
// append validation error to errs
errs = append(
errs, fmt.Errorf(
"'monitors' entry #%s couldn't be validated: %v", entry, err))
// increment metrics
countMonitors.WithLabelValues(m.Kind, "false").Inc()
} else {
// append monitor to monitors
monitors = append(monitors, monitor)
// increment metrics
countMonitors.WithLabelValues(m.Kind, "true").Inc()
}
}
if len(c.MonConfs) == len(errs) {
return nil, errs, errors.New("no valid monitors, cannot continue")
}
return monitors, errs, nil
}
// MakeObserver constructs an `Observer` object from the contents of the
// bound `ObsConf`. If the `ObsConf` cannot be validated, an error
// appropriate for end-user consumption is returned instead.
func (c *ObsConf) MakeObserver() (*Observer, error) {
err := c.validateSyslog()
if err != nil {
return nil, err
}
err = c.validateDebugAddr()
if err != nil {
return nil, err
}
if len(c.MonConfs) == 0 {
return nil, errors.New("no monitors provided")
}
if len(c.Buckets) == 0 {
return nil, errors.New("no histogram buckets provided")
}
// Start monitoring and logging.
metrics, logger := cmd.StatsAndLogging(c.Syslog, c.DebugAddr)
histObservations = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "obs_observations",
Help: "details of each probe attempt",
Buckets: c.Buckets,
}, []string{"name", "kind", "success"})
metrics.MustRegister(countMonitors)
metrics.MustRegister(histObservations)
defer logger.AuditPanic()
logger.Info(cmd.VersionString())
logger.Infof("Initializing boulder-observer daemon")
logger.Debugf("Using config: %+v", c)
monitors, errs, err := c.makeMonitors()
if len(errs) != 0 {
logger.Errf("%d of %d monitors failed validation", len(errs), len(c.MonConfs))
for _, err := range errs {
logger.Errf("%s", err)
}
} else {
logger.Info("all monitors passed validation")
}
if err != nil {
return nil, err
}
return &Observer{logger, monitors}, nil
}