huge refactor
- extendable backends - better project structure - better cli interface
This commit is contained in:
124
monitors/http.go
Normal file
124
monitors/http.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package monitors
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Investigating template
|
||||
var defaultHTTPInvestigatingTpl = MessageTemplate{
|
||||
Subject: `{{ .Monitor.Name }} - {{ .SystemName }}`,
|
||||
Message: `{{ .Monitor.Name }} HTTP check **failed** (server time: {{ .now }})
|
||||
|
||||
{{ .FailReason }}`,
|
||||
}
|
||||
|
||||
// Fixed template
|
||||
var defaultHTTPFixedTpl = MessageTemplate{
|
||||
Subject: `{{ .Monitor.Name }} - {{ .SystemName }}`,
|
||||
Message: `**Resolved** - {{ .now }}
|
||||
|
||||
- - -
|
||||
|
||||
{{ .incident.Message }}`,
|
||||
}
|
||||
|
||||
type HTTPMonitor struct {
|
||||
AbstractMonitor `mapstructure:",squash"`
|
||||
|
||||
Method string
|
||||
ExpectedStatusCode int `mapstructure:"expected_status_code"`
|
||||
Headers map[string]string
|
||||
|
||||
// compiled to Regexp
|
||||
ExpectedBody string `mapstructure:"expected_body"`
|
||||
bodyRegexp *regexp.Regexp
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
func (monitor *HTTPMonitor) test() (bool, []error) {
|
||||
req, err := http.NewRequest(monitor.Method, monitor.Target, nil)
|
||||
for k, v := range monitor.Headers {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
|
||||
transport := http.DefaultTransport.(*http.Transport)
|
||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: monitor.Strict == false}
|
||||
client := &http.Client{
|
||||
Timeout: time.Duration(monitor.Timeout * time.Second),
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return false, []error{err}
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if monitor.ExpectedStatusCode > 0 && resp.StatusCode != monitor.ExpectedStatusCode {
|
||||
fail := "Expected HTTP response status: " + strconv.Itoa(monitor.ExpectedStatusCode) + ", got: " + strconv.Itoa(resp.StatusCode)
|
||||
return false, []error{errors.New(fail)}
|
||||
}
|
||||
|
||||
if monitor.bodyRegexp != nil {
|
||||
// check response body
|
||||
responseBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, []error{err}
|
||||
}
|
||||
|
||||
if !monitor.bodyRegexp.Match(responseBody) {
|
||||
fail := "Unexpected body: " + string(responseBody) + ".\nExpected to match: " + monitor.ExpectedBody
|
||||
return false, []error{errors.New(fail)}
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
func (mon *HTTPMonitor) Validate(validate backendValidateFunc) []string {
|
||||
mon.Template.Investigating.SetDefault(defaultHTTPInvestigatingTpl)
|
||||
mon.Template.Fixed.SetDefault(defaultHTTPFixedTpl)
|
||||
|
||||
errs := mon.AbstractMonitor.Validate(validate)
|
||||
|
||||
if len(mon.ExpectedBody) > 0 {
|
||||
exp, err := regexp.Compile(mon.ExpectedBody)
|
||||
if err != nil {
|
||||
errs = append(errs, "Regexp compilation failure: "+err.Error())
|
||||
} else {
|
||||
mon.bodyRegexp = exp
|
||||
}
|
||||
}
|
||||
|
||||
if len(mon.ExpectedBody) == 0 && mon.ExpectedStatusCode == 0 {
|
||||
errs = append(errs, "Both 'expected_body' and 'expected_status_code' fields empty")
|
||||
}
|
||||
|
||||
mon.Method = strings.ToUpper(mon.Method)
|
||||
switch mon.Method {
|
||||
case "GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD":
|
||||
break
|
||||
case "":
|
||||
mon.Method = "GET"
|
||||
default:
|
||||
errs = append(errs, "Unsupported HTTP method: "+mon.Method)
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func (mon *HTTPMonitor) Describe() []string {
|
||||
features := mon.AbstractMonitor.Describe()
|
||||
features = append(features, "Method: "+mon.Method)
|
||||
|
||||
return features
|
||||
}
|
||||
Reference in New Issue
Block a user