diff --git a/.changelog/8431.txt b/.changelog/8431.txt new file mode 100644 index 0000000000..597e06c3eb --- /dev/null +++ b/.changelog/8431.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +health-checks: add H2 ping health checks. +``` diff --git a/agent/agent.go b/agent/agent.go index 65f8e4643b..53e4fb2a3c 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -204,6 +204,9 @@ type Agent struct { // checkHTTPs maps the check ID to an associated HTTP check checkHTTPs map[structs.CheckID]*checks.CheckHTTP + // checkH2PINGs maps the check ID to an associated HTTP2 PING check + checkH2PINGs map[structs.CheckID]*checks.CheckH2PING + // checkTCPs maps the check ID to an associated TCP check checkTCPs map[structs.CheckID]*checks.CheckTCP @@ -349,6 +352,7 @@ func New(bd BaseDeps) (*Agent, error) { checkMonitors: make(map[structs.CheckID]*checks.CheckMonitor), checkTTLs: make(map[structs.CheckID]*checks.CheckTTL), checkHTTPs: make(map[structs.CheckID]*checks.CheckHTTP), + checkH2PINGs: make(map[structs.CheckID]*checks.CheckH2PING), checkTCPs: make(map[structs.CheckID]*checks.CheckTCP), checkGRPCs: make(map[structs.CheckID]*checks.CheckGRPC), checkDockers: make(map[structs.CheckID]*checks.CheckDocker), @@ -1367,6 +1371,9 @@ func (a *Agent) ShutdownAgent() error { for _, chk := range a.checkAliases { chk.Stop() } + for _, chk := range a.checkH2PINGs { + chk.Stop() + } // Stop gRPC if a.grpcServer != nil { @@ -2685,6 +2692,36 @@ func (a *Agent) addCheck(check *structs.HealthCheck, chkType *structs.CheckType, monitor.Start() a.checkMonitors[cid] = monitor + case chkType.IsH2PING(): + if existing, ok := a.checkH2PINGs[cid]; ok { + existing.Stop() + delete(a.checkH2PINGs, cid) + } + if chkType.Interval < checks.MinInterval { + a.logger.Warn("check has interval below minimum", + "check", cid.String(), + "minimum_interval", checks.MinInterval, + ) + chkType.Interval = checks.MinInterval + } + + tlsClientConfig := a.tlsConfigurator.OutgoingTLSConfigForCheck(chkType.TLSSkipVerify, chkType.TLSServerName) + tlsClientConfig.NextProtos = []string{http2.NextProtoTLS} + + h2ping := &checks.CheckH2PING{ + CheckID: cid, + ServiceID: sid, + H2PING: chkType.H2PING, + Interval: chkType.Interval, + Timeout: chkType.Timeout, + Logger: a.logger, + TLSClientConfig: tlsClientConfig, + StatusHandler: statusHandler, + } + + h2ping.Start() + a.checkH2PINGs[cid] = h2ping + case chkType.IsAlias(): if existing, ok := a.checkAliases[cid]; ok { existing.Stop() @@ -2890,6 +2927,11 @@ func (a *Agent) cancelCheckMonitors(checkID structs.CheckID) { check.Stop() delete(a.checkDockers, checkID) } + if check, ok := a.checkH2PINGs[checkID]; ok { + check.Stop() + delete(a.checkH2PINGs, checkID) + } + } // updateTTLCheck is used to update the status of a TTL check via the Agent API. diff --git a/agent/agent_test.go b/agent/agent_test.go index 54fbbfe697..83d47d25d3 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -811,6 +811,31 @@ func TestAgent_CheckAliasRPC(t *testing.T) { } } +func TestAgent_AddServiceWithH2PINGCheck(t *testing.T) { + t.Parallel() + a := NewTestAgent(t, "") + defer a.Shutdown() + check := []*structs.CheckType{ + { + CheckID: "test-h2ping-check", + Name: "test-h2ping-check", + H2PING: "localhost:12345", + TLSSkipVerify: true, + Interval: 10 * time.Second, + }, + } + + nodeService := &structs.NodeService{ + ID: "test-h2ping-check-service", + Service: "test-h2ping-check-service", + } + err := a.addServiceFromSource(nodeService, check, false, "", ConfigSourceLocal) + if err != nil { + t.Fatalf("Error registering service: %v", err) + } + requireCheckExists(t, a, "test-h2ping-check") +} + func TestAgent_AddServiceNoExec(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") diff --git a/agent/checks/check.go b/agent/checks/check.go index c1d3bd280b..868ad4d115 100644 --- a/agent/checks/check.go +++ b/agent/checks/check.go @@ -1,8 +1,10 @@ package checks import ( + "context" "crypto/tls" "fmt" + http2 "golang.org/x/net/http2" "io" "io/ioutil" "net" @@ -504,6 +506,86 @@ func (c *CheckHTTP) check() { } } +type CheckH2PING struct { + CheckID structs.CheckID + ServiceID structs.ServiceID + H2PING string + Interval time.Duration + Timeout time.Duration + Logger hclog.Logger + TLSClientConfig *tls.Config + StatusHandler *StatusHandler + + stop bool + stopCh chan struct{} + stopLock sync.Mutex +} + +func (c *CheckH2PING) check() { + t := &http2.Transport{ + TLSClientConfig: c.TLSClientConfig, + } + target := c.H2PING + conn, err := tls.Dial("tcp", target, c.TLSClientConfig) + if err != nil { + message := fmt.Sprintf("Failed to dial to %s: %s", target, err) + c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, message) + return + } + defer conn.Close() + clientConn, err := t.NewClientConn(conn) + if err != nil { + message := fmt.Sprintf("Failed to create client connection %s", err) + c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, message) + return + } + ctx, cancel := context.WithTimeout(context.Background(), c.Timeout) + defer cancel() + err = clientConn.Ping(ctx) + if err == nil { + c.StatusHandler.updateCheck(c.CheckID, api.HealthPassing, "HTTP2 ping was successful") + } else { + message := fmt.Sprintf("HTTP2 ping failed: %s", err) + c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, message) + } +} + +// Stop is used to stop an H2PING check. +func (c *CheckH2PING) Stop() { + c.stopLock.Lock() + defer c.stopLock.Unlock() + if !c.stop { + c.stop = true + close(c.stopCh) + } +} + +func (c *CheckH2PING) run() { + // Get the randomized initial pause time + initialPauseTime := lib.RandomStagger(c.Interval) + next := time.After(initialPauseTime) + for { + select { + case <-next: + c.check() + next = time.After(c.Interval) + case <-c.stopCh: + return + } + } +} + +func (c *CheckH2PING) Start() { + c.stopLock.Lock() + defer c.stopLock.Unlock() + if c.Timeout <= 0 { + c.Timeout = 10 * time.Second + } + c.stop = false + c.stopCh = make(chan struct{}) + go c.run() +} + // CheckTCP is used to periodically make an TCP/UDP connection to // determine the health of a given check. // The check is passing if the connection succeeds diff --git a/agent/checks/check_test.go b/agent/checks/check_test.go index ce1137b12d..580e2eac16 100644 --- a/agent/checks/check_test.go +++ b/agent/checks/check_test.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/go-uuid" "github.com/stretchr/testify/require" + http2 "golang.org/x/net/http2" ) func uniqueID() string { @@ -964,6 +965,162 @@ func TestCheckTCPPassing(t *testing.T) { tcpServer.Close() } +func TestCheckH2PING(t *testing.T) { + t.Parallel() + + tests := []struct { + desc string + passing bool + timeout time.Duration + connTimeout time.Duration + }{ + {desc: "passing", passing: true, timeout: 1 * time.Second, connTimeout: 1 * time.Second}, + {desc: "failing because of time out", passing: false, timeout: 1 * time.Nanosecond, connTimeout: 1 * time.Second}, + {desc: "failing because of closed connection", passing: false, timeout: 1 * time.Nanosecond, connTimeout: 1 * time.Millisecond}, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return }) + server := httptest.NewUnstartedServer(handler) + server.EnableHTTP2 = true + server.Config.ReadTimeout = tt.connTimeout + server.StartTLS() + defer server.Close() + serverAddress := server.Listener.Addr() + target := serverAddress.String() + + notif := mock.NewNotify() + logger := testutil.Logger(t) + statusHandler := NewStatusHandler(notif, logger, 0, 0) + cid := structs.NewCheckID("foo", nil) + tlsCfg := &api.TLSConfig{ + InsecureSkipVerify: true, + } + tlsClientCfg, err := api.SetupTLSConfig(tlsCfg) + if err != nil { + t.Fatalf("%v", err) + } + tlsClientCfg.NextProtos = []string{http2.NextProtoTLS} + + check := &CheckH2PING{ + CheckID: cid, + H2PING: target, + Interval: 5 * time.Second, + Timeout: tt.timeout, + Logger: logger, + TLSClientConfig: tlsClientCfg, + StatusHandler: statusHandler, + } + + check.Start() + defer check.Stop() + + if tt.passing { + retry.Run(t, func(r *retry.R) { + if got, want := notif.State(cid), api.HealthPassing; got != want { + r.Fatalf("got state %q want %q", got, want) + } + }) + } else { + retry.Run(t, func(r *retry.R) { + if got, want := notif.State(cid), api.HealthCritical; got != want { + r.Fatalf("got state %q want %q", got, want) + } + }) + } + }) + } +} + +func TestCheckH2PING_TLS_BadVerify(t *testing.T) { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return }) + server := httptest.NewUnstartedServer(handler) + server.EnableHTTP2 = true + server.StartTLS() + defer server.Close() + serverAddress := server.Listener.Addr() + target := serverAddress.String() + + notif := mock.NewNotify() + logger := testutil.Logger(t) + statusHandler := NewStatusHandler(notif, logger, 0, 0) + cid := structs.NewCheckID("foo", nil) + tlsCfg := &api.TLSConfig{} + tlsClientCfg, err := api.SetupTLSConfig(tlsCfg) + if err != nil { + t.Fatalf("%v", err) + } + tlsClientCfg.NextProtos = []string{http2.NextProtoTLS} + + check := &CheckH2PING{ + CheckID: cid, + H2PING: target, + Interval: 5 * time.Second, + Timeout: 2 * time.Second, + Logger: logger, + TLSClientConfig: tlsClientCfg, + StatusHandler: statusHandler, + } + + check.Start() + defer check.Stop() + + insecureSkipVerifyValue := check.TLSClientConfig.InsecureSkipVerify + if insecureSkipVerifyValue { + t.Fatalf("The default value for InsecureSkipVerify should be false but was %v", insecureSkipVerifyValue) + } + retry.Run(t, func(r *retry.R) { + if got, want := notif.State(cid), api.HealthCritical; got != want { + r.Fatalf("got state %q want %q", got, want) + } + expectedOutput := "certificate signed by unknown authority" + if !strings.Contains(notif.Output(cid), expectedOutput) { + r.Fatalf("should have included output %s: %v", expectedOutput, notif.OutputMap()) + } + }) +} +func TestCheckH2PINGInvalidListener(t *testing.T) { + t.Parallel() + + notif := mock.NewNotify() + logger := testutil.Logger(t) + statusHandler := NewStatusHandler(notif, logger, 0, 0) + cid := structs.NewCheckID("foo", nil) + tlsCfg := &api.TLSConfig{ + InsecureSkipVerify: true, + } + tlsClientCfg, err := api.SetupTLSConfig(tlsCfg) + if err != nil { + t.Fatalf("%v", err) + } + tlsClientCfg.NextProtos = []string{http2.NextProtoTLS} + + check := &CheckH2PING{ + CheckID: cid, + H2PING: "localhost:55555", + Interval: 5 * time.Second, + Timeout: 1 * time.Second, + Logger: logger, + TLSClientConfig: tlsClientCfg, + StatusHandler: statusHandler, + } + + check.Start() + defer check.Stop() + + retry.Run(t, func(r *retry.R) { + if got, want := notif.State(cid), api.HealthCritical; got != want { + r.Fatalf("got state %q want %q", got, want) + } + expectedOutput := "Failed to dial to" + if !strings.Contains(notif.Output(cid), expectedOutput) { + r.Fatalf("should have included output %s: %v", expectedOutput, notif.OutputMap()) + } + + }) +} + func TestCheck_Docker(t *testing.T) { if testing.Short() { t.Skip("too slow for testing.Short") diff --git a/agent/config/builder.go b/agent/config/builder.go index e85715ffe9..7e151e760a 100644 --- a/agent/config/builder.go +++ b/agent/config/builder.go @@ -1579,6 +1579,7 @@ func (b *builder) checkVal(v *CheckDefinition) *structs.CheckDefinition { TTL: b.durationVal(fmt.Sprintf("check[%s].ttl", id), v.TTL), SuccessBeforePassing: intVal(v.SuccessBeforePassing), FailuresBeforeCritical: intVal(v.FailuresBeforeCritical), + H2PING: stringVal(v.H2PING), DeregisterCriticalServiceAfter: b.durationVal(fmt.Sprintf("check[%s].deregister_critical_service_after", id), v.DeregisterCriticalServiceAfter), OutputMaxSize: intValWithDefault(v.OutputMaxSize, checks.DefaultBufSize), EnterpriseMeta: v.EnterpriseMeta.ToStructs(), diff --git a/agent/config/config.go b/agent/config/config.go index b575d5b350..937d543886 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -411,6 +411,7 @@ type CheckDefinition struct { AliasService *string `mapstructure:"alias_service"` Timeout *string `mapstructure:"timeout"` TTL *string `mapstructure:"ttl"` + H2PING *string `mapstructure:"h2ping"` SuccessBeforePassing *int `mapstructure:"success_before_passing"` FailuresBeforeCritical *int `mapstructure:"failures_before_critical"` DeregisterCriticalServiceAfter *string `mapstructure:"deregister_critical_service_after" alias:"deregistercriticalserviceafter"` diff --git a/agent/config/runtime.go b/agent/config/runtime.go index c5f3872185..66c43d1244 100644 --- a/agent/config/runtime.go +++ b/agent/config/runtime.go @@ -470,6 +470,7 @@ type RuntimeConfig struct { // header = map[string][]string // method = string // tcp = string + // h2ping = string // interval = string // docker_container_id = string // shell = string diff --git a/agent/config/runtime_test.go b/agent/config/runtime_test.go index a68ed5f944..38ea470fb5 100644 --- a/agent/config/runtime_test.go +++ b/agent/config/runtime_test.go @@ -5205,6 +5205,7 @@ func TestLoad_FullConfig(t *testing.T) { Method: "aldrIQ4l", Body: "wSjTy7dg", TCP: "RJQND605", + H2PING: "9N1cSb5B", Interval: 22164 * time.Second, OutputMaxSize: checks.DefaultBufSize, DockerContainerID: "ipgdFtjd", @@ -5232,6 +5233,7 @@ func TestLoad_FullConfig(t *testing.T) { Body: "0jkKgGUC", OutputMaxSize: checks.DefaultBufSize, TCP: "4jG5casb", + H2PING: "HCHU7gEb", Interval: 28767 * time.Second, DockerContainerID: "THW6u7rL", Shell: "C1Zt3Zwh", @@ -5258,6 +5260,7 @@ func TestLoad_FullConfig(t *testing.T) { Body: "5PBQd2OT", OutputMaxSize: checks.DefaultBufSize, TCP: "JY6fTTcw", + H2PING: "rQ8eyCSF", Interval: 18714 * time.Second, DockerContainerID: "qF66POS9", Shell: "sOnDy228", @@ -5464,6 +5467,7 @@ func TestLoad_FullConfig(t *testing.T) { Body: "WeikigLh", OutputMaxSize: checks.DefaultBufSize, TCP: "ICbxkpSF", + H2PING: "7s7BbMyb", Interval: 24392 * time.Second, DockerContainerID: "ZKXr68Yb", Shell: "CEfzx0Fo", @@ -5515,6 +5519,7 @@ func TestLoad_FullConfig(t *testing.T) { Body: "7CRjCJyz", OutputMaxSize: checks.DefaultBufSize, TCP: "MN3oA9D2", + H2PING: "OV6Q2XEg", Interval: 32718 * time.Second, DockerContainerID: "cU15LMet", Shell: "nEz9qz2l", @@ -5539,6 +5544,7 @@ func TestLoad_FullConfig(t *testing.T) { Body: "4I8ucZgZ", OutputMaxSize: checks.DefaultBufSize, TCP: "2exjZIGE", + H2PING: "jTDuR1DC", Interval: 5656 * time.Second, DockerContainerID: "5tDBWpfA", Shell: "rlTpLM8s", @@ -5657,6 +5663,7 @@ func TestLoad_FullConfig(t *testing.T) { Body: "OwGjTFQi", OutputMaxSize: checks.DefaultBufSize, TCP: "bNnNfx2A", + H2PING: "qC1pidiW", Interval: 22224 * time.Second, DockerContainerID: "ipgdFtjd", Shell: "omVZq7Sz", @@ -5681,6 +5688,7 @@ func TestLoad_FullConfig(t *testing.T) { Body: "lUVLGYU7", OutputMaxSize: checks.DefaultBufSize, TCP: "FfvCwlqH", + H2PING: "spI3muI3", Interval: 12356 * time.Second, DockerContainerID: "HBndBU6R", Shell: "hVI33JjA", @@ -5705,6 +5713,7 @@ func TestLoad_FullConfig(t *testing.T) { Body: "wVVL2V6f", OutputMaxSize: checks.DefaultBufSize, TCP: "fjiLFqVd", + H2PING: "5NbNWhan", Interval: 23926 * time.Second, DockerContainerID: "dO5TtRHk", Shell: "e6q2ttES", diff --git a/agent/config/testdata/TestRuntimeConfig_Sanitize.golden b/agent/config/testdata/TestRuntimeConfig_Sanitize.golden index b792e466fa..9e4ceb1ac0 100644 --- a/agent/config/testdata/TestRuntimeConfig_Sanitize.golden +++ b/agent/config/testdata/TestRuntimeConfig_Sanitize.golden @@ -93,6 +93,7 @@ "FailuresBeforeCritical": 0, "GRPC": "", "GRPCUseTLS": false, + "H2PING": "", "HTTP": "", "Header": {}, "ID": "", @@ -294,6 +295,7 @@ "FailuresBeforeCritical": 0, "GRPC": "", "GRPCUseTLS": false, + "H2PING": "", "HTTP": "", "Header": {}, "Interval": "0s", diff --git a/agent/config/testdata/full-config.hcl b/agent/config/testdata/full-config.hcl index 9d25247e6d..6b56b1bc7e 100644 --- a/agent/config/testdata/full-config.hcl +++ b/agent/config/testdata/full-config.hcl @@ -109,6 +109,7 @@ check = { method = "Dou0nGT5" body = "5PBQd2OT" tcp = "JY6fTTcw" + h2ping = "rQ8eyCSF" interval = "18714s" output_max_size = 4096 docker_container_id = "qF66POS9" @@ -136,6 +137,7 @@ checks = [ method = "aldrIQ4l" body = "wSjTy7dg" tcp = "RJQND605" + h2ping = "9N1cSb5B" interval = "22164s" output_max_size = 4096 docker_container_id = "ipgdFtjd" @@ -162,6 +164,7 @@ checks = [ method = "gLrztrNw" body = "0jkKgGUC" tcp = "4jG5casb" + h2ping = "HCHU7gEb" interval = "28767s" output_max_size = 4096 docker_container_id = "THW6u7rL" @@ -378,6 +381,7 @@ service = { method = "9afLm3Mj" body = "wVVL2V6f" tcp = "fjiLFqVd" + h2ping = "5NbNWhan" interval = "23926s" docker_container_id = "dO5TtRHk" shell = "e6q2ttES" @@ -402,6 +406,7 @@ service = { method = "T66MFBfR" body = "OwGjTFQi" tcp = "bNnNfx2A" + h2ping = "qC1pidiW" interval = "22224s" output_max_size = 4096 docker_container_id = "ipgdFtjd" @@ -426,6 +431,7 @@ service = { method = "ciYHWors" body = "lUVLGYU7" tcp = "FfvCwlqH" + h2ping = "spI3muI3" interval = "12356s" output_max_size = 4096 docker_container_id = "HBndBU6R" @@ -464,6 +470,7 @@ services = [ method = "X5DrovFc" body = "WeikigLh" tcp = "ICbxkpSF" + h2ping = "7s7BbMyb" interval = "24392s" output_max_size = 4096 docker_container_id = "ZKXr68Yb" @@ -505,6 +512,7 @@ services = [ method = "5wkAxCUE" body = "7CRjCJyz" tcp = "MN3oA9D2" + h2ping = "OV6Q2XEg" interval = "32718s" output_max_size = 4096 docker_container_id = "cU15LMet" @@ -529,6 +537,7 @@ services = [ method = "wzByP903" body = "4I8ucZgZ" tcp = "2exjZIGE" + h2ping = "jTDuR1DC" interval = "5656s" output_max_size = 4096 docker_container_id = "5tDBWpfA" @@ -675,4 +684,4 @@ watches = [{ datacenter = "fYrl3F5d" key = "sl3Dffu7" args = ["dltjDJ2a", "flEa7C2d"] -}] \ No newline at end of file +}] diff --git a/agent/config/testdata/full-config.json b/agent/config/testdata/full-config.json index 106bea01a9..4443f2879a 100644 --- a/agent/config/testdata/full-config.json +++ b/agent/config/testdata/full-config.json @@ -111,6 +111,7 @@ "body": "5PBQd2OT", "output_max_size": 4096, "tcp": "JY6fTTcw", + "h2ping": "rQ8eyCSF", "interval": "18714s", "docker_container_id": "qF66POS9", "shell": "sOnDy228", @@ -137,6 +138,7 @@ "method": "aldrIQ4l", "body": "wSjTy7dg", "tcp": "RJQND605", + "h2ping": "9N1cSb5B", "interval": "22164s", "output_max_size": 4096, "docker_container_id": "ipgdFtjd", @@ -163,6 +165,7 @@ "method": "gLrztrNw", "body": "0jkKgGUC", "tcp": "4jG5casb", + "h2ping": "HCHU7gEb", "interval": "28767s", "output_max_size": 4096, "docker_container_id": "THW6u7rL", @@ -374,6 +377,7 @@ "method": "9afLm3Mj", "body": "wVVL2V6f", "tcp": "fjiLFqVd", + "h2ping": "5NbNWhan", "interval": "23926s", "output_max_size": 4096, "docker_container_id": "dO5TtRHk", @@ -399,6 +403,7 @@ "method": "T66MFBfR", "body": "OwGjTFQi", "tcp": "bNnNfx2A", + "h2ping": "qC1pidiW", "interval": "22224s", "output_max_size": 4096, "docker_container_id": "ipgdFtjd", @@ -423,6 +428,7 @@ "method": "ciYHWors", "body": "lUVLGYU7", "tcp": "FfvCwlqH", + "h2ping": "spI3muI3", "interval": "12356s", "output_max_size": 4096, "docker_container_id": "HBndBU6R", @@ -461,6 +467,7 @@ "method": "X5DrovFc", "body": "WeikigLh", "tcp": "ICbxkpSF", + "h2ping": "7s7BbMyb", "interval": "24392s", "output_max_size": 4096, "docker_container_id": "ZKXr68Yb", @@ -502,6 +509,7 @@ "method": "5wkAxCUE", "body": "7CRjCJyz", "tcp": "MN3oA9D2", + "h2ping": "OV6Q2XEg", "interval": "32718s", "output_max_size": 4096, "docker_container_id": "cU15LMet", @@ -526,6 +534,7 @@ "method": "wzByP903", "body": "4I8ucZgZ", "tcp": "2exjZIGE", + "h2ping": "jTDuR1DC", "interval": "5656s", "output_max_size": 4096, "docker_container_id": "5tDBWpfA", @@ -675,4 +684,4 @@ "args": ["dltjDJ2a", "flEa7C2d"] } ] -} \ No newline at end of file +} diff --git a/agent/structs/check_definition.go b/agent/structs/check_definition.go index 3a8c2326a3..9262ef01fe 100644 --- a/agent/structs/check_definition.go +++ b/agent/structs/check_definition.go @@ -24,6 +24,7 @@ type CheckDefinition struct { // ScriptArgs []string HTTP string + H2PING string Header map[string][]string Method string Body string @@ -177,6 +178,7 @@ func (c *CheckDefinition) CheckType() *CheckType { AliasNode: c.AliasNode, AliasService: c.AliasService, HTTP: c.HTTP, + H2PING: c.H2PING, GRPC: c.GRPC, GRPCUseTLS: c.GRPCUseTLS, Header: c.Header, diff --git a/agent/structs/check_definition_test.go b/agent/structs/check_definition_test.go index 871091562e..160d15c6a1 100644 --- a/agent/structs/check_definition_test.go +++ b/agent/structs/check_definition_test.go @@ -85,6 +85,7 @@ func TestCheckDefinitionToCheckType(t *testing.T) { Token: "tok", ScriptArgs: []string{"/bin/foo"}, HTTP: "someurl", + H2PING: "somehttp2url", TCP: "host:port", Interval: 1 * time.Second, DockerContainerID: "abc123", @@ -102,6 +103,7 @@ func TestCheckDefinitionToCheckType(t *testing.T) { ScriptArgs: []string{"/bin/foo"}, HTTP: "someurl", + H2PING: "somehttp2url", TCP: "host:port", Interval: 1 * time.Second, DockerContainerID: "abc123", diff --git a/agent/structs/check_type.go b/agent/structs/check_type.go index 4e864d96b8..372ab57491 100644 --- a/agent/structs/check_type.go +++ b/agent/structs/check_type.go @@ -12,10 +12,10 @@ import ( type CheckTypes []*CheckType // CheckType is used to create either the CheckMonitor or the CheckTTL. -// The following types are supported: Script, HTTP, TCP, Docker, TTL, GRPC, Alias. Script, -// HTTP, Docker, TCP and GRPC all require Interval. Only one of the types may +// The following types are supported: Script, HTTP, TCP, Docker, TTL, GRPC, Alias, H2PING. Script, +// HTTP, Docker, TCP, GRPC, and H2PING all require Interval. Only one of the types may // to be provided: TTL or Script/Interval or HTTP/Interval or TCP/Interval or -// Docker/Interval or GRPC/Interval or AliasService. +// Docker/Interval or GRPC/Interval or AliasService or H2PING/Interval. // Since types like CheckHTTP and CheckGRPC derive from CheckType, there are // helper conversion methods that do the reverse conversion. ie. checkHTTP.CheckType() type CheckType struct { @@ -32,6 +32,7 @@ type CheckType struct { ScriptArgs []string HTTP string + H2PING string Header map[string][]string Method string Body string @@ -161,13 +162,13 @@ func (t *CheckType) UnmarshalJSON(data []byte) (err error) { // Validate returns an error message if the check is invalid func (c *CheckType) Validate() error { - intervalCheck := c.IsScript() || c.HTTP != "" || c.TCP != "" || c.GRPC != "" + intervalCheck := c.IsScript() || c.HTTP != "" || c.TCP != "" || c.GRPC != "" || c.H2PING != "" if c.Interval > 0 && c.TTL > 0 { return fmt.Errorf("Interval and TTL cannot both be specified") } if intervalCheck && c.Interval <= 0 { - return fmt.Errorf("Interval must be > 0 for Script, HTTP, or TCP checks") + return fmt.Errorf("Interval must be > 0 for Script, HTTP, H2PING, or TCP checks") } if intervalCheck && c.IsAlias() { return fmt.Errorf("Interval cannot be set for Alias checks") @@ -229,6 +230,11 @@ func (c *CheckType) IsGRPC() bool { return c.GRPC != "" && c.Interval > 0 } +// IsH2PING checks if this is a H2PING type +func (c *CheckType) IsH2PING() bool { + return c.H2PING != "" && c.Interval > 0 +} + func (c *CheckType) Type() string { switch { case c.IsGRPC(): @@ -245,6 +251,8 @@ func (c *CheckType) Type() string { return "docker" case c.IsScript(): return "script" + case c.IsH2PING(): + return "h2ping" default: return "" } diff --git a/agent/structs/structs.go b/agent/structs/structs.go index ec1082cc7c..2146f89e8e 100644 --- a/agent/structs/structs.go +++ b/agent/structs/structs.go @@ -1450,6 +1450,7 @@ type HealthCheckDefinition struct { Method string `json:",omitempty"` Body string `json:",omitempty"` TCP string `json:",omitempty"` + H2PING string `json:",omitempty"` Interval time.Duration `json:",omitempty"` OutputMaxSize uint `json:",omitempty"` Timeout time.Duration `json:",omitempty"` @@ -1596,6 +1597,7 @@ func (c *HealthCheck) CheckType() *CheckType { Method: c.Definition.Method, Body: c.Definition.Body, TCP: c.Definition.TCP, + H2PING: c.Definition.H2PING, Interval: c.Definition.Interval, DockerContainerID: c.Definition.DockerContainerID, Shell: c.Definition.Shell, diff --git a/proto/pbservice/healthcheck.gen.go b/proto/pbservice/healthcheck.gen.go index dcf8435bbe..266a011a23 100644 --- a/proto/pbservice/healthcheck.gen.go +++ b/proto/pbservice/healthcheck.gen.go @@ -21,6 +21,7 @@ func CheckTypeToStructs(s CheckType) structs.CheckType { t.AliasService = s.AliasService t.DockerContainerID = s.DockerContainerID t.Shell = s.Shell + t.H2PING = s.H2PING t.GRPC = s.GRPC t.GRPCUseTLS = s.GRPCUseTLS t.TLSServerName = s.TLSServerName @@ -52,6 +53,7 @@ func NewCheckTypeFromStructs(t structs.CheckType) CheckType { s.AliasService = t.AliasService s.DockerContainerID = t.DockerContainerID s.Shell = t.Shell + s.H2PING = t.H2PING s.GRPC = t.GRPC s.GRPCUseTLS = t.GRPCUseTLS s.TLSServerName = t.TLSServerName @@ -116,6 +118,7 @@ func HealthCheckDefinitionToStructs(s HealthCheckDefinition) structs.HealthCheck t.ScriptArgs = s.ScriptArgs t.DockerContainerID = s.DockerContainerID t.Shell = s.Shell + t.H2PING = s.H2PING t.GRPC = s.GRPC t.GRPCUseTLS = s.GRPCUseTLS t.AliasNode = s.AliasNode @@ -139,6 +142,7 @@ func NewHealthCheckDefinitionFromStructs(t structs.HealthCheckDefinition) Health s.ScriptArgs = t.ScriptArgs s.DockerContainerID = t.DockerContainerID s.Shell = t.Shell + s.H2PING = t.H2PING s.GRPC = t.GRPC s.GRPCUseTLS = t.GRPCUseTLS s.AliasNode = t.AliasNode diff --git a/proto/pbservice/healthcheck.pb.go b/proto/pbservice/healthcheck.pb.go index ae66511c73..c189c9dc65 100644 --- a/proto/pbservice/healthcheck.pb.go +++ b/proto/pbservice/healthcheck.pb.go @@ -148,6 +148,7 @@ type HealthCheckDefinition struct { ScriptArgs []string `protobuf:"bytes,10,rep,name=ScriptArgs,proto3" json:"ScriptArgs,omitempty"` DockerContainerID string `protobuf:"bytes,11,opt,name=DockerContainerID,proto3" json:"DockerContainerID,omitempty"` Shell string `protobuf:"bytes,12,opt,name=Shell,proto3" json:"Shell,omitempty"` + H2PING string `protobuf:"bytes,20,opt,name=H2PING,proto3" json:"H2PING,omitempty"` GRPC string `protobuf:"bytes,13,opt,name=GRPC,proto3" json:"GRPC,omitempty"` GRPCUseTLS bool `protobuf:"varint,14,opt,name=GRPCUseTLS,proto3" json:"GRPCUseTLS,omitempty"` AliasNode string `protobuf:"bytes,15,opt,name=AliasNode,proto3" json:"AliasNode,omitempty"` @@ -190,10 +191,10 @@ var xxx_messageInfo_HealthCheckDefinition proto.InternalMessageInfo // CheckType is used to create either the CheckMonitor or the CheckTTL. // The following types are supported: Script, HTTP, TCP, Docker, TTL, GRPC, -// Alias. Script, -// HTTP, Docker, TCP and GRPC all require Interval. Only one of the types may +// Alias. Script, H2PING, +// HTTP, Docker, TCP, H2PING and GRPC all require Interval. Only one of the types may // to be provided: TTL or Script/Interval or HTTP/Interval or TCP/Interval or -// Docker/Interval or GRPC/Interval or AliasService. +// Docker/Interval or GRPC/Interval or H2PING/Interval or AliasService. // // mog annotation: // @@ -217,6 +218,7 @@ type CheckType struct { AliasService string `protobuf:"bytes,11,opt,name=AliasService,proto3" json:"AliasService,omitempty"` DockerContainerID string `protobuf:"bytes,12,opt,name=DockerContainerID,proto3" json:"DockerContainerID,omitempty"` Shell string `protobuf:"bytes,13,opt,name=Shell,proto3" json:"Shell,omitempty"` + H2PING string `protobuf:"bytes,28,opt,name=H2PING,proto3" json:"H2PING,omitempty"` GRPC string `protobuf:"bytes,14,opt,name=GRPC,proto3" json:"GRPC,omitempty"` GRPCUseTLS bool `protobuf:"varint,15,opt,name=GRPCUseTLS,proto3" json:"GRPCUseTLS,omitempty"` TLSServerName string `protobuf:"bytes,27,opt,name=TLSServerName,proto3" json:"TLSServerName,omitempty"` @@ -283,71 +285,72 @@ func init() { func init() { proto.RegisterFile("proto/pbservice/healthcheck.proto", fileDescriptor_8a6f7448747c9fbe) } var fileDescriptor_8a6f7448747c9fbe = []byte{ - // 1016 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcf, 0x6f, 0xe3, 0x44, - 0x14, 0x8e, 0x9b, 0x36, 0x8d, 0x27, 0x6d, 0xb7, 0x9d, 0xed, 0x96, 0xd9, 0x2e, 0x72, 0x43, 0xe0, - 0x10, 0x44, 0x71, 0xa4, 0x22, 0x10, 0x20, 0x01, 0x6a, 0x92, 0xfd, 0x11, 0xd4, 0x2e, 0xc1, 0x31, - 0x7b, 0xe0, 0xe6, 0x3a, 0x93, 0xc4, 0x8a, 0xe3, 0x89, 0xc6, 0xe3, 0xaa, 0xe1, 0xca, 0x3f, 0x80, - 0xc4, 0x65, 0xff, 0xa4, 0x1e, 0x7b, 0xe4, 0x54, 0xa0, 0xfd, 0x27, 0x10, 0x27, 0x34, 0x6f, 0xec, - 0xd4, 0xd9, 0x78, 0x49, 0x58, 0x2d, 0xa7, 0xcc, 0x7c, 0xef, 0xbd, 0x19, 0xcf, 0x7b, 0xdf, 0xf7, - 0xb5, 0xe8, 0xbd, 0x31, 0x67, 0x82, 0xd5, 0xc6, 0x67, 0x21, 0xe5, 0xe7, 0x9e, 0x4b, 0x6b, 0x03, - 0xea, 0xf8, 0x62, 0xe0, 0x0e, 0xa8, 0x3b, 0x34, 0x21, 0x86, 0xf5, 0x69, 0x70, 0xdf, 0xe8, 0x33, - 0xd6, 0xf7, 0x69, 0x0d, 0x02, 0x67, 0x51, 0xaf, 0xd6, 0x8d, 0xb8, 0x23, 0x3c, 0x16, 0xa8, 0xd4, - 0xfd, 0x47, 0xc9, 0x69, 0x2e, 0x1b, 0x8d, 0x58, 0x50, 0x53, 0x3f, 0x71, 0x70, 0xb7, 0xcf, 0xfa, - 0x4c, 0x25, 0xc8, 0x95, 0x42, 0x2b, 0x3f, 0xaf, 0xa2, 0xd2, 0x33, 0xb8, 0xb3, 0x21, 0xef, 0xc4, - 0x18, 0xad, 0x3e, 0x67, 0x5d, 0x4a, 0xb4, 0xb2, 0x56, 0xd5, 0x2d, 0x58, 0xe3, 0xa7, 0x68, 0x1d, - 0x82, 0xad, 0x26, 0x59, 0x91, 0x70, 0xfd, 0xe3, 0xbf, 0xaf, 0x0f, 0x3e, 0xec, 0x7b, 0x62, 0x10, - 0x9d, 0x99, 0x2e, 0x1b, 0xd5, 0x06, 0x4e, 0x38, 0xf0, 0x5c, 0xc6, 0xc7, 0x35, 0x97, 0x05, 0x61, - 0xe4, 0xd7, 0xc4, 0x64, 0x4c, 0x43, 0x33, 0x2e, 0xb2, 0x92, 0x6a, 0x38, 0xdc, 0x19, 0x51, 0x92, - 0x8f, 0x0f, 0x77, 0x46, 0x14, 0xef, 0xa1, 0x42, 0x47, 0x38, 0x22, 0x0a, 0xc9, 0x2a, 0xa0, 0xf1, - 0x0e, 0xef, 0xa2, 0xb5, 0xe7, 0x4c, 0xd0, 0x90, 0xac, 0x01, 0xac, 0x36, 0x32, 0xfb, 0xbb, 0x48, - 0x8c, 0x23, 0x41, 0x0a, 0x2a, 0x5b, 0xed, 0xf0, 0xbb, 0x48, 0xef, 0xa8, 0x26, 0xb5, 0x9a, 0x64, - 0x1d, 0x42, 0x77, 0x00, 0x2e, 0xa3, 0x52, 0xbc, 0x81, 0xeb, 0x8b, 0x10, 0x4f, 0x43, 0xa9, 0x0c, - 0xdb, 0xe9, 0x87, 0x44, 0x2f, 0xe7, 0x53, 0x19, 0x12, 0x92, 0xdf, 0x6e, 0x4f, 0xc6, 0x94, 0x6c, - 0xa8, 0x6f, 0x97, 0x6b, 0xfc, 0x04, 0xa1, 0x26, 0xed, 0x79, 0x81, 0x27, 0x67, 0x40, 0x50, 0x59, - 0xab, 0x96, 0x8e, 0xca, 0xe6, 0x74, 0x5e, 0x66, 0xaa, 0xb1, 0x77, 0x79, 0xf5, 0xd5, 0xcb, 0xeb, - 0x83, 0x9c, 0x95, 0xaa, 0xc4, 0x5f, 0x20, 0xdd, 0x72, 0x7a, 0xa2, 0x15, 0x74, 0xe9, 0x05, 0x29, - 0xc1, 0x31, 0x3b, 0x66, 0x3c, 0xbc, 0x69, 0xa0, 0x5e, 0x94, 0x75, 0x57, 0xd7, 0x07, 0x9a, 0x75, - 0x97, 0x8d, 0x9b, 0x68, 0xeb, 0x71, 0x20, 0x28, 0x1f, 0x73, 0x2f, 0xa4, 0xa7, 0x54, 0x38, 0x64, - 0x13, 0xea, 0xf7, 0x92, 0xfa, 0xd9, 0x68, 0x7c, 0xf9, 0x2b, 0x35, 0x95, 0xf7, 0x81, 0x04, 0x5d, - 0xca, 0x5f, 0x38, 0x7e, 0x44, 0x65, 0xef, 0x61, 0x41, 0x34, 0xe8, 0x83, 0xda, 0x54, 0xfe, 0x2a, - 0xa0, 0x07, 0x99, 0x2f, 0x92, 0xbd, 0x79, 0x66, 0xdb, 0xed, 0x84, 0x34, 0x72, 0x8d, 0x3f, 0x40, - 0x9b, 0xf6, 0x49, 0x47, 0x76, 0x90, 0x72, 0xe8, 0xfa, 0x7d, 0x08, 0xce, 0x82, 0x49, 0xd6, 0xd0, - 0x1b, 0xbf, 0xa0, 0xdc, 0xeb, 0x4d, 0x80, 0x60, 0x45, 0x6b, 0x16, 0xc4, 0xdf, 0xa2, 0x82, 0xfa, - 0x3c, 0x92, 0x2f, 0xe7, 0xab, 0xa5, 0xa3, 0xc3, 0x45, 0x3d, 0x36, 0x55, 0xfa, 0xe3, 0x40, 0xf0, - 0x49, 0xfc, 0xe4, 0xf8, 0x04, 0xc9, 0xa0, 0x53, 0x2a, 0x06, 0xac, 0x9b, 0xf0, 0x4d, 0xed, 0xe4, - 0x1b, 0xea, 0xac, 0x3b, 0x21, 0x58, 0xbd, 0x41, 0xae, 0xf1, 0x36, 0xca, 0xdb, 0x8d, 0x76, 0xcc, - 0x40, 0xb9, 0xc4, 0xdf, 0xa0, 0x62, 0x4b, 0xb6, 0xee, 0xdc, 0xf1, 0x81, 0x81, 0xa5, 0xa3, 0x87, - 0xa6, 0x12, 0xa5, 0x99, 0x88, 0xd2, 0x6c, 0xc6, 0xa2, 0x54, 0x03, 0x7b, 0xf9, 0xfb, 0x81, 0x66, - 0x4d, 0x8b, 0xe4, 0x83, 0x15, 0x65, 0x4f, 0x9d, 0x8b, 0x8e, 0xf7, 0x13, 0x25, 0x7a, 0x59, 0xab, - 0x6e, 0x5a, 0xb3, 0x20, 0xfe, 0x0a, 0xad, 0xdb, 0xde, 0x88, 0xb2, 0x48, 0x00, 0x99, 0x97, 0xbc, - 0x25, 0xa9, 0xc1, 0x43, 0x64, 0x34, 0x29, 0xa7, 0x7d, 0x2f, 0x14, 0x94, 0x37, 0xb8, 0x27, 0x3c, - 0xd7, 0xf1, 0x63, 0x32, 0x1f, 0xf7, 0x04, 0xe5, 0x20, 0x81, 0x25, 0x4f, 0x5d, 0x70, 0x14, 0x36, - 0x10, 0xea, 0xb8, 0xdc, 0x1b, 0x8b, 0x63, 0xde, 0x0f, 0x09, 0x02, 0xc6, 0xa4, 0x10, 0x7c, 0x88, - 0x76, 0x9a, 0xcc, 0x1d, 0x52, 0xde, 0x60, 0x81, 0x70, 0xbc, 0x80, 0xf2, 0x56, 0x13, 0x48, 0xae, - 0x5b, 0xf3, 0x01, 0x49, 0xbd, 0xce, 0x80, 0xfa, 0x7e, 0xac, 0x33, 0xb5, 0x91, 0xc3, 0x79, 0x6a, - 0xb5, 0x1b, 0xc0, 0x6d, 0xdd, 0x82, 0xb5, 0xbc, 0x57, 0xfe, 0xfe, 0x10, 0x52, 0xfb, 0xa4, 0x43, - 0xb6, 0x80, 0x37, 0x29, 0x44, 0x5a, 0xc2, 0xb1, 0xef, 0x39, 0x21, 0xd8, 0xd9, 0x3d, 0x65, 0x09, - 0x53, 0x00, 0x57, 0xd0, 0x06, 0x6c, 0xe2, 0xa7, 0x90, 0x6d, 0x48, 0x98, 0xc1, 0xf0, 0xa7, 0x28, - 0x6f, 0xdb, 0x27, 0x64, 0x67, 0xf9, 0x5e, 0xc9, 0xfc, 0xfd, 0xef, 0x13, 0x31, 0x01, 0xfd, 0x24, - 0x89, 0x86, 0x74, 0x12, 0x6b, 0x43, 0x2e, 0xf1, 0x21, 0x5a, 0x3b, 0x07, 0x79, 0xad, 0xc4, 0x52, - 0x9d, 0x61, 0x73, 0xa2, 0x42, 0x4b, 0x25, 0x7d, 0xb9, 0xf2, 0xb9, 0x56, 0xf9, 0x55, 0x47, 0x3a, - 0x50, 0x1c, 0x6c, 0x27, 0xe5, 0xc7, 0xda, 0x5b, 0xf1, 0xe3, 0x95, 0x4c, 0x3f, 0xce, 0x67, 0xfb, - 0xf1, 0x6a, 0xda, 0x8f, 0x67, 0x87, 0xbf, 0x36, 0x37, 0xfc, 0xc4, 0x19, 0x0a, 0x29, 0x67, 0xf8, - 0x7a, 0xaa, 0xe6, 0x5d, 0x50, 0x73, 0xda, 0x31, 0xa7, 0x8f, 0x5c, 0x4a, 0xc1, 0xeb, 0x99, 0x0a, - 0xde, 0x9f, 0x57, 0x70, 0x31, 0x5b, 0xc1, 0xfa, 0x9b, 0x28, 0x78, 0x86, 0x57, 0x68, 0x11, 0xaf, - 0x4a, 0x19, 0xbc, 0xca, 0x54, 0xc4, 0xc6, 0x42, 0x45, 0x6c, 0x66, 0x29, 0x62, 0xeb, 0xb5, 0x8a, - 0xb8, 0x37, 0xa7, 0x88, 0x39, 0x4b, 0x7e, 0xb4, 0x94, 0x25, 0x6f, 0x67, 0x59, 0x72, 0xca, 0xa1, - 0x76, 0xde, 0xc0, 0xa1, 0x62, 0x69, 0xe1, 0xff, 0x26, 0x2d, 0x7c, 0x84, 0x76, 0x3b, 0x91, 0xeb, - 0xd2, 0x30, 0xac, 0xd3, 0x1e, 0xe3, 0xb4, 0xed, 0x84, 0xa1, 0x17, 0xf4, 0xc9, 0x83, 0xb2, 0x56, - 0x5d, 0xb3, 0x32, 0x63, 0xf8, 0x33, 0xb4, 0xf7, 0xc4, 0xf1, 0xfc, 0x88, 0xd3, 0x38, 0x90, 0xb8, - 0x18, 0xd9, 0x83, 0xaa, 0xd7, 0x44, 0xe5, 0x9c, 0xdb, 0x9c, 0x5d, 0x4c, 0x80, 0xbf, 0xef, 0xa8, - 0x39, 0x4f, 0x81, 0x69, 0x14, 0x86, 0x40, 0x52, 0x51, 0x98, 0xc4, 0x62, 0x03, 0xbe, 0xff, 0xf6, - 0x0c, 0x78, 0xee, 0x4f, 0xca, 0x43, 0x78, 0xd7, 0x2c, 0xf8, 0x3f, 0xb8, 0x52, 0xfd, 0xf4, 0xf2, - 0x4f, 0x23, 0x77, 0x79, 0x63, 0x68, 0x57, 0x37, 0x86, 0xf6, 0xc7, 0x8d, 0xa1, 0xfd, 0x72, 0x6b, - 0xe4, 0x5e, 0xde, 0x1a, 0xb9, 0xab, 0x5b, 0x23, 0xf7, 0xdb, 0xad, 0x91, 0xfb, 0xf1, 0xa3, 0x7f, - 0x33, 0xa5, 0x57, 0xfe, 0xf5, 0x3d, 0x2b, 0x00, 0xf0, 0xc9, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, - 0xf4, 0xca, 0x84, 0xe7, 0x14, 0x0b, 0x00, 0x00, + // 1031 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x4d, 0x73, 0xdb, 0x44, + 0x18, 0xb6, 0xe2, 0x7c, 0x69, 0x9d, 0xa4, 0xc9, 0x36, 0x0d, 0xdb, 0xb4, 0xa3, 0x98, 0xc0, 0xc1, + 0x0c, 0x41, 0x9e, 0x31, 0x03, 0x03, 0xcc, 0x00, 0x13, 0xdb, 0x6d, 0x62, 0x26, 0x09, 0x46, 0x16, + 0x3d, 0x70, 0x53, 0xe4, 0xb5, 0xad, 0xb1, 0xac, 0xf5, 0xac, 0x56, 0x99, 0x98, 0x2b, 0x7f, 0xa0, + 0xc7, 0xfe, 0x07, 0xfe, 0x48, 0x8e, 0x39, 0x72, 0x0a, 0x90, 0xfc, 0x0b, 0x4e, 0xcc, 0xbe, 0x2b, + 0x39, 0x72, 0xad, 0x62, 0xd3, 0x69, 0x4f, 0x7e, 0x3f, 0x77, 0xb5, 0xef, 0xfb, 0x3c, 0x4f, 0x82, + 0x3e, 0x1c, 0x72, 0x26, 0x58, 0x79, 0x78, 0x1e, 0x52, 0x7e, 0xe1, 0xb9, 0xb4, 0xdc, 0xa3, 0x8e, + 0x2f, 0x7a, 0x6e, 0x8f, 0xba, 0x7d, 0x13, 0x72, 0x58, 0x1f, 0x27, 0x77, 0x8d, 0x2e, 0x63, 0x5d, + 0x9f, 0x96, 0x21, 0x71, 0x1e, 0x75, 0xca, 0xed, 0x88, 0x3b, 0xc2, 0x63, 0x81, 0x2a, 0xdd, 0x7d, + 0x92, 0x9c, 0xe6, 0xb2, 0xc1, 0x80, 0x05, 0x65, 0xf5, 0x13, 0x27, 0xb7, 0xbb, 0xac, 0xcb, 0x54, + 0x81, 0xb4, 0x54, 0x74, 0xff, 0xb7, 0x45, 0x54, 0x38, 0x86, 0x3b, 0x6b, 0xf2, 0x4e, 0x8c, 0xd1, + 0xe2, 0x19, 0x6b, 0x53, 0xa2, 0x15, 0xb5, 0x92, 0x6e, 0x81, 0x8d, 0x8f, 0xd0, 0x0a, 0x24, 0x1b, + 0x75, 0xb2, 0x20, 0xc3, 0xd5, 0xcf, 0xfe, 0xb9, 0xd9, 0xfb, 0xa4, 0xeb, 0x89, 0x5e, 0x74, 0x6e, + 0xba, 0x6c, 0x50, 0xee, 0x39, 0x61, 0xcf, 0x73, 0x19, 0x1f, 0x96, 0x5d, 0x16, 0x84, 0x91, 0x5f, + 0x16, 0xa3, 0x21, 0x0d, 0xcd, 0xb8, 0xc9, 0x4a, 0xba, 0xe1, 0x70, 0x67, 0x40, 0x49, 0x3e, 0x3e, + 0xdc, 0x19, 0x50, 0xbc, 0x83, 0x96, 0x5b, 0xc2, 0x11, 0x51, 0x48, 0x16, 0x21, 0x1a, 0x7b, 0x78, + 0x1b, 0x2d, 0x9d, 0x31, 0x41, 0x43, 0xb2, 0x04, 0x61, 0xe5, 0xc8, 0xea, 0x1f, 0x23, 0x31, 0x8c, + 0x04, 0x59, 0x56, 0xd5, 0xca, 0xc3, 0x4f, 0x91, 0xde, 0x52, 0x43, 0x6a, 0xd4, 0xc9, 0x0a, 0xa4, + 0xee, 0x03, 0xb8, 0x88, 0x0a, 0xb1, 0x03, 0xd7, 0xaf, 0x42, 0x3e, 0x1d, 0x4a, 0x55, 0xd8, 0x4e, + 0x37, 0x24, 0x7a, 0x31, 0x9f, 0xaa, 0x90, 0x21, 0xf9, 0xed, 0xf6, 0x68, 0x48, 0xc9, 0x9a, 0xfa, + 0x76, 0x69, 0xe3, 0xe7, 0x08, 0xd5, 0x69, 0xc7, 0x0b, 0x3c, 0xb9, 0x03, 0x82, 0x8a, 0x5a, 0xa9, + 0x50, 0x29, 0x9a, 0xe3, 0x7d, 0x99, 0xa9, 0xc1, 0xde, 0xd7, 0x55, 0x17, 0xaf, 0x6e, 0xf6, 0x72, + 0x56, 0xaa, 0x13, 0x7f, 0x8d, 0x74, 0xcb, 0xe9, 0x88, 0x46, 0xd0, 0xa6, 0x97, 0xa4, 0x00, 0xc7, + 0x6c, 0x99, 0xf1, 0xf2, 0xc6, 0x89, 0xea, 0xaa, 0xec, 0xbb, 0xbe, 0xd9, 0xd3, 0xac, 0xfb, 0x6a, + 0x5c, 0x47, 0x1b, 0xcf, 0x02, 0x41, 0xf9, 0x90, 0x7b, 0x21, 0x3d, 0xa5, 0xc2, 0x21, 0xeb, 0xd0, + 0xbf, 0x93, 0xf4, 0x4f, 0x66, 0xe3, 0xcb, 0x5f, 0xeb, 0xd9, 0xff, 0x08, 0x40, 0xd0, 0xa6, 0xfc, + 0x85, 0xe3, 0x47, 0x54, 0xce, 0x1e, 0x0c, 0xa2, 0xc1, 0x1c, 0x94, 0xb3, 0xff, 0x72, 0x05, 0x3d, + 0xca, 0x7c, 0x91, 0x9c, 0xcd, 0xb1, 0x6d, 0x37, 0x13, 0xd0, 0x48, 0x1b, 0x7f, 0x8c, 0xd6, 0xed, + 0x93, 0x96, 0x9c, 0x20, 0xe5, 0x30, 0xf5, 0x87, 0x90, 0x9c, 0x0c, 0x26, 0x55, 0x7d, 0x6f, 0xf8, + 0x82, 0x72, 0xaf, 0x33, 0x02, 0x80, 0xad, 0x5a, 0x93, 0x41, 0xfc, 0x03, 0x5a, 0x56, 0x9f, 0x47, + 0xf2, 0xc5, 0x7c, 0xa9, 0x50, 0x39, 0x98, 0x35, 0x63, 0x53, 0x95, 0x3f, 0x0b, 0x04, 0x1f, 0xc5, + 0x4f, 0x8e, 0x4f, 0x90, 0x08, 0x3a, 0xa5, 0xa2, 0xc7, 0xda, 0x09, 0xde, 0x94, 0x27, 0xdf, 0x50, + 0x65, 0xed, 0x11, 0xc1, 0xea, 0x0d, 0xd2, 0xc6, 0x9b, 0x28, 0x6f, 0xd7, 0x9a, 0x31, 0x02, 0xa5, + 0x89, 0xbf, 0x47, 0xab, 0x0d, 0x39, 0xba, 0x0b, 0xc7, 0x07, 0x04, 0x16, 0x2a, 0x8f, 0x4d, 0x45, + 0x4a, 0x33, 0x21, 0xa5, 0x59, 0x8f, 0x49, 0xa9, 0x16, 0xf6, 0xea, 0xcf, 0x3d, 0xcd, 0x1a, 0x37, + 0xc9, 0x07, 0x2b, 0xc8, 0x9e, 0x3a, 0x97, 0x2d, 0xef, 0x57, 0x4a, 0xf4, 0xa2, 0x56, 0x5a, 0xb7, + 0x26, 0x83, 0xf8, 0x5b, 0xb4, 0x62, 0x7b, 0x03, 0xca, 0x22, 0x01, 0x60, 0x9e, 0xf3, 0x96, 0xa4, + 0x07, 0xf7, 0x91, 0x51, 0xa7, 0x9c, 0x76, 0xbd, 0x50, 0x50, 0x5e, 0xe3, 0x9e, 0xf0, 0x5c, 0xc7, + 0x8f, 0xc1, 0x7c, 0xd8, 0x11, 0x94, 0x03, 0x05, 0xe6, 0x3c, 0x75, 0xc6, 0x51, 0xd8, 0x40, 0xa8, + 0xe5, 0x72, 0x6f, 0x28, 0x0e, 0x79, 0x37, 0x24, 0x08, 0x10, 0x93, 0x8a, 0xe0, 0x03, 0xb4, 0x55, + 0x67, 0x6e, 0x9f, 0xf2, 0x1a, 0x0b, 0x84, 0xe3, 0x05, 0x94, 0x37, 0xea, 0x00, 0x72, 0xdd, 0x9a, + 0x4e, 0x48, 0xe8, 0xb5, 0x7a, 0xd4, 0xf7, 0x63, 0x9e, 0x29, 0x47, 0x2e, 0xed, 0xb8, 0xd2, 0x6c, + 0x9c, 0x1d, 0x91, 0x6d, 0xb5, 0x34, 0xe5, 0xc9, 0xa5, 0x1d, 0x59, 0xcd, 0x1a, 0x60, 0x5e, 0xb7, + 0xc0, 0x96, 0xdf, 0x23, 0x7f, 0x7f, 0x0e, 0xa9, 0x7d, 0xd2, 0x22, 0x1b, 0x80, 0xa7, 0x54, 0x44, + 0x4a, 0xc5, 0xa1, 0xef, 0x39, 0x21, 0xc8, 0xdc, 0x03, 0x25, 0x15, 0xe3, 0x00, 0xde, 0x47, 0x6b, + 0xe0, 0xc4, 0x4f, 0x24, 0x9b, 0x50, 0x30, 0x11, 0xc3, 0x5f, 0xa0, 0xbc, 0x6d, 0x9f, 0x90, 0xad, + 0xf9, 0x67, 0x28, 0xeb, 0x77, 0x7f, 0x4a, 0x48, 0x06, 0xb0, 0x94, 0xe0, 0xea, 0xd3, 0x51, 0xcc, + 0x19, 0x69, 0xe2, 0x03, 0xb4, 0x74, 0x01, 0xb4, 0x5b, 0x88, 0x29, 0x3c, 0x81, 0xf2, 0x84, 0x9d, + 0x96, 0x2a, 0xfa, 0x66, 0xe1, 0x2b, 0x6d, 0xff, 0x77, 0x1d, 0xe9, 0x00, 0x7d, 0x90, 0xa3, 0x94, + 0x4e, 0x6b, 0xef, 0x44, 0xa7, 0x17, 0x32, 0x75, 0x3a, 0x9f, 0xad, 0xd3, 0x8b, 0x69, 0x9d, 0x9e, + 0x04, 0xc5, 0xd2, 0x14, 0x28, 0x12, 0xc5, 0x58, 0x4e, 0x29, 0xc6, 0x77, 0x63, 0x96, 0x6f, 0x03, + 0xcb, 0xd3, 0x4a, 0x3a, 0x7e, 0xe4, 0x5c, 0xcc, 0x5e, 0xc9, 0x64, 0xf6, 0xee, 0x34, 0xb3, 0x57, + 0xb3, 0x99, 0xad, 0xbf, 0x0d, 0xb3, 0x27, 0x70, 0x85, 0x66, 0xe1, 0xaa, 0x90, 0x81, 0xab, 0x4c, + 0xa6, 0xac, 0xcd, 0x64, 0xca, 0x7a, 0x36, 0x53, 0x9e, 0x66, 0x32, 0x65, 0xe3, 0x8d, 0x4c, 0x79, + 0x30, 0xc5, 0x94, 0x29, 0x09, 0x7f, 0x32, 0x97, 0x84, 0x6f, 0x66, 0x49, 0x78, 0x4a, 0xd1, 0xb6, + 0xde, 0x42, 0xd1, 0x62, 0xca, 0xe1, 0xff, 0x47, 0x39, 0x5c, 0x41, 0xdb, 0xad, 0xc8, 0x75, 0x69, + 0x18, 0x56, 0x69, 0x87, 0x71, 0xda, 0x74, 0xc2, 0xd0, 0x0b, 0xba, 0xe4, 0x51, 0x51, 0x2b, 0x2d, + 0x59, 0x99, 0x39, 0xfc, 0x25, 0xda, 0x79, 0xee, 0x78, 0x7e, 0xc4, 0x69, 0x9c, 0x48, 0x54, 0x8f, + 0xec, 0x40, 0xd7, 0x1b, 0xb2, 0x72, 0xff, 0x4d, 0xce, 0x2e, 0x47, 0x80, 0xeb, 0x0f, 0xd4, 0xfe, + 0xc7, 0x81, 0x71, 0x16, 0x96, 0x40, 0x52, 0x59, 0xd8, 0xc4, 0x6c, 0xc1, 0x7e, 0xf8, 0xee, 0x04, + 0x7b, 0xea, 0x4f, 0xd0, 0x63, 0x78, 0xd7, 0x64, 0xf0, 0x3d, 0xa8, 0x55, 0xf5, 0xf4, 0xea, 0x6f, + 0x23, 0x77, 0x75, 0x6b, 0x68, 0xd7, 0xb7, 0x86, 0xf6, 0xd7, 0xad, 0xa1, 0xbd, 0xbc, 0x33, 0x72, + 0xaf, 0xee, 0x8c, 0xdc, 0xf5, 0x9d, 0x91, 0xfb, 0xe3, 0xce, 0xc8, 0xfd, 0xf2, 0xe9, 0x7f, 0x89, + 0xd5, 0x6b, 0xff, 0x2a, 0x9f, 0x2f, 0x43, 0xe0, 0xf3, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x5b, + 0x4c, 0x80, 0x35, 0x44, 0x0b, 0x00, 0x00, } func (m *HealthCheck) Marshal() (dAtA []byte, err error) { @@ -527,6 +530,15 @@ func (m *HealthCheckDefinition) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.H2PING) > 0 { + i -= len(m.H2PING) + copy(dAtA[i:], m.H2PING) + i = encodeVarintHealthcheck(dAtA, i, uint64(len(m.H2PING))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa2 + } if len(m.TLSServerName) > 0 { i -= len(m.TLSServerName) copy(dAtA[i:], m.TLSServerName) @@ -718,6 +730,15 @@ func (m *CheckType) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.H2PING) > 0 { + i -= len(m.H2PING) + copy(dAtA[i:], m.H2PING) + i = encodeVarintHealthcheck(dAtA, i, uint64(len(m.H2PING))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xe2 + } if len(m.TLSServerName) > 0 { i -= len(m.TLSServerName) copy(dAtA[i:], m.TLSServerName) @@ -1118,6 +1139,10 @@ func (m *HealthCheckDefinition) Size() (n int) { if l > 0 { n += 2 + l + sovHealthcheck(uint64(l)) } + l = len(m.H2PING) + if l > 0 { + n += 2 + l + sovHealthcheck(uint64(l)) + } return n } @@ -1229,6 +1254,10 @@ func (m *CheckType) Size() (n int) { if l > 0 { n += 2 + l + sovHealthcheck(uint64(l)) } + l = len(m.H2PING) + if l > 0 { + n += 2 + l + sovHealthcheck(uint64(l)) + } return n } @@ -2496,6 +2525,38 @@ func (m *HealthCheckDefinition) Unmarshal(dAtA []byte) error { } m.TLSServerName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 20: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field H2PING", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHealthcheck + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHealthcheck + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHealthcheck + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.H2PING = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipHealthcheck(dAtA[iNdEx:]) @@ -3451,6 +3512,38 @@ func (m *CheckType) Unmarshal(dAtA []byte) error { } m.TLSServerName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 28: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field H2PING", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHealthcheck + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHealthcheck + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHealthcheck + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.H2PING = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipHealthcheck(dAtA[iNdEx:]) diff --git a/proto/pbservice/healthcheck.proto b/proto/pbservice/healthcheck.proto index a5e4386330..cc8fb71c6b 100644 --- a/proto/pbservice/healthcheck.proto +++ b/proto/pbservice/healthcheck.proto @@ -76,6 +76,7 @@ message HealthCheckDefinition { repeated string ScriptArgs = 10; string DockerContainerID = 11; string Shell = 12; + string H2PING = 20; string GRPC = 13; bool GRPCUseTLS = 14; string AliasNode = 15; @@ -86,10 +87,10 @@ message HealthCheckDefinition { // CheckType is used to create either the CheckMonitor or the CheckTTL. // The following types are supported: Script, HTTP, TCP, Docker, TTL, GRPC, -// Alias. Script, -// HTTP, Docker, TCP and GRPC all require Interval. Only one of the types may +// Alias. Script, H2PING, +// HTTP, Docker, TCP, H2PING and GRPC all require Interval. Only one of the types may // to be provided: TTL or Script/Interval or HTTP/Interval or TCP/Interval or -// Docker/Interval or GRPC/Interval or AliasService. +// Docker/Interval or GRPC/Interval or H2PING/Interval or AliasService. // // mog annotation: // @@ -116,6 +117,7 @@ message CheckType { string AliasService = 11; string DockerContainerID = 12; string Shell = 13; + string H2PING = 28; string GRPC = 14; bool GRPCUseTLS = 15; string TLSServerName = 27; @@ -142,4 +144,4 @@ message CheckType { // mog: func-to=int func-from=int32 int32 OutputMaxSize = 25; -} \ No newline at end of file +} diff --git a/website/content/api-docs/agent/check.mdx b/website/content/api-docs/agent/check.mdx index 2da114c7ec..67819a944b 100644 --- a/website/content/api-docs/agent/check.mdx +++ b/website/content/api-docs/agent/check.mdx @@ -162,6 +162,11 @@ The table below shows this endpoint's support for If TLS is enabled, then by default, a valid TLS certificate is expected. Certificate verification can be turned off by setting `TLSSkipVerify` to `true`. +- `H2PING` `(string "")` - Specifies an address that uses http2 with TLS to run a ping check on. + At the specified `Interval`, a connection is made to the address, and a ping is sent. + If the ping is successful, the check will be classified as `passing`, otherwise it will be marked as `critical`. + A valid SSL certificate is required by default, but verification can be removed with `TLSSkipVerify`. + - `HTTP` `(string: "")` - Specifies an `HTTP` check to perform a `GET` request against the value of `HTTP` (expected to be a URL) every `Interval`. If the response is any `2xx` code, the check is `passing`. If the response is `429 Too Many Requests`, the check is `warning`. Otherwise, the check is diff --git a/website/content/docs/discovery/checks.mdx b/website/content/docs/discovery/checks.mdx index 1e41bd508e..d6789a9d20 100644 --- a/website/content/docs/discovery/checks.mdx +++ b/website/content/docs/discovery/checks.mdx @@ -120,6 +120,13 @@ There are several different kinds of checks: `tls_skip_verify` field to `true` in the check definition. To check on a specific service instead of the whole gRPC server, add the service identifier after the `gRPC` check's endpoint in the following format `/:service_identifier`. +- `H2ping + Interval` - These checks test an endpoint that uses http2 with TLS + by connecting to the endpoint and sending a ping frame. If the ping is successful + within a specified timeout, then the check is updated as passing. + The timeout defaults to 10 seconds, but is configurable using the `timeout` field. A valid + certificate is required, unless `tls_skip_verify` is set to `true`. + The check will be run on the interval specified by the `interval` field. + - `Alias` - These checks alias the health state of another registered node or service. The state of the check will be updated asynchronously, but is nearly instant. For aliased services on the same agent, the local state is monitored @@ -235,6 +242,19 @@ A gRPC check for the specific `my_service` service: } ``` +A h2ping check: + +```javascript +{ + "check": { + "id": "h2ping-check", + "name": "h2ping", + "h2ping": "localhost:22222", + "interval": "10s", + } +} +``` + An alias check for a local service: ```javascript