agent: support custom header and method for http checks (#3106)
This patch adds support for custom headers and method for HTTP checks. Fixes #2474 Fixes #2657 Fixes #3106
This commit is contained in:
parent
ccfa5dbbac
commit
e206ab5cb6
24
api/agent.go
24
api/agent.go
|
@ -67,17 +67,19 @@ type AgentCheckRegistration struct {
|
||||||
|
|
||||||
// AgentServiceCheck is used to define a node or service level check
|
// AgentServiceCheck is used to define a node or service level check
|
||||||
type AgentServiceCheck struct {
|
type AgentServiceCheck struct {
|
||||||
Script string `json:",omitempty"`
|
Script string `json:",omitempty"`
|
||||||
DockerContainerID string `json:",omitempty"`
|
DockerContainerID string `json:",omitempty"`
|
||||||
Shell string `json:",omitempty"` // Only supported for Docker.
|
Shell string `json:",omitempty"` // Only supported for Docker.
|
||||||
Interval string `json:",omitempty"`
|
Interval string `json:",omitempty"`
|
||||||
Timeout string `json:",omitempty"`
|
Timeout string `json:",omitempty"`
|
||||||
TTL string `json:",omitempty"`
|
TTL string `json:",omitempty"`
|
||||||
HTTP string `json:",omitempty"`
|
HTTP string `json:",omitempty"`
|
||||||
TCP string `json:",omitempty"`
|
Header map[string][]string `json:",omitempty"`
|
||||||
Status string `json:",omitempty"`
|
Method string `json:",omitempty"`
|
||||||
Notes string `json:",omitempty"`
|
TCP string `json:",omitempty"`
|
||||||
TLSSkipVerify bool `json:",omitempty"`
|
Status string `json:",omitempty"`
|
||||||
|
Notes string `json:",omitempty"`
|
||||||
|
TLSSkipVerify bool `json:",omitempty"`
|
||||||
|
|
||||||
// In Consul 0.7 and later, checks that are associated with a service
|
// In Consul 0.7 and later, checks that are associated with a service
|
||||||
// may also contain this optional DeregisterCriticalServiceAfter field,
|
// may also contain this optional DeregisterCriticalServiceAfter field,
|
||||||
|
|
|
@ -1575,6 +1575,8 @@ func (a *Agent) AddCheck(check *structs.HealthCheck, chkType *CheckType, persist
|
||||||
Notify: &a.state,
|
Notify: &a.state,
|
||||||
CheckID: check.CheckID,
|
CheckID: check.CheckID,
|
||||||
HTTP: chkType.HTTP,
|
HTTP: chkType.HTTP,
|
||||||
|
Header: chkType.Header,
|
||||||
|
Method: chkType.Method,
|
||||||
Interval: chkType.Interval,
|
Interval: chkType.Interval,
|
||||||
Timeout: chkType.Timeout,
|
Timeout: chkType.Timeout,
|
||||||
Logger: a.logger,
|
Logger: a.logger,
|
||||||
|
|
|
@ -57,6 +57,8 @@ type CheckType struct {
|
||||||
|
|
||||||
Script string
|
Script string
|
||||||
HTTP string
|
HTTP string
|
||||||
|
Header map[string][]string
|
||||||
|
Method string
|
||||||
TCP string
|
TCP string
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
DockerContainerID string
|
DockerContainerID string
|
||||||
|
@ -347,6 +349,8 @@ type CheckHTTP struct {
|
||||||
Notify CheckNotifier
|
Notify CheckNotifier
|
||||||
CheckID types.CheckID
|
CheckID types.CheckID
|
||||||
HTTP string
|
HTTP string
|
||||||
|
Header map[string][]string
|
||||||
|
Method string
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
Logger *log.Logger
|
Logger *log.Logger
|
||||||
|
@ -429,15 +433,31 @@ func (c *CheckHTTP) run() {
|
||||||
|
|
||||||
// check is invoked periodically to perform the HTTP check
|
// check is invoked periodically to perform the HTTP check
|
||||||
func (c *CheckHTTP) check() {
|
func (c *CheckHTTP) check() {
|
||||||
req, err := http.NewRequest("GET", c.HTTP, nil)
|
method := c.Method
|
||||||
|
if method == "" {
|
||||||
|
method = "GET"
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, c.HTTP, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Printf("[WARN] agent: http request failed '%s': %s", c.HTTP, err)
|
c.Logger.Printf("[WARN] agent: http request failed '%s': %s", c.HTTP, err)
|
||||||
c.Notify.UpdateCheck(c.CheckID, api.HealthCritical, err.Error())
|
c.Notify.UpdateCheck(c.CheckID, api.HealthCritical, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("User-Agent", UserAgent)
|
req.Header = http.Header(c.Header)
|
||||||
req.Header.Set("Accept", "text/plain, text/*, */*")
|
|
||||||
|
// this happens during testing but not in prod
|
||||||
|
if req.Header == nil {
|
||||||
|
req.Header = make(http.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Header.Get("User-Agent") == "" {
|
||||||
|
req.Header.Set("User-Agent", UserAgent)
|
||||||
|
}
|
||||||
|
if req.Header.Get("Accept") == "" {
|
||||||
|
req.Header.Set("Accept", "text/plain, text/*, */*")
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
resp, err := c.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -4,12 +4,14 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -28,7 +30,7 @@ func expectStatus(t *testing.T, script, status string) {
|
||||||
CheckID: types.CheckID("foo"),
|
CheckID: types.CheckID("foo"),
|
||||||
Script: script,
|
Script: script,
|
||||||
Interval: 10 * time.Millisecond,
|
Interval: 10 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
defer check.Stop()
|
defer check.Stop()
|
||||||
|
@ -71,7 +73,7 @@ func TestCheckMonitor_Timeout(t *testing.T) {
|
||||||
Script: "sleep 1 && exit 0",
|
Script: "sleep 1 && exit 0",
|
||||||
Interval: 10 * time.Millisecond,
|
Interval: 10 * time.Millisecond,
|
||||||
Timeout: 5 * time.Millisecond,
|
Timeout: 5 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
defer check.Stop()
|
defer check.Stop()
|
||||||
|
@ -95,7 +97,7 @@ func TestCheckMonitor_RandomStagger(t *testing.T) {
|
||||||
CheckID: types.CheckID("foo"),
|
CheckID: types.CheckID("foo"),
|
||||||
Script: "exit 0",
|
Script: "exit 0",
|
||||||
Interval: 25 * time.Millisecond,
|
Interval: 25 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
defer check.Stop()
|
defer check.Stop()
|
||||||
|
@ -120,7 +122,7 @@ func TestCheckMonitor_LimitOutput(t *testing.T) {
|
||||||
CheckID: types.CheckID("foo"),
|
CheckID: types.CheckID("foo"),
|
||||||
Script: "od -N 81920 /dev/urandom",
|
Script: "od -N 81920 /dev/urandom",
|
||||||
Interval: 25 * time.Millisecond,
|
Interval: 25 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
defer check.Stop()
|
defer check.Stop()
|
||||||
|
@ -140,7 +142,7 @@ func TestCheckTTL(t *testing.T) {
|
||||||
Notify: notif,
|
Notify: notif,
|
||||||
CheckID: types.CheckID("foo"),
|
CheckID: types.CheckID("foo"),
|
||||||
TTL: 100 * time.Millisecond,
|
TTL: 100 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
defer check.Stop()
|
defer check.Stop()
|
||||||
|
@ -178,126 +180,98 @@ func TestCheckTTL(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockHTTPServer(responseCode int) *httptest.Server {
|
func TestCheckHTTP(t *testing.T) {
|
||||||
mux := http.NewServeMux()
|
t.Parallel()
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// Body larger than 4k limit
|
|
||||||
body := bytes.Repeat([]byte{'a'}, 2*CheckBufSize)
|
|
||||||
w.WriteHeader(responseCode)
|
|
||||||
w.Write(body)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
return httptest.NewServer(mux)
|
tests := []struct {
|
||||||
}
|
desc string
|
||||||
|
code int
|
||||||
|
method string
|
||||||
|
header http.Header
|
||||||
|
status string
|
||||||
|
}{
|
||||||
|
// passing
|
||||||
|
{code: 200, status: api.HealthPassing},
|
||||||
|
{code: 201, status: api.HealthPassing},
|
||||||
|
{code: 250, status: api.HealthPassing},
|
||||||
|
{code: 299, status: api.HealthPassing},
|
||||||
|
|
||||||
func mockTLSHTTPServer(responseCode int) *httptest.Server {
|
// warning
|
||||||
mux := http.NewServeMux()
|
{code: 429, status: api.HealthWarning},
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// Body larger than 4k limit
|
|
||||||
body := bytes.Repeat([]byte{'a'}, 2*CheckBufSize)
|
|
||||||
w.WriteHeader(responseCode)
|
|
||||||
w.Write(body)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
return httptest.NewTLSServer(mux)
|
// critical
|
||||||
}
|
{code: 150, status: api.HealthCritical},
|
||||||
|
{code: 199, status: api.HealthCritical},
|
||||||
|
{code: 300, status: api.HealthCritical},
|
||||||
|
{code: 400, status: api.HealthCritical},
|
||||||
|
{code: 500, status: api.HealthCritical},
|
||||||
|
|
||||||
func expectHTTPStatus(t *testing.T, url string, status string) {
|
// custom method
|
||||||
notif := mock.NewNotify()
|
{desc: "custom method GET", code: 200, method: "GET", status: api.HealthPassing},
|
||||||
check := &CheckHTTP{
|
{desc: "custom method POST", code: 200, method: "POST", status: api.HealthPassing},
|
||||||
Notify: notif,
|
{desc: "custom method abc", code: 200, method: "abc", status: api.HealthPassing},
|
||||||
CheckID: types.CheckID("foo"),
|
|
||||||
HTTP: url,
|
// custom header
|
||||||
Interval: 10 * time.Millisecond,
|
{desc: "custom header", code: 200, header: http.Header{"A": []string{"b", "c"}}, status: api.HealthPassing},
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
|
||||||
}
|
}
|
||||||
check.Start()
|
|
||||||
defer check.Stop()
|
for _, tt := range tests {
|
||||||
retry.Run(t, func(r *retry.R) {
|
desc := tt.desc
|
||||||
if got, want := notif.Updates("foo"), 2; got < want {
|
if desc == "" {
|
||||||
r.Fatalf("got %d updates want at least %d", got, want)
|
desc = fmt.Sprintf("code %d -> status %s", tt.code, tt.status)
|
||||||
}
|
}
|
||||||
if got, want := notif.State("foo"), status; got != want {
|
t.Run(desc, func(t *testing.T) {
|
||||||
r.Fatalf("got state %q want %q", got, want)
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
if tt.method != "" && tt.method != r.Method {
|
||||||
// Allow slightly more data than CheckBufSize, for the header
|
w.WriteHeader(999)
|
||||||
if n := len(notif.Output("foo")); n > (CheckBufSize + 256) {
|
return
|
||||||
r.Fatalf("output too long: %d (%d-byte limit)", n, CheckBufSize)
|
}
|
||||||
}
|
if len(tt.header) > 0 && !reflect.DeepEqual(tt.header, r.Header) {
|
||||||
})
|
w.WriteHeader(999)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
// Body larger than 4k limit
|
||||||
|
body := bytes.Repeat([]byte{'a'}, 2*CheckBufSize)
|
||||||
|
w.WriteHeader(tt.code)
|
||||||
|
w.Write(body)
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
func TestCheckHTTPCritical(t *testing.T) {
|
notif := mock.NewNotify()
|
||||||
t.Parallel()
|
check := &CheckHTTP{
|
||||||
// var server *httptest.Server
|
Notify: notif,
|
||||||
|
CheckID: types.CheckID("foo"),
|
||||||
|
HTTP: server.URL,
|
||||||
|
Method: tt.method,
|
||||||
|
Header: tt.header,
|
||||||
|
Interval: 10 * time.Millisecond,
|
||||||
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
|
}
|
||||||
|
check.Start()
|
||||||
|
defer check.Stop()
|
||||||
|
|
||||||
server := mockHTTPServer(150)
|
retry.Run(t, func(r *retry.R) {
|
||||||
expectHTTPStatus(t, server.URL, api.HealthCritical)
|
if got, want := notif.Updates("foo"), 2; got < want {
|
||||||
server.Close()
|
r.Fatalf("got %d updates want at least %d", got, want)
|
||||||
|
}
|
||||||
// 2xx - 1
|
if got, want := notif.State("foo"), tt.status; got != want {
|
||||||
server = mockHTTPServer(199)
|
r.Fatalf("got state %q want %q", got, want)
|
||||||
expectHTTPStatus(t, server.URL, api.HealthCritical)
|
}
|
||||||
server.Close()
|
// Allow slightly more data than CheckBufSize, for the header
|
||||||
|
if n := len(notif.Output("foo")); n > (CheckBufSize + 256) {
|
||||||
// 2xx + 1
|
r.Fatalf("output too long: %d (%d-byte limit)", n, CheckBufSize)
|
||||||
server = mockHTTPServer(300)
|
}
|
||||||
expectHTTPStatus(t, server.URL, api.HealthCritical)
|
})
|
||||||
server.Close()
|
})
|
||||||
|
}
|
||||||
server = mockHTTPServer(400)
|
|
||||||
expectHTTPStatus(t, server.URL, api.HealthCritical)
|
|
||||||
server.Close()
|
|
||||||
|
|
||||||
server = mockHTTPServer(500)
|
|
||||||
expectHTTPStatus(t, server.URL, api.HealthCritical)
|
|
||||||
server.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckHTTPPassing(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
var server *httptest.Server
|
|
||||||
|
|
||||||
server = mockHTTPServer(200)
|
|
||||||
expectHTTPStatus(t, server.URL, api.HealthPassing)
|
|
||||||
server.Close()
|
|
||||||
|
|
||||||
server = mockHTTPServer(201)
|
|
||||||
expectHTTPStatus(t, server.URL, api.HealthPassing)
|
|
||||||
server.Close()
|
|
||||||
|
|
||||||
server = mockHTTPServer(250)
|
|
||||||
expectHTTPStatus(t, server.URL, api.HealthPassing)
|
|
||||||
server.Close()
|
|
||||||
|
|
||||||
server = mockHTTPServer(299)
|
|
||||||
expectHTTPStatus(t, server.URL, api.HealthPassing)
|
|
||||||
server.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckHTTPWarning(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
server := mockHTTPServer(429)
|
|
||||||
expectHTTPStatus(t, server.URL, api.HealthWarning)
|
|
||||||
server.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func mockSlowHTTPServer(responseCode int, sleep time.Duration) *httptest.Server {
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
time.Sleep(sleep)
|
|
||||||
w.WriteHeader(responseCode)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
return httptest.NewServer(mux)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckHTTPTimeout(t *testing.T) {
|
func TestCheckHTTPTimeout(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
server := mockSlowHTTPServer(200, 10*time.Millisecond)
|
timeout := 5 * time.Millisecond
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
|
||||||
|
time.Sleep(2 * timeout)
|
||||||
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
notif := mock.NewNotify()
|
notif := mock.NewNotify()
|
||||||
|
@ -305,9 +279,9 @@ func TestCheckHTTPTimeout(t *testing.T) {
|
||||||
Notify: notif,
|
Notify: notif,
|
||||||
CheckID: types.CheckID("bar"),
|
CheckID: types.CheckID("bar"),
|
||||||
HTTP: server.URL,
|
HTTP: server.URL,
|
||||||
Timeout: 5 * time.Millisecond,
|
Timeout: timeout,
|
||||||
Interval: 10 * time.Millisecond,
|
Interval: 10 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
}
|
}
|
||||||
|
|
||||||
check.Start()
|
check.Start()
|
||||||
|
@ -328,7 +302,7 @@ func TestCheckHTTP_disablesKeepAlives(t *testing.T) {
|
||||||
CheckID: types.CheckID("foo"),
|
CheckID: types.CheckID("foo"),
|
||||||
HTTP: "http://foo.bar/baz",
|
HTTP: "http://foo.bar/baz",
|
||||||
Interval: 10 * time.Second,
|
Interval: 10 * time.Second,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
}
|
}
|
||||||
|
|
||||||
check.Start()
|
check.Start()
|
||||||
|
@ -345,7 +319,7 @@ func TestCheckHTTP_TLSSkipVerify_defaultFalse(t *testing.T) {
|
||||||
CheckID: "foo",
|
CheckID: "foo",
|
||||||
HTTP: "https://foo.bar/baz",
|
HTTP: "https://foo.bar/baz",
|
||||||
Interval: 10 * time.Second,
|
Interval: 10 * time.Second,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
}
|
}
|
||||||
|
|
||||||
check.Start()
|
check.Start()
|
||||||
|
@ -356,6 +330,15 @@ func TestCheckHTTP_TLSSkipVerify_defaultFalse(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mockTLSHTTPServer(code int) *httptest.Server {
|
||||||
|
return httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Body larger than 4k limit
|
||||||
|
body := bytes.Repeat([]byte{'a'}, 2*CheckBufSize)
|
||||||
|
w.WriteHeader(code)
|
||||||
|
w.Write(body)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckHTTP_TLSSkipVerify_true_pass(t *testing.T) {
|
func TestCheckHTTP_TLSSkipVerify_true_pass(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
server := mockTLSHTTPServer(200)
|
server := mockTLSHTTPServer(200)
|
||||||
|
@ -368,7 +351,7 @@ func TestCheckHTTP_TLSSkipVerify_true_pass(t *testing.T) {
|
||||||
CheckID: types.CheckID("skipverify_true"),
|
CheckID: types.CheckID("skipverify_true"),
|
||||||
HTTP: server.URL,
|
HTTP: server.URL,
|
||||||
Interval: 5 * time.Millisecond,
|
Interval: 5 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
TLSSkipVerify: true,
|
TLSSkipVerify: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +380,7 @@ func TestCheckHTTP_TLSSkipVerify_true_fail(t *testing.T) {
|
||||||
CheckID: types.CheckID("skipverify_true"),
|
CheckID: types.CheckID("skipverify_true"),
|
||||||
HTTP: server.URL,
|
HTTP: server.URL,
|
||||||
Interval: 5 * time.Millisecond,
|
Interval: 5 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
TLSSkipVerify: true,
|
TLSSkipVerify: true,
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
|
@ -425,7 +408,7 @@ func TestCheckHTTP_TLSSkipVerify_false(t *testing.T) {
|
||||||
CheckID: types.CheckID("skipverify_false"),
|
CheckID: types.CheckID("skipverify_false"),
|
||||||
HTTP: server.URL,
|
HTTP: server.URL,
|
||||||
Interval: 100 * time.Millisecond,
|
Interval: 100 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
TLSSkipVerify: false,
|
TLSSkipVerify: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,7 +455,7 @@ func expectTCPStatus(t *testing.T, tcp string, status string) {
|
||||||
CheckID: types.CheckID("foo"),
|
CheckID: types.CheckID("foo"),
|
||||||
TCP: tcp,
|
TCP: tcp,
|
||||||
Interval: 10 * time.Millisecond,
|
Interval: 10 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
defer check.Stop()
|
defer check.Stop()
|
||||||
|
@ -649,7 +632,7 @@ func expectDockerCheckStatus(t *testing.T, dockerClient DockerClient, status str
|
||||||
DockerContainerID: "54432bad1fc7",
|
DockerContainerID: "54432bad1fc7",
|
||||||
Shell: "/bin/sh",
|
Shell: "/bin/sh",
|
||||||
Interval: 10 * time.Millisecond,
|
Interval: 10 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
dockerClient: dockerClient,
|
dockerClient: dockerClient,
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
|
@ -711,7 +694,7 @@ func TestDockerCheckDefaultToSh(t *testing.T) {
|
||||||
Script: "/health.sh",
|
Script: "/health.sh",
|
||||||
DockerContainerID: "54432bad1fc7",
|
DockerContainerID: "54432bad1fc7",
|
||||||
Interval: 10 * time.Millisecond,
|
Interval: 10 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
dockerClient: &fakeDockerClientWithNoErrors{},
|
dockerClient: &fakeDockerClientWithNoErrors{},
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
|
@ -733,7 +716,7 @@ func TestDockerCheckUseShellFromEnv(t *testing.T) {
|
||||||
Script: "/health.sh",
|
Script: "/health.sh",
|
||||||
DockerContainerID: "54432bad1fc7",
|
DockerContainerID: "54432bad1fc7",
|
||||||
Interval: 10 * time.Millisecond,
|
Interval: 10 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
dockerClient: &fakeDockerClientWithNoErrors{},
|
dockerClient: &fakeDockerClientWithNoErrors{},
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
|
@ -756,7 +739,7 @@ func TestDockerCheckTruncateOutput(t *testing.T) {
|
||||||
DockerContainerID: "54432bad1fc7",
|
DockerContainerID: "54432bad1fc7",
|
||||||
Shell: "/bin/sh",
|
Shell: "/bin/sh",
|
||||||
Interval: 10 * time.Millisecond,
|
Interval: 10 * time.Millisecond,
|
||||||
Logger: log.New(os.Stderr, UniqueID(), log.LstdFlags),
|
Logger: log.New(ioutil.Discard, UniqueID(), log.LstdFlags),
|
||||||
dockerClient: &fakeDockerClientWithLongOutput{},
|
dockerClient: &fakeDockerClientWithLongOutput{},
|
||||||
}
|
}
|
||||||
check.Start()
|
check.Start()
|
||||||
|
@ -768,5 +751,4 @@ func TestDockerCheckTruncateOutput(t *testing.T) {
|
||||||
if len(notif.Output("foo")) > CheckBufSize+100 {
|
if len(notif.Output("foo")) > CheckBufSize+100 {
|
||||||
t.Fatalf("output size is too long")
|
t.Fatalf("output size is too long")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
@ -1413,83 +1414,97 @@ AFTER_FIX:
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FixupCheckType(raw interface{}) error {
|
var errInvalidHeaderFormat = errors.New("agent: invalid format of 'header' field")
|
||||||
var ttlKey, intervalKey, timeoutKey string
|
|
||||||
const deregisterKey = "DeregisterCriticalServiceAfter"
|
|
||||||
|
|
||||||
// Handle decoding of time durations
|
func FixupCheckType(raw interface{}) error {
|
||||||
rawMap, ok := raw.(map[string]interface{})
|
rawMap, ok := raw.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parseDuration := func(v interface{}) (time.Duration, error) {
|
||||||
|
if v == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
if d, ok := v.(time.Duration); ok {
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
s, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
return 0, fmt.Errorf("invalid format")
|
||||||
|
}
|
||||||
|
d, err := time.ParseDuration(s)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parseHeaderMap := func(v interface{}) (map[string][]string, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
vm, ok := v.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, errInvalidHeaderFormat
|
||||||
|
}
|
||||||
|
m := map[string][]string{}
|
||||||
|
for k, vv := range vm {
|
||||||
|
vs, ok := vv.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, errInvalidHeaderFormat
|
||||||
|
}
|
||||||
|
for _, vs := range vs {
|
||||||
|
s, ok := vs.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, errInvalidHeaderFormat
|
||||||
|
}
|
||||||
|
m[k] = append(m[k], s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
replace := func(oldKey, newKey string, val interface{}) {
|
||||||
|
rawMap[newKey] = val
|
||||||
|
if oldKey != newKey {
|
||||||
|
delete(rawMap, oldKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for k, v := range rawMap {
|
for k, v := range rawMap {
|
||||||
switch strings.ToLower(k) {
|
switch strings.ToLower(k) {
|
||||||
case "ttl":
|
case "header":
|
||||||
ttlKey = k
|
h, err := parseHeaderMap(v)
|
||||||
case "interval":
|
if err != nil {
|
||||||
intervalKey = k
|
return fmt.Errorf("invalid %q: %s", k, err)
|
||||||
case "timeout":
|
}
|
||||||
timeoutKey = k
|
rawMap[k] = h
|
||||||
case "deregister_critical_service_after":
|
|
||||||
rawMap[deregisterKey] = v
|
case "ttl", "interval", "timeout":
|
||||||
delete(rawMap, k)
|
d, err := parseDuration(v)
|
||||||
case "service_id":
|
if err != nil {
|
||||||
rawMap["serviceid"] = v
|
return fmt.Errorf("invalid %q: %v", k, err)
|
||||||
delete(rawMap, k)
|
}
|
||||||
|
rawMap[k] = d
|
||||||
|
|
||||||
|
case "deregister_critical_service_after", "deregistercriticalserviceafter":
|
||||||
|
d, err := parseDuration(v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid %q: %v", k, err)
|
||||||
|
}
|
||||||
|
replace(k, "DeregisterCriticalServiceAfter", d)
|
||||||
|
|
||||||
case "docker_container_id":
|
case "docker_container_id":
|
||||||
rawMap["DockerContainerID"] = v
|
replace(k, "DockerContainerID", v)
|
||||||
delete(rawMap, k)
|
|
||||||
|
case "service_id":
|
||||||
|
replace(k, "ServiceID", v)
|
||||||
|
|
||||||
case "tls_skip_verify":
|
case "tls_skip_verify":
|
||||||
rawMap["TLSSkipVerify"] = v
|
replace(k, "TLSSkipVerify", v)
|
||||||
delete(rawMap, k)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ttl, ok := rawMap[ttlKey]; ok {
|
|
||||||
ttlS, ok := ttl.(string)
|
|
||||||
if ok {
|
|
||||||
dur, err := time.ParseDuration(ttlS)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rawMap[ttlKey] = dur
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if interval, ok := rawMap[intervalKey]; ok {
|
|
||||||
intervalS, ok := interval.(string)
|
|
||||||
if ok {
|
|
||||||
dur, err := time.ParseDuration(intervalS)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rawMap[intervalKey] = dur
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if timeout, ok := rawMap[timeoutKey]; ok {
|
|
||||||
timeoutS, ok := timeout.(string)
|
|
||||||
if ok {
|
|
||||||
dur, err := time.ParseDuration(timeoutS)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rawMap[timeoutKey] = dur
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if deregister, ok := rawMap[deregisterKey]; ok {
|
|
||||||
timeoutS, ok := deregister.(string)
|
|
||||||
if ok {
|
|
||||||
dur, err := time.ParseDuration(timeoutS)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rawMap[deregisterKey] = dur
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -724,6 +724,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
"Notes": "j",
|
"Notes": "j",
|
||||||
"Script": "k",
|
"Script": "k",
|
||||||
"HTTP": "l",
|
"HTTP": "l",
|
||||||
|
"Header": {"a":["b"], "c":["d", "e"]},
|
||||||
|
"Method": "x",
|
||||||
"TCP": "m",
|
"TCP": "m",
|
||||||
"DockerContainerID": "n",
|
"DockerContainerID": "n",
|
||||||
"Shell": "o",
|
"Shell": "o",
|
||||||
|
@ -752,6 +754,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
Notes: "j",
|
Notes: "j",
|
||||||
Script: "k",
|
Script: "k",
|
||||||
HTTP: "l",
|
HTTP: "l",
|
||||||
|
Header: map[string][]string{"a": []string{"b"}, "c": []string{"d", "e"}},
|
||||||
|
Method: "x",
|
||||||
TCP: "m",
|
TCP: "m",
|
||||||
DockerContainerID: "n",
|
DockerContainerID: "n",
|
||||||
Shell: "o",
|
Shell: "o",
|
||||||
|
@ -784,6 +788,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
"Notes": "j",
|
"Notes": "j",
|
||||||
"Script": "k",
|
"Script": "k",
|
||||||
"HTTP": "l",
|
"HTTP": "l",
|
||||||
|
"Header": {"a":["b"], "c":["d", "e"]},
|
||||||
|
"Method": "x",
|
||||||
"TCP": "m",
|
"TCP": "m",
|
||||||
"DockerContainerID": "n",
|
"DockerContainerID": "n",
|
||||||
"Shell": "o",
|
"Shell": "o",
|
||||||
|
@ -800,6 +806,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
"Notes": "jj",
|
"Notes": "jj",
|
||||||
"Script": "kk",
|
"Script": "kk",
|
||||||
"HTTP": "ll",
|
"HTTP": "ll",
|
||||||
|
"Header": {"aa":["bb"], "cc":["dd", "ee"]},
|
||||||
|
"Method": "xx",
|
||||||
"TCP": "mm",
|
"TCP": "mm",
|
||||||
"DockerContainerID": "nn",
|
"DockerContainerID": "nn",
|
||||||
"Shell": "oo",
|
"Shell": "oo",
|
||||||
|
@ -830,6 +838,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
Notes: "j",
|
Notes: "j",
|
||||||
Script: "k",
|
Script: "k",
|
||||||
HTTP: "l",
|
HTTP: "l",
|
||||||
|
Header: map[string][]string{"a": []string{"b"}, "c": []string{"d", "e"}},
|
||||||
|
Method: "x",
|
||||||
TCP: "m",
|
TCP: "m",
|
||||||
DockerContainerID: "n",
|
DockerContainerID: "n",
|
||||||
Shell: "o",
|
Shell: "o",
|
||||||
|
@ -846,6 +856,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
Notes: "jj",
|
Notes: "jj",
|
||||||
Script: "kk",
|
Script: "kk",
|
||||||
HTTP: "ll",
|
HTTP: "ll",
|
||||||
|
Header: map[string][]string{"aa": []string{"bb"}, "cc": []string{"dd", "ee"}},
|
||||||
|
Method: "xx",
|
||||||
TCP: "mm",
|
TCP: "mm",
|
||||||
DockerContainerID: "nn",
|
DockerContainerID: "nn",
|
||||||
Shell: "oo",
|
Shell: "oo",
|
||||||
|
@ -879,6 +891,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
"Notes": "j",
|
"Notes": "j",
|
||||||
"Script": "k",
|
"Script": "k",
|
||||||
"HTTP": "l",
|
"HTTP": "l",
|
||||||
|
"Header": {"a":["b"], "c":["d", "e"]},
|
||||||
|
"Method": "x",
|
||||||
"TCP": "m",
|
"TCP": "m",
|
||||||
"DockerContainerID": "n",
|
"DockerContainerID": "n",
|
||||||
"Shell": "o",
|
"Shell": "o",
|
||||||
|
@ -904,6 +918,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
"Notes": "jj",
|
"Notes": "jj",
|
||||||
"Script": "kk",
|
"Script": "kk",
|
||||||
"HTTP": "ll",
|
"HTTP": "ll",
|
||||||
|
"Header": {"aa":["bb"], "cc":["dd", "ee"]},
|
||||||
|
"Method": "xx",
|
||||||
"TCP": "mm",
|
"TCP": "mm",
|
||||||
"DockerContainerID": "nn",
|
"DockerContainerID": "nn",
|
||||||
"Shell": "oo",
|
"Shell": "oo",
|
||||||
|
@ -933,6 +949,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
Notes: "j",
|
Notes: "j",
|
||||||
Script: "k",
|
Script: "k",
|
||||||
HTTP: "l",
|
HTTP: "l",
|
||||||
|
Header: map[string][]string{"a": []string{"b"}, "c": []string{"d", "e"}},
|
||||||
|
Method: "x",
|
||||||
TCP: "m",
|
TCP: "m",
|
||||||
DockerContainerID: "n",
|
DockerContainerID: "n",
|
||||||
Shell: "o",
|
Shell: "o",
|
||||||
|
@ -958,6 +976,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
Notes: "jj",
|
Notes: "jj",
|
||||||
Script: "kk",
|
Script: "kk",
|
||||||
HTTP: "ll",
|
HTTP: "ll",
|
||||||
|
Header: map[string][]string{"aa": []string{"bb"}, "cc": []string{"dd", "ee"}},
|
||||||
|
Method: "xx",
|
||||||
TCP: "mm",
|
TCP: "mm",
|
||||||
DockerContainerID: "nn",
|
DockerContainerID: "nn",
|
||||||
Shell: "oo",
|
Shell: "oo",
|
||||||
|
@ -985,6 +1005,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
"script": "d",
|
"script": "d",
|
||||||
"shell": "e",
|
"shell": "e",
|
||||||
"http": "f",
|
"http": "f",
|
||||||
|
"Header": {"a":["b"], "c":["d", "e"]},
|
||||||
|
"Method": "x",
|
||||||
"tcp": "g",
|
"tcp": "g",
|
||||||
"docker_container_id": "h",
|
"docker_container_id": "h",
|
||||||
"tls_skip_verify": true,
|
"tls_skip_verify": true,
|
||||||
|
@ -1006,6 +1028,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
Script: "d",
|
Script: "d",
|
||||||
Shell: "e",
|
Shell: "e",
|
||||||
HTTP: "f",
|
HTTP: "f",
|
||||||
|
Header: map[string][]string{"a": []string{"b"}, "c": []string{"d", "e"}},
|
||||||
|
Method: "x",
|
||||||
TCP: "g",
|
TCP: "g",
|
||||||
DockerContainerID: "h",
|
DockerContainerID: "h",
|
||||||
TLSSkipVerify: true,
|
TLSSkipVerify: true,
|
||||||
|
@ -1031,6 +1055,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
"script": "g",
|
"script": "g",
|
||||||
"shell": "h",
|
"shell": "h",
|
||||||
"http": "i",
|
"http": "i",
|
||||||
|
"Header": {"a":["b"], "c":["d", "e"]},
|
||||||
|
"Method": "x",
|
||||||
"tcp": "j",
|
"tcp": "j",
|
||||||
"docker_container_id": "k",
|
"docker_container_id": "k",
|
||||||
"tls_skip_verify": true,
|
"tls_skip_verify": true,
|
||||||
|
@ -1049,6 +1075,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
"script": "gg",
|
"script": "gg",
|
||||||
"shell": "hh",
|
"shell": "hh",
|
||||||
"http": "ii",
|
"http": "ii",
|
||||||
|
"Header": {"aa":["bb"], "cc":["dd", "ee"]},
|
||||||
|
"Method": "xx",
|
||||||
"tcp": "jj",
|
"tcp": "jj",
|
||||||
"docker_container_id": "kk",
|
"docker_container_id": "kk",
|
||||||
"tls_skip_verify": false,
|
"tls_skip_verify": false,
|
||||||
|
@ -1071,6 +1099,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
Script: "g",
|
Script: "g",
|
||||||
Shell: "h",
|
Shell: "h",
|
||||||
HTTP: "i",
|
HTTP: "i",
|
||||||
|
Header: map[string][]string{"a": []string{"b"}, "c": []string{"d", "e"}},
|
||||||
|
Method: "x",
|
||||||
TCP: "j",
|
TCP: "j",
|
||||||
DockerContainerID: "k",
|
DockerContainerID: "k",
|
||||||
TLSSkipVerify: true,
|
TLSSkipVerify: true,
|
||||||
|
@ -1089,6 +1119,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
Script: "gg",
|
Script: "gg",
|
||||||
Shell: "hh",
|
Shell: "hh",
|
||||||
HTTP: "ii",
|
HTTP: "ii",
|
||||||
|
Header: map[string][]string{"aa": []string{"bb"}, "cc": []string{"dd", "ee"}},
|
||||||
|
Method: "xx",
|
||||||
TCP: "jj",
|
TCP: "jj",
|
||||||
DockerContainerID: "kk",
|
DockerContainerID: "kk",
|
||||||
TLSSkipVerify: false,
|
TLSSkipVerify: false,
|
||||||
|
|
|
@ -62,6 +62,8 @@ type CheckDefinition struct {
|
||||||
//
|
//
|
||||||
Script string
|
Script string
|
||||||
HTTP string
|
HTTP string
|
||||||
|
Header map[string][]string
|
||||||
|
Method string
|
||||||
TCP string
|
TCP string
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
DockerContainerID string
|
DockerContainerID string
|
||||||
|
|
|
@ -27,17 +27,21 @@ There are five different kinds of checks:
|
||||||
`timeout` field in the check definition.
|
`timeout` field in the check definition.
|
||||||
|
|
||||||
* HTTP + Interval - These checks make an HTTP `GET` request every Interval (e.g.
|
* HTTP + Interval - These checks make an HTTP `GET` request every Interval (e.g.
|
||||||
every 30 seconds) to the specified URL. The status of the service depends on the HTTP response code:
|
every 30 seconds) to the specified URL. The status of the service depends on
|
||||||
any `2xx` code is considered passing, a `429 Too Many Requests` is a warning, and anything else is a failure.
|
the HTTP response code: any `2xx` code is considered passing, a `429 Too Many
|
||||||
This type of check should be preferred over a script that uses `curl` or another external process
|
Requests` is a warning, and anything else is a failure. This type of check
|
||||||
to check a simple HTTP operation. By default, HTTP checks will be configured
|
should be preferred over a script that uses `curl` or another external process
|
||||||
with a request timeout equal to the check interval, with a max of 10 seconds.
|
to check a simple HTTP operation. By default, HTTP checks are `GET` requests
|
||||||
It is possible to configure a custom HTTP check timeout value by specifying
|
unless the `method` field specifies a different method. Additional header
|
||||||
the `timeout` field in the check definition. The output of the check is
|
fields can be set through the `header` field which is a map of lists of
|
||||||
limited to roughly 4K. Responses larger than this will be truncated. HTTP checks
|
strings, e.g. `{"x-foo": ["bar", "baz"]}`. By default, HTTP checks will be
|
||||||
also support SSL. By default, a valid SSL certificate is expected. Certificate
|
configured with a request timeout equal to the check interval, with a max of
|
||||||
verification can be turned off by setting the `tls_skip_verify` field to `true`
|
10 seconds. It is possible to configure a custom HTTP check timeout value by
|
||||||
in the check definition.
|
specifying the `timeout` field in the check definition. The output of the
|
||||||
|
check is limited to roughly 4K. Responses larger than this will be truncated.
|
||||||
|
HTTP checks also support SSL. By default, a valid SSL certificate is expected.
|
||||||
|
Certificate verification can be turned off by setting the `tls_skip_verify`
|
||||||
|
field to `true` in the check definition.
|
||||||
|
|
||||||
* TCP + Interval - These checks make an TCP connection attempt every Interval
|
* TCP + Interval - These checks make an TCP connection attempt every Interval
|
||||||
(e.g. every 30 seconds) to the specified IP/hostname and port. If no hostname
|
(e.g. every 30 seconds) to the specified IP/hostname and port. If no hostname
|
||||||
|
@ -104,6 +108,8 @@ A HTTP check:
|
||||||
"id": "api",
|
"id": "api",
|
||||||
"name": "HTTP API on port 5000",
|
"name": "HTTP API on port 5000",
|
||||||
"http": "http://localhost:5000/health",
|
"http": "http://localhost:5000/health",
|
||||||
|
"method": "POST",
|
||||||
|
"header": {"x-foo":["bar", "baz"]},
|
||||||
"interval": "10s",
|
"interval": "10s",
|
||||||
"timeout": "1s"
|
"timeout": "1s"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue