* UDP check for service stanza #12221 * add pass status on timeout condition * delete useless files * Update check_test.go improve comment in test * fix test * fix requested changes and update TestRuntimeConfig_Sanitize.golden * add freeport to TestCheckUDPCritical * improve comment for CheckUDP struct * fix requested changes * fix requested changes * fix requested changes * add UDP to proto * add UDP to proto and add a changelog * add requested test on agent_endpoint_test.go * add test for given endpoints * fix failing tests * add documentation for udp healthcheck * regenerate proto using buf * Update website/content/api-docs/agent/check.mdx Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com> * Update website/content/api-docs/agent/check.mdx Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com> * Update website/content/docs/discovery/checks.mdx Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com> * Update website/content/docs/ecs/configuration-reference.mdx Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com> * Update website/content/docs/ecs/configuration-reference.mdx Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com> * add debug echo * add debug circle-ci * add debug circle-ci bash * use echo instead of status_stage * remove debug and status from devtools script and use echo instead * Update website/content/api-docs/agent/check.mdx Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com> * fix test * replace status_stage with status * replace functions with echo Co-authored-by: Dhia Ayachi <dhia@hashicorp.com> Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com> Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com>
This commit is contained in:
parent
977b39cde1
commit
f155ff347c
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:feature
|
||||||
|
checks: add UDP health checks..
|
||||||
|
```
|
|
@ -248,6 +248,9 @@ type Agent struct {
|
||||||
// checkTCPs maps the check ID to an associated TCP check
|
// checkTCPs maps the check ID to an associated TCP check
|
||||||
checkTCPs map[structs.CheckID]*checks.CheckTCP
|
checkTCPs map[structs.CheckID]*checks.CheckTCP
|
||||||
|
|
||||||
|
// checkUDPs maps the check ID to an associated UDP check
|
||||||
|
checkUDPs map[structs.CheckID]*checks.CheckUDP
|
||||||
|
|
||||||
// checkGRPCs maps the check ID to an associated GRPC check
|
// checkGRPCs maps the check ID to an associated GRPC check
|
||||||
checkGRPCs map[structs.CheckID]*checks.CheckGRPC
|
checkGRPCs map[structs.CheckID]*checks.CheckGRPC
|
||||||
|
|
||||||
|
@ -401,6 +404,7 @@ func New(bd BaseDeps) (*Agent, error) {
|
||||||
checkHTTPs: make(map[structs.CheckID]*checks.CheckHTTP),
|
checkHTTPs: make(map[structs.CheckID]*checks.CheckHTTP),
|
||||||
checkH2PINGs: make(map[structs.CheckID]*checks.CheckH2PING),
|
checkH2PINGs: make(map[structs.CheckID]*checks.CheckH2PING),
|
||||||
checkTCPs: make(map[structs.CheckID]*checks.CheckTCP),
|
checkTCPs: make(map[structs.CheckID]*checks.CheckTCP),
|
||||||
|
checkUDPs: make(map[structs.CheckID]*checks.CheckUDP),
|
||||||
checkGRPCs: make(map[structs.CheckID]*checks.CheckGRPC),
|
checkGRPCs: make(map[structs.CheckID]*checks.CheckGRPC),
|
||||||
checkDockers: make(map[structs.CheckID]*checks.CheckDocker),
|
checkDockers: make(map[structs.CheckID]*checks.CheckDocker),
|
||||||
checkAliases: make(map[structs.CheckID]*checks.CheckAlias),
|
checkAliases: make(map[structs.CheckID]*checks.CheckAlias),
|
||||||
|
@ -1497,6 +1501,9 @@ func (a *Agent) ShutdownAgent() error {
|
||||||
for _, chk := range a.checkTCPs {
|
for _, chk := range a.checkTCPs {
|
||||||
chk.Stop()
|
chk.Stop()
|
||||||
}
|
}
|
||||||
|
for _, chk := range a.checkUDPs {
|
||||||
|
chk.Stop()
|
||||||
|
}
|
||||||
for _, chk := range a.checkGRPCs {
|
for _, chk := range a.checkGRPCs {
|
||||||
chk.Stop()
|
chk.Stop()
|
||||||
}
|
}
|
||||||
|
@ -2796,6 +2803,31 @@ func (a *Agent) addCheck(check *structs.HealthCheck, chkType *structs.CheckType,
|
||||||
tcp.Start()
|
tcp.Start()
|
||||||
a.checkTCPs[cid] = tcp
|
a.checkTCPs[cid] = tcp
|
||||||
|
|
||||||
|
case chkType.IsUDP():
|
||||||
|
if existing, ok := a.checkUDPs[cid]; ok {
|
||||||
|
existing.Stop()
|
||||||
|
delete(a.checkUDPs, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
udp := &checks.CheckUDP{
|
||||||
|
CheckID: cid,
|
||||||
|
ServiceID: sid,
|
||||||
|
UDP: chkType.UDP,
|
||||||
|
Interval: chkType.Interval,
|
||||||
|
Timeout: chkType.Timeout,
|
||||||
|
Logger: a.logger,
|
||||||
|
StatusHandler: statusHandler,
|
||||||
|
}
|
||||||
|
udp.Start()
|
||||||
|
a.checkUDPs[cid] = udp
|
||||||
|
|
||||||
case chkType.IsGRPC():
|
case chkType.IsGRPC():
|
||||||
if existing, ok := a.checkGRPCs[cid]; ok {
|
if existing, ok := a.checkGRPCs[cid]; ok {
|
||||||
existing.Stop()
|
existing.Stop()
|
||||||
|
@ -3095,6 +3127,10 @@ func (a *Agent) cancelCheckMonitors(checkID structs.CheckID) {
|
||||||
check.Stop()
|
check.Stop()
|
||||||
delete(a.checkTCPs, checkID)
|
delete(a.checkTCPs, checkID)
|
||||||
}
|
}
|
||||||
|
if check, ok := a.checkUDPs[checkID]; ok {
|
||||||
|
check.Stop()
|
||||||
|
delete(a.checkUDPs, checkID)
|
||||||
|
}
|
||||||
if check, ok := a.checkGRPCs[checkID]; ok {
|
if check, ok := a.checkGRPCs[checkID]; ok {
|
||||||
check.Stop()
|
check.Stop()
|
||||||
delete(a.checkGRPCs, checkID)
|
delete(a.checkGRPCs, checkID)
|
||||||
|
|
|
@ -2514,6 +2514,48 @@ func TestAgent_RegisterCheck(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAgent_RegisterCheck_UDP(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
a := NewTestAgent(t, "")
|
||||||
|
defer a.Shutdown()
|
||||||
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||||
|
|
||||||
|
args := &structs.CheckDefinition{
|
||||||
|
UDP: "1.1.1.1",
|
||||||
|
Name: "test",
|
||||||
|
Interval: 10 * time.Second,
|
||||||
|
}
|
||||||
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register?token=abc123", jsonReader(args))
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
a.srv.h.ServeHTTP(resp, req)
|
||||||
|
require.Equal(t, http.StatusOK, resp.Code)
|
||||||
|
|
||||||
|
// Ensure we have a check mapping
|
||||||
|
checkID := structs.NewCheckID("test", nil)
|
||||||
|
if existing := a.State.Check(checkID); existing == nil {
|
||||||
|
t.Fatalf("missing test check")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := a.checkUDPs[checkID]; !ok {
|
||||||
|
t.Fatalf("missing test check udp")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the token was configured
|
||||||
|
if token := a.State.CheckToken(checkID); token == "" {
|
||||||
|
t.Fatalf("missing token")
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default, checks start in critical state.
|
||||||
|
state := a.State.Check(checkID)
|
||||||
|
if state.Status != api.HealthCritical {
|
||||||
|
t.Fatalf("bad: %v", state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This verifies all the forms of the new args-style check that we need to
|
// This verifies all the forms of the new args-style check that we need to
|
||||||
// support as a result of https://github.com/hashicorp/consul/issues/3587.
|
// support as a result of https://github.com/hashicorp/consul/issues/3587.
|
||||||
func TestAgent_RegisterCheck_Scripts(t *testing.T) {
|
func TestAgent_RegisterCheck_Scripts(t *testing.T) {
|
||||||
|
@ -3276,6 +3318,10 @@ func testAgent_RegisterService(t *testing.T, extraHCL string) {
|
||||||
{
|
{
|
||||||
TTL: 30 * time.Second,
|
TTL: 30 * time.Second,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
UDP: "1.1.1.1",
|
||||||
|
Interval: 5 * time.Second,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Weights: &structs.Weights{
|
Weights: &structs.Weights{
|
||||||
Passing: 100,
|
Passing: 100,
|
||||||
|
@ -3307,12 +3353,12 @@ func testAgent_RegisterService(t *testing.T, extraHCL string) {
|
||||||
|
|
||||||
// Ensure we have a check mapping
|
// Ensure we have a check mapping
|
||||||
checks := a.State.Checks(structs.WildcardEnterpriseMetaInDefaultPartition())
|
checks := a.State.Checks(structs.WildcardEnterpriseMetaInDefaultPartition())
|
||||||
if len(checks) != 3 {
|
if len(checks) != 4 {
|
||||||
t.Fatalf("bad: %v", checks)
|
t.Fatalf("bad: %v", checks)
|
||||||
}
|
}
|
||||||
for _, c := range checks {
|
for _, c := range checks {
|
||||||
if c.Type != "ttl" {
|
if c.Type != "ttl" && c.Type != "udp" {
|
||||||
t.Fatalf("expected ttl check type, got %s", c.Type)
|
t.Fatalf("expected ttl or udp check type, got %s", c.Type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3362,6 +3408,11 @@ func testAgent_RegisterService_ReRegister(t *testing.T, extraHCL string) {
|
||||||
CheckID: types.CheckID("check_2"),
|
CheckID: types.CheckID("check_2"),
|
||||||
TTL: 30 * time.Second,
|
TTL: 30 * time.Second,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
CheckID: types.CheckID("check_3"),
|
||||||
|
UDP: "1.1.1.1",
|
||||||
|
Interval: 5 * time.Second,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Weights: &structs.Weights{
|
Weights: &structs.Weights{
|
||||||
Passing: 100,
|
Passing: 100,
|
||||||
|
@ -3387,6 +3438,11 @@ func testAgent_RegisterService_ReRegister(t *testing.T, extraHCL string) {
|
||||||
CheckID: types.CheckID("check_3"),
|
CheckID: types.CheckID("check_3"),
|
||||||
TTL: 30 * time.Second,
|
TTL: 30 * time.Second,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
CheckID: types.CheckID("check_3"),
|
||||||
|
UDP: "1.1.1.1",
|
||||||
|
Interval: 5 * time.Second,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Weights: &structs.Weights{
|
Weights: &structs.Weights{
|
||||||
Passing: 100,
|
Passing: 100,
|
||||||
|
@ -3714,6 +3770,231 @@ func testAgent_RegisterService_TranslateKeys(t *testing.T, extraHCL string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAgent_RegisterService_TranslateKeys_UDP(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("normal", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testAgent_RegisterService_TranslateKeys(t, "enable_central_service_config = false")
|
||||||
|
})
|
||||||
|
t.Run("service manager", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testAgent_RegisterService_TranslateKeys(t, "enable_central_service_config = true")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAgent_RegisterService_TranslateKeys_UDP(t *testing.T, extraHCL string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
ip string
|
||||||
|
expectedUDPCheckStart string
|
||||||
|
}{
|
||||||
|
{"127.0.0.1", "127.0.0.1:"}, // private network address
|
||||||
|
{"::1", "[::1]:"}, // shared address space
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.ip, func(t *testing.T) {
|
||||||
|
a := NewTestAgent(t, `
|
||||||
|
connect {}
|
||||||
|
`+extraHCL)
|
||||||
|
defer a.Shutdown()
|
||||||
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||||
|
|
||||||
|
json := `
|
||||||
|
{
|
||||||
|
"name":"test",
|
||||||
|
"port":8000,
|
||||||
|
"enable_tag_override": true,
|
||||||
|
"tagged_addresses": {
|
||||||
|
"lan": {
|
||||||
|
"address": "1.2.3.4",
|
||||||
|
"port": 5353
|
||||||
|
},
|
||||||
|
"wan": {
|
||||||
|
"address": "2.3.4.5",
|
||||||
|
"port": 53
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"some": "meta",
|
||||||
|
"enable_tag_override": "meta is 'opaque' so should not get translated"
|
||||||
|
},
|
||||||
|
"kind": "connect-proxy",` +
|
||||||
|
// Note the uppercase P is important here - it ensures translation works
|
||||||
|
// correctly in case-insensitive way. Without it this test can pass even
|
||||||
|
// when translation is broken for other valid inputs.
|
||||||
|
`"Proxy": {
|
||||||
|
"destination_service_name": "web",
|
||||||
|
"destination_service_id": "web",
|
||||||
|
"local_service_port": 1234,
|
||||||
|
"local_service_address": "` + tt.ip + `",
|
||||||
|
"config": {
|
||||||
|
"destination_type": "proxy.config is 'opaque' so should not get translated"
|
||||||
|
},
|
||||||
|
"upstreams": [
|
||||||
|
{
|
||||||
|
"destination_type": "service",
|
||||||
|
"destination_namespace": "default",
|
||||||
|
"destination_partition": "default",
|
||||||
|
"destination_name": "db",
|
||||||
|
"local_bind_address": "` + tt.ip + `",
|
||||||
|
"local_bind_port": 1234,
|
||||||
|
"config": {
|
||||||
|
"destination_type": "proxy.upstreams.config is 'opaque' so should not get translated"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"connect": {
|
||||||
|
"sidecar_service": {
|
||||||
|
"name":"test-proxy",
|
||||||
|
"port":8001,
|
||||||
|
"enable_tag_override": true,
|
||||||
|
"meta": {
|
||||||
|
"some": "meta",
|
||||||
|
"enable_tag_override": "sidecar_service.meta is 'opaque' so should not get translated"
|
||||||
|
},
|
||||||
|
"kind": "connect-proxy",
|
||||||
|
"proxy": {
|
||||||
|
"destination_service_name": "test",
|
||||||
|
"destination_service_id": "test",
|
||||||
|
"local_service_port": 4321,
|
||||||
|
"local_service_address": "` + tt.ip + `",
|
||||||
|
"upstreams": [
|
||||||
|
{
|
||||||
|
"destination_type": "service",
|
||||||
|
"destination_namespace": "default",
|
||||||
|
"destination_partition": "default",
|
||||||
|
"destination_name": "db",
|
||||||
|
"local_bind_address": "` + tt.ip + `",
|
||||||
|
"local_bind_port": 1234,
|
||||||
|
"config": {
|
||||||
|
"destination_type": "sidecar_service.proxy.upstreams.config is 'opaque' so should not get translated"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"weights":{
|
||||||
|
"passing": 16
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", strings.NewReader(json))
|
||||||
|
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
a.srv.h.ServeHTTP(rr, req)
|
||||||
|
require.Equal(t, 200, rr.Code, "body: %s", rr.Body)
|
||||||
|
|
||||||
|
svc := &structs.NodeService{
|
||||||
|
ID: "test",
|
||||||
|
Service: "test",
|
||||||
|
TaggedAddresses: map[string]structs.ServiceAddress{
|
||||||
|
"lan": {
|
||||||
|
Address: "1.2.3.4",
|
||||||
|
Port: 5353,
|
||||||
|
},
|
||||||
|
"wan": {
|
||||||
|
Address: "2.3.4.5",
|
||||||
|
Port: 53,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Meta: map[string]string{
|
||||||
|
"some": "meta",
|
||||||
|
"enable_tag_override": "meta is 'opaque' so should not get translated",
|
||||||
|
},
|
||||||
|
Port: 8000,
|
||||||
|
EnableTagOverride: true,
|
||||||
|
Weights: &structs.Weights{Passing: 16, Warning: 0},
|
||||||
|
Kind: structs.ServiceKindConnectProxy,
|
||||||
|
Proxy: structs.ConnectProxyConfig{
|
||||||
|
DestinationServiceName: "web",
|
||||||
|
DestinationServiceID: "web",
|
||||||
|
LocalServiceAddress: tt.ip,
|
||||||
|
LocalServicePort: 1234,
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"destination_type": "proxy.config is 'opaque' so should not get translated",
|
||||||
|
},
|
||||||
|
Upstreams: structs.Upstreams{
|
||||||
|
{
|
||||||
|
DestinationType: structs.UpstreamDestTypeService,
|
||||||
|
DestinationName: "db",
|
||||||
|
DestinationNamespace: "default",
|
||||||
|
DestinationPartition: "default",
|
||||||
|
LocalBindAddress: tt.ip,
|
||||||
|
LocalBindPort: 1234,
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"destination_type": "proxy.upstreams.config is 'opaque' so should not get translated",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Connect: structs.ServiceConnect{
|
||||||
|
// The sidecar service is nilled since it is only config sugar and
|
||||||
|
// shouldn't be represented in state. We assert that the translations
|
||||||
|
// there worked by inspecting the registered sidecar below.
|
||||||
|
SidecarService: nil,
|
||||||
|
},
|
||||||
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||||
|
}
|
||||||
|
|
||||||
|
got := a.State.Service(structs.NewServiceID("test", nil))
|
||||||
|
require.Equal(t, svc, got)
|
||||||
|
|
||||||
|
sidecarSvc := &structs.NodeService{
|
||||||
|
Kind: structs.ServiceKindConnectProxy,
|
||||||
|
ID: "test-sidecar-proxy",
|
||||||
|
Service: "test-proxy",
|
||||||
|
Meta: map[string]string{
|
||||||
|
"some": "meta",
|
||||||
|
"enable_tag_override": "sidecar_service.meta is 'opaque' so should not get translated",
|
||||||
|
},
|
||||||
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||||
|
Port: 8001,
|
||||||
|
EnableTagOverride: true,
|
||||||
|
Weights: &structs.Weights{Passing: 1, Warning: 1},
|
||||||
|
LocallyRegisteredAsSidecar: true,
|
||||||
|
Proxy: structs.ConnectProxyConfig{
|
||||||
|
DestinationServiceName: "test",
|
||||||
|
DestinationServiceID: "test",
|
||||||
|
LocalServiceAddress: tt.ip,
|
||||||
|
LocalServicePort: 4321,
|
||||||
|
Upstreams: structs.Upstreams{
|
||||||
|
{
|
||||||
|
DestinationType: structs.UpstreamDestTypeService,
|
||||||
|
DestinationName: "db",
|
||||||
|
DestinationNamespace: "default",
|
||||||
|
DestinationPartition: "default",
|
||||||
|
LocalBindAddress: tt.ip,
|
||||||
|
LocalBindPort: 1234,
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"destination_type": "sidecar_service.proxy.upstreams.config is 'opaque' so should not get translated",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||||
|
}
|
||||||
|
gotSidecar := a.State.Service(structs.NewServiceID("test-sidecar-proxy", nil))
|
||||||
|
hasNoCorrectUDPCheck := true
|
||||||
|
for _, v := range a.checkUDPs {
|
||||||
|
if strings.HasPrefix(v.UDP, tt.expectedUDPCheckStart) {
|
||||||
|
hasNoCorrectUDPCheck = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Println("UDP Check:= ", v)
|
||||||
|
}
|
||||||
|
if hasNoCorrectUDPCheck {
|
||||||
|
t.Fatalf("Did not find the expected UDP Healtcheck '%s' in %#v ", tt.expectedUDPCheckStart, a.checkUDPs)
|
||||||
|
}
|
||||||
|
require.Equal(t, sidecarSvc, gotSidecar)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAgent_RegisterService_ACLDeny(t *testing.T) {
|
func TestAgent_RegisterService_ACLDeny(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("too slow for testing.Short")
|
t.Skip("too slow for testing.Short")
|
||||||
|
@ -4463,6 +4744,503 @@ func testAgent_RegisterServiceDeregisterService_Sidecar(t *testing.T, extraHCL s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This tests local agent service registration with a sidecar service. Note we
|
||||||
|
// only test simple defaults for the sidecar here since the actual logic for
|
||||||
|
// handling sidecar defaults and port assignment is tested thoroughly in
|
||||||
|
// TestAgent_sidecarServiceFromNodeService. Note it also tests Deregister
|
||||||
|
// explicitly too since setup is identical.
|
||||||
|
func TestAgent_RegisterServiceDeregisterService_Sidecar_UDP(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("normal", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testAgent_RegisterServiceDeregisterService_Sidecar_UDP(t, "enable_central_service_config = false")
|
||||||
|
})
|
||||||
|
t.Run("service manager", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testAgent_RegisterServiceDeregisterService_Sidecar_UDP(t, "enable_central_service_config = true")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAgent_RegisterServiceDeregisterService_Sidecar_UDP(t *testing.T, extraHCL string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
preRegister, preRegister2 *structs.NodeService
|
||||||
|
// Use raw JSON payloads rather than encoding to avoid subtleties with some
|
||||||
|
// internal representations and different ways they encode and decode. We
|
||||||
|
// rely on the payload being Unmarshalable to structs.ServiceDefinition
|
||||||
|
// directly.
|
||||||
|
json string
|
||||||
|
enableACL bool
|
||||||
|
tokenRules string
|
||||||
|
wantNS *structs.NodeService
|
||||||
|
wantErr string
|
||||||
|
wantSidecarIDLeftAfterDereg bool
|
||||||
|
assertStateFn func(t *testing.T, state *local.State)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "sanity check no sidecar case",
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
wantNS: nil,
|
||||||
|
wantErr: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default sidecar",
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
wantNS: testDefaultSidecar("web", 1111),
|
||||||
|
wantErr: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ACL OK defaults",
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
enableACL: true,
|
||||||
|
tokenRules: `
|
||||||
|
service "web-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "web" {
|
||||||
|
policy = "write"
|
||||||
|
}`,
|
||||||
|
wantNS: testDefaultSidecar("web", 1111),
|
||||||
|
wantErr: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ACL denied",
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
enableACL: true,
|
||||||
|
tokenRules: ``, // No token rules means no valid token
|
||||||
|
wantNS: nil,
|
||||||
|
wantErr: "Permission denied",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ACL OK for service but not for sidecar",
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
enableACL: true,
|
||||||
|
// This will become more common/reasonable when ACLs support exact match.
|
||||||
|
tokenRules: `
|
||||||
|
service "web-sidecar-proxy" {
|
||||||
|
policy = "deny"
|
||||||
|
}
|
||||||
|
service "web" {
|
||||||
|
policy = "write"
|
||||||
|
}`,
|
||||||
|
wantNS: nil,
|
||||||
|
wantErr: "Permission denied",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ACL OK for service and sidecar but not sidecar's overridden destination",
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {
|
||||||
|
"proxy": {
|
||||||
|
"DestinationServiceName": "foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
enableACL: true,
|
||||||
|
tokenRules: `
|
||||||
|
service "web-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "web" {
|
||||||
|
policy = "write"
|
||||||
|
}`,
|
||||||
|
wantNS: nil,
|
||||||
|
wantErr: "Permission denied",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ACL OK for service but not for overridden sidecar",
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {
|
||||||
|
"name": "foo-sidecar-proxy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
enableACL: true,
|
||||||
|
tokenRules: `
|
||||||
|
service "web-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "web" {
|
||||||
|
policy = "write"
|
||||||
|
}`,
|
||||||
|
wantNS: nil,
|
||||||
|
wantErr: "Permission denied",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ACL OK for service but and overridden for sidecar",
|
||||||
|
// This test ensures that if the sidecar embeds it's own token with
|
||||||
|
// different privs from the main request token it will be honored for the
|
||||||
|
// sidecar registration. We use the test root token since that should have
|
||||||
|
// permission.
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {
|
||||||
|
"name": "foo",
|
||||||
|
"token": "root"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
enableACL: true,
|
||||||
|
tokenRules: `
|
||||||
|
service "web-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "web" {
|
||||||
|
policy = "write"
|
||||||
|
}`,
|
||||||
|
wantNS: testDefaultSidecar("web", 1111, func(ns *structs.NodeService) {
|
||||||
|
ns.Service = "foo"
|
||||||
|
}),
|
||||||
|
wantErr: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid check definition in sidecar",
|
||||||
|
// Note no interval in the UDP check should fail validation
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {
|
||||||
|
"check": {
|
||||||
|
"UDP": "foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
wantNS: nil,
|
||||||
|
wantErr: "invalid check in sidecar_service",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid checks definitions in sidecar",
|
||||||
|
// Note no interval in the UDP check should fail validation
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {
|
||||||
|
"checks": [{
|
||||||
|
"UDP": "foo"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
wantNS: nil,
|
||||||
|
wantErr: "invalid check in sidecar_service",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid check status in sidecar",
|
||||||
|
// Note no interval in the UDP check should fail validation
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {
|
||||||
|
"check": {
|
||||||
|
"UDP": "foo",
|
||||||
|
"Interval": 10,
|
||||||
|
"Status": "unsupported-status"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
wantNS: nil,
|
||||||
|
wantErr: "Status for checks must 'passing', 'warning', 'critical'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid checks status in sidecar",
|
||||||
|
// Note no interval in the UDP check should fail validation
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {
|
||||||
|
"checks": [{
|
||||||
|
"UDP": "foo",
|
||||||
|
"Interval": 10,
|
||||||
|
"Status": "unsupported-status"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
wantNS: nil,
|
||||||
|
wantErr: "Status for checks must 'passing', 'warning', 'critical'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "another service registered with same ID as a sidecar should not be deregistered",
|
||||||
|
// Add another service with the same ID that a sidecar for web would have
|
||||||
|
preRegister: &structs.NodeService{
|
||||||
|
ID: "web-sidecar-proxy",
|
||||||
|
Service: "fake-sidecar",
|
||||||
|
Port: 9999,
|
||||||
|
},
|
||||||
|
// Register web with NO SIDECAR
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
// Note here that although the registration here didn't register it, we
|
||||||
|
// should still see the NodeService we pre-registered here.
|
||||||
|
wantNS: &structs.NodeService{
|
||||||
|
ID: "web-sidecar-proxy",
|
||||||
|
Service: "fake-sidecar",
|
||||||
|
Port: 9999,
|
||||||
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||||
|
Weights: &structs.Weights{
|
||||||
|
Passing: 1,
|
||||||
|
Warning: 1,
|
||||||
|
},
|
||||||
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||||
|
},
|
||||||
|
// After we deregister the web service above, the fake sidecar with
|
||||||
|
// clashing ID SHOULD NOT have been removed since it wasn't part of the
|
||||||
|
// original registration.
|
||||||
|
wantSidecarIDLeftAfterDereg: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "updates to sidecar should work",
|
||||||
|
// Add a valid sidecar already registered
|
||||||
|
preRegister: &structs.NodeService{
|
||||||
|
ID: "web-sidecar-proxy",
|
||||||
|
Service: "web-sidecar-proxy",
|
||||||
|
LocallyRegisteredAsSidecar: true,
|
||||||
|
Port: 9999,
|
||||||
|
},
|
||||||
|
// Register web with Sidecar on different port
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 1111,
|
||||||
|
"connect": {
|
||||||
|
"SidecarService": {
|
||||||
|
"Port": 6666
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
// Note here that although the registration here didn't register it, we
|
||||||
|
// should still see the NodeService we pre-registered here.
|
||||||
|
wantNS: &structs.NodeService{
|
||||||
|
Kind: "connect-proxy",
|
||||||
|
ID: "web-sidecar-proxy",
|
||||||
|
Service: "web-sidecar-proxy",
|
||||||
|
LocallyRegisteredAsSidecar: true,
|
||||||
|
Port: 6666,
|
||||||
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||||
|
Weights: &structs.Weights{
|
||||||
|
Passing: 1,
|
||||||
|
Warning: 1,
|
||||||
|
},
|
||||||
|
Proxy: structs.ConnectProxyConfig{
|
||||||
|
DestinationServiceName: "web",
|
||||||
|
DestinationServiceID: "web",
|
||||||
|
LocalServiceAddress: "127.0.0.1",
|
||||||
|
LocalServicePort: 1111,
|
||||||
|
},
|
||||||
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update that removes sidecar should NOT deregister it",
|
||||||
|
// Add web with a valid sidecar already registered
|
||||||
|
preRegister: &structs.NodeService{
|
||||||
|
ID: "web",
|
||||||
|
Service: "web",
|
||||||
|
Port: 1111,
|
||||||
|
},
|
||||||
|
preRegister2: testDefaultSidecar("web", 1111),
|
||||||
|
// Register (update) web and remove sidecar (and port for sanity check)
|
||||||
|
json: `
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 2222
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
// Sidecar should still be there such that API can update registration
|
||||||
|
// without accidentally removing a sidecar. This is equivalent to embedded
|
||||||
|
// checks which are not removed by just not being included in an update.
|
||||||
|
// We will document that sidecar registrations via API must be explicitiy
|
||||||
|
// deregistered.
|
||||||
|
wantNS: testDefaultSidecar("web", 1111),
|
||||||
|
// Sanity check the rest of the update happened though.
|
||||||
|
assertStateFn: func(t *testing.T, state *local.State) {
|
||||||
|
svc := state.Service(structs.NewServiceID("web", nil))
|
||||||
|
require.NotNil(t, svc)
|
||||||
|
require.Equal(t, 2222, svc.Port)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
||||||
|
// Constrain auto ports to 1 available to make it deterministic
|
||||||
|
hcl := `ports {
|
||||||
|
sidecar_min_port = 2222
|
||||||
|
sidecar_max_port = 2222
|
||||||
|
}
|
||||||
|
`
|
||||||
|
if tt.enableACL {
|
||||||
|
hcl = hcl + TestACLConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
a := NewTestAgent(t, hcl+" "+extraHCL)
|
||||||
|
defer a.Shutdown()
|
||||||
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
||||||
|
|
||||||
|
if tt.preRegister != nil {
|
||||||
|
require.NoError(t, a.addServiceFromSource(tt.preRegister, nil, false, "", ConfigSourceLocal))
|
||||||
|
}
|
||||||
|
if tt.preRegister2 != nil {
|
||||||
|
require.NoError(t, a.addServiceFromSource(tt.preRegister2, nil, false, "", ConfigSourceLocal))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an ACL token with require policy
|
||||||
|
var token string
|
||||||
|
if tt.enableACL && tt.tokenRules != "" {
|
||||||
|
token = testCreateToken(t, a, tt.tokenRules)
|
||||||
|
}
|
||||||
|
|
||||||
|
br := bytes.NewBufferString(tt.json)
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register?token="+token, br)
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
a.srv.h.ServeHTTP(resp, req)
|
||||||
|
if tt.wantErr != "" {
|
||||||
|
require.Contains(t, strings.ToLower(resp.Body.String()), strings.ToLower(tt.wantErr))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.Equal(t, 200, resp.Code, "request failed with body: %s",
|
||||||
|
resp.Body.String())
|
||||||
|
|
||||||
|
// Sanity the target service registration
|
||||||
|
svcs := a.State.AllServices()
|
||||||
|
|
||||||
|
// Parse the expected definition into a ServiceDefinition
|
||||||
|
var sd structs.ServiceDefinition
|
||||||
|
err := json.Unmarshal([]byte(tt.json), &sd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, sd.Name)
|
||||||
|
|
||||||
|
svcID := sd.ID
|
||||||
|
if svcID == "" {
|
||||||
|
svcID = sd.Name
|
||||||
|
}
|
||||||
|
sid := structs.NewServiceID(svcID, nil)
|
||||||
|
svc, ok := svcs[sid]
|
||||||
|
require.True(t, ok, "has service "+sid.String())
|
||||||
|
assert.Equal(t, sd.Name, svc.Service)
|
||||||
|
assert.Equal(t, sd.Port, svc.Port)
|
||||||
|
// Ensure that the actual registered service _doesn't_ still have it's
|
||||||
|
// sidecar info since it's duplicate and we don't want that synced up to
|
||||||
|
// the catalog or included in responses particularly - it's just
|
||||||
|
// registration syntax sugar.
|
||||||
|
assert.Nil(t, svc.Connect.SidecarService)
|
||||||
|
|
||||||
|
if tt.wantNS == nil {
|
||||||
|
// Sanity check that there was no service registered, we rely on there
|
||||||
|
// being no services at start of test so we can just use the count.
|
||||||
|
assert.Len(t, svcs, 1, "should be no sidecar registered")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure sidecar
|
||||||
|
svc, ok = svcs[structs.NewServiceID(tt.wantNS.ID, nil)]
|
||||||
|
require.True(t, ok, "no sidecar registered at "+tt.wantNS.ID)
|
||||||
|
assert.Equal(t, tt.wantNS, svc)
|
||||||
|
|
||||||
|
if tt.assertStateFn != nil {
|
||||||
|
tt.assertStateFn(t, a.State)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now verify deregistration also removes sidecar (if there was one and it
|
||||||
|
// was added via sidecar not just coincidental ID clash)
|
||||||
|
{
|
||||||
|
req := httptest.NewRequest("PUT",
|
||||||
|
"/v1/agent/service/deregister/"+svcID+"?token="+token, nil)
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
a.srv.h.ServeHTTP(resp, req)
|
||||||
|
require.Equal(t, http.StatusOK, resp.Code)
|
||||||
|
|
||||||
|
svcs := a.State.AllServices()
|
||||||
|
_, ok = svcs[structs.NewServiceID(tt.wantNS.ID, nil)]
|
||||||
|
if tt.wantSidecarIDLeftAfterDereg {
|
||||||
|
require.True(t, ok, "removed non-sidecar service at "+tt.wantNS.ID)
|
||||||
|
} else {
|
||||||
|
require.False(t, ok, "sidecar not deregistered with service "+svcID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// END HERE
|
||||||
|
|
||||||
// This tests that connect proxy validation is done for local agent
|
// This tests that connect proxy validation is done for local agent
|
||||||
// registration. This doesn't need to test validation exhaustively since
|
// registration. This doesn't need to test validation exhaustively since
|
||||||
// that is done via a table test in the structs package.
|
// that is done via a table test in the structs package.
|
||||||
|
|
|
@ -603,6 +603,63 @@ func TestCatalogRegister_checkRegistration(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCatalogRegister_checkRegistration_UDP(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
a := NewTestAgent(t, "")
|
||||||
|
defer a.Shutdown()
|
||||||
|
|
||||||
|
// Register node with a service and check
|
||||||
|
check := structs.HealthCheck{
|
||||||
|
Node: "foo",
|
||||||
|
CheckID: "foo-check",
|
||||||
|
Name: "foo check",
|
||||||
|
ServiceID: "api",
|
||||||
|
Definition: structs.HealthCheckDefinition{
|
||||||
|
UDP: "localhost:8888",
|
||||||
|
Interval: 5 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
args := &structs.RegisterRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Node: "foo",
|
||||||
|
Address: "127.0.0.1",
|
||||||
|
Service: &structs.NodeService{
|
||||||
|
Service: "api",
|
||||||
|
},
|
||||||
|
Check: &check,
|
||||||
|
}
|
||||||
|
|
||||||
|
var out struct{}
|
||||||
|
if err := a.RPC("Catalog.Register", args, &out); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
req, _ := http.NewRequest("GET", "/v1/health/checks/api", nil)
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
obj, err := a.srv.HealthServiceChecks(resp, req)
|
||||||
|
if err != nil {
|
||||||
|
r.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checks := obj.(structs.HealthChecks)
|
||||||
|
if len(checks) != 1 {
|
||||||
|
r.Fatalf("expected 1 check, got: %d", len(checks))
|
||||||
|
}
|
||||||
|
if checks[0].CheckID != check.CheckID {
|
||||||
|
r.Fatalf("expected check id %s, got %s", check.Type, checks[0].Type)
|
||||||
|
}
|
||||||
|
if checks[0].Type != "udp" {
|
||||||
|
r.Fatalf("expected check type udp, got %s", checks[0].Type)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestCatalogServiceNodes(t *testing.T) {
|
func TestCatalogServiceNodes(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("too slow for testing.Short")
|
t.Skip("too slow for testing.Short")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package checks
|
package checks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -703,6 +704,135 @@ func (c *CheckTCP) check() {
|
||||||
c.StatusHandler.updateCheck(c.CheckID, api.HealthPassing, fmt.Sprintf("TCP connect %s: Success", c.TCP))
|
c.StatusHandler.updateCheck(c.CheckID, api.HealthPassing, fmt.Sprintf("TCP connect %s: Success", c.TCP))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckUDP is used to periodically send a UDP datagram to determine the health of a given check.
|
||||||
|
// The check is passing if the connection succeeds, the response is bytes.Equal to the bytes passed
|
||||||
|
// in or if the error returned is a timeout error
|
||||||
|
// The check is critical if: the connection succeeds but the response is not equal to the bytes passed in,
|
||||||
|
// the connection succeeds but the error returned is not a timeout error or the connection fails
|
||||||
|
type CheckUDP struct {
|
||||||
|
CheckID structs.CheckID
|
||||||
|
ServiceID structs.ServiceID
|
||||||
|
UDP string
|
||||||
|
Message string
|
||||||
|
Interval time.Duration
|
||||||
|
Timeout time.Duration
|
||||||
|
Logger hclog.Logger
|
||||||
|
StatusHandler *StatusHandler
|
||||||
|
|
||||||
|
dialer *net.Dialer
|
||||||
|
stop bool
|
||||||
|
stopCh chan struct{}
|
||||||
|
stopLock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckUDP) Start() {
|
||||||
|
c.stopLock.Lock()
|
||||||
|
defer c.stopLock.Unlock()
|
||||||
|
|
||||||
|
if c.dialer == nil {
|
||||||
|
// Create the socket dialer
|
||||||
|
c.dialer = &net.Dialer{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
if c.Timeout > 0 {
|
||||||
|
c.dialer.Timeout = c.Timeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.stop = false
|
||||||
|
c.stopCh = make(chan struct{})
|
||||||
|
go c.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckUDP) Stop() {
|
||||||
|
c.stopLock.Lock()
|
||||||
|
defer c.stopLock.Unlock()
|
||||||
|
if !c.stop {
|
||||||
|
c.stop = true
|
||||||
|
close(c.stopCh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckUDP) 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 *CheckUDP) check() {
|
||||||
|
|
||||||
|
conn, err := c.dialer.Dial(`udp`, c.UDP)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
||||||
|
c.StatusHandler.updateCheck(c.CheckID, api.HealthPassing, fmt.Sprintf("UDP connect %s: Success", c.UDP))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
c.Logger.Warn("Check socket connection failed",
|
||||||
|
"check", c.CheckID.String(),
|
||||||
|
"error", err,
|
||||||
|
)
|
||||||
|
c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
n, err := fmt.Fprintf(conn, c.Message)
|
||||||
|
if err != nil {
|
||||||
|
c.Logger.Warn("Check socket write failed",
|
||||||
|
"check", c.CheckID.String(),
|
||||||
|
"error", err,
|
||||||
|
)
|
||||||
|
c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if n != len(c.Message) {
|
||||||
|
c.Logger.Warn("Check socket short write",
|
||||||
|
"check", c.CheckID.String(),
|
||||||
|
"error", err,
|
||||||
|
)
|
||||||
|
c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.Logger.Warn("Check socket write failed",
|
||||||
|
"check", c.CheckID.String(),
|
||||||
|
"error", err,
|
||||||
|
)
|
||||||
|
c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = bufio.NewReader(conn).Read(make([]byte, 1))
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "i/o timeout") {
|
||||||
|
c.StatusHandler.updateCheck(c.CheckID, api.HealthPassing, fmt.Sprintf("UDP connect %s: Success", c.UDP))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
c.Logger.Warn("Check socket read failed",
|
||||||
|
"check", c.CheckID.String(),
|
||||||
|
"error", err,
|
||||||
|
)
|
||||||
|
c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if err == nil {
|
||||||
|
c.StatusHandler.updateCheck(c.CheckID, api.HealthPassing, fmt.Sprintf("UDP connect %s: Success", c.UDP))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CheckDocker is used to periodically invoke a script to
|
// CheckDocker is used to periodically invoke a script to
|
||||||
// determine the health of an application running inside a
|
// determine the health of an application running inside a
|
||||||
// Docker Container. We assume that the script is compatible
|
// Docker Container. We assume that the script is compatible
|
||||||
|
|
|
@ -2,20 +2,25 @@ package checks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/mock"
|
"github.com/hashicorp/consul/agent/mock"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
|
"github.com/hashicorp/consul/sdk/freeport"
|
||||||
"github.com/hashicorp/consul/sdk/testutil"
|
"github.com/hashicorp/consul/sdk/testutil"
|
||||||
"github.com/hashicorp/consul/sdk/testutil/retry"
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
||||||
"github.com/hashicorp/go-uuid"
|
"github.com/hashicorp/go-uuid"
|
||||||
|
@ -1141,6 +1146,152 @@ func TestCheckTCPPassing(t *testing.T) {
|
||||||
tcpServer.Close()
|
tcpServer.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sendResponse(conn *net.UDPConn, addr *net.UDPAddr) {
|
||||||
|
_, err := conn.WriteToUDP([]byte("healthy"), addr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Couldn't send response %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockUDPServer(ctx context.Context, network string, port int) {
|
||||||
|
|
||||||
|
b := make([]byte, 1024)
|
||||||
|
addr := fmt.Sprintf(`127.0.0.1:%d`, port)
|
||||||
|
|
||||||
|
udpAddr, err := net.ResolveUDPAddr(network, addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error resolving UDP address: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ser, err := net.ListenUDP("udp", udpAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error listening UDP: ", err)
|
||||||
|
}
|
||||||
|
defer ser.Close()
|
||||||
|
|
||||||
|
chClose := make(chan interface{})
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
log.Print("Waiting for UDP message")
|
||||||
|
_, remoteaddr, err := ser.ReadFromUDP(b)
|
||||||
|
log.Printf("Read a message from %v %s \n", remoteaddr, b)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error reading from UDP %s", err.Error())
|
||||||
|
}
|
||||||
|
sendResponse(ser, remoteaddr)
|
||||||
|
select {
|
||||||
|
case <-chClose:
|
||||||
|
fmt.Println("cancelled")
|
||||||
|
wg.Done()
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
fmt.Println("cancelled")
|
||||||
|
close(chClose)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectUDPStatus(t *testing.T, udp string, status string) {
|
||||||
|
notif := mock.NewNotify()
|
||||||
|
logger := testutil.Logger(t)
|
||||||
|
statusHandler := NewStatusHandler(notif, logger, 0, 0, 0)
|
||||||
|
cid := structs.NewCheckID("foo", nil)
|
||||||
|
|
||||||
|
check := &CheckUDP{
|
||||||
|
CheckID: cid,
|
||||||
|
UDP: udp,
|
||||||
|
Interval: 10 * time.Millisecond,
|
||||||
|
Logger: logger,
|
||||||
|
StatusHandler: statusHandler,
|
||||||
|
}
|
||||||
|
check.Start()
|
||||||
|
defer check.Stop()
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
if got, want := notif.Updates(cid), 2; got < want {
|
||||||
|
r.Fatalf("got %d updates want at least %d", got, want)
|
||||||
|
}
|
||||||
|
if got, want := notif.State(cid), status; got != want {
|
||||||
|
r.Fatalf("got state %q want %q", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectUDPTimeout(t *testing.T, udp string, status string) {
|
||||||
|
notif := mock.NewNotify()
|
||||||
|
logger := testutil.Logger(t)
|
||||||
|
statusHandler := NewStatusHandler(notif, logger, 0, 0, 0)
|
||||||
|
cid := structs.NewCheckID("foo", nil)
|
||||||
|
|
||||||
|
check := &CheckUDP{
|
||||||
|
CheckID: cid,
|
||||||
|
UDP: udp,
|
||||||
|
Interval: 10 * time.Millisecond,
|
||||||
|
Timeout: 5 * time.Nanosecond,
|
||||||
|
Logger: logger,
|
||||||
|
StatusHandler: statusHandler,
|
||||||
|
}
|
||||||
|
check.Start()
|
||||||
|
defer check.Stop()
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
if got, want := notif.Updates(cid), 2; got < want {
|
||||||
|
r.Fatalf("got %d updates want at least %d", got, want)
|
||||||
|
}
|
||||||
|
if got, want := notif.State(cid), status; got != want {
|
||||||
|
r.Fatalf("got state %q want %q", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckUDPTimeoutPassing(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
port := freeport.GetOne(t)
|
||||||
|
serverUrl := "127.0.0.1:" + strconv.Itoa(port)
|
||||||
|
|
||||||
|
go mockUDPServer(ctx, `udp`, port)
|
||||||
|
expectUDPTimeout(t, serverUrl, api.HealthPassing) // Should pass since timeout is handled as success, from specification
|
||||||
|
}
|
||||||
|
func TestCheckUDPCritical(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
port := freeport.GetOne(t)
|
||||||
|
notExistentPort := freeport.GetOne(t)
|
||||||
|
serverUrl := "127.0.0.1:" + strconv.Itoa(notExistentPort)
|
||||||
|
|
||||||
|
go mockUDPServer(ctx, `udp`, port)
|
||||||
|
|
||||||
|
expectUDPStatus(t, serverUrl, api.HealthCritical) // Should be unhealthy since we never connect to mocked udp server.
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckUDPPassing(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
port := freeport.GetOne(t)
|
||||||
|
serverUrl := "127.0.0.1:" + strconv.Itoa(port)
|
||||||
|
|
||||||
|
go mockUDPServer(ctx, `udp`, port)
|
||||||
|
expectUDPStatus(t, serverUrl, api.HealthPassing)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckH2PING(t *testing.T) {
|
func TestCheckH2PING(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
|
@ -403,6 +403,7 @@ type CheckDefinition struct {
|
||||||
DisableRedirects *bool `mapstructure:"disable_redirects"`
|
DisableRedirects *bool `mapstructure:"disable_redirects"`
|
||||||
OutputMaxSize *int `mapstructure:"output_max_size"`
|
OutputMaxSize *int `mapstructure:"output_max_size"`
|
||||||
TCP *string `mapstructure:"tcp"`
|
TCP *string `mapstructure:"tcp"`
|
||||||
|
UDP *string `mapstructure:"udp"`
|
||||||
Interval *string `mapstructure:"interval"`
|
Interval *string `mapstructure:"interval"`
|
||||||
DockerContainerID *string `mapstructure:"docker_container_id" alias:"dockercontainerid"`
|
DockerContainerID *string `mapstructure:"docker_container_id" alias:"dockercontainerid"`
|
||||||
Shell *string `mapstructure:"shell"`
|
Shell *string `mapstructure:"shell"`
|
||||||
|
|
|
@ -118,7 +118,8 @@
|
||||||
"TLSSkipVerify": false,
|
"TLSSkipVerify": false,
|
||||||
"TTL": "0s",
|
"TTL": "0s",
|
||||||
"Timeout": "0s",
|
"Timeout": "0s",
|
||||||
"Token": "hidden"
|
"Token": "hidden",
|
||||||
|
"UDP": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ClientAddrs": [],
|
"ClientAddrs": [],
|
||||||
|
@ -324,7 +325,8 @@
|
||||||
"TLSServerName": "",
|
"TLSServerName": "",
|
||||||
"TLSSkipVerify": false,
|
"TLSSkipVerify": false,
|
||||||
"TTL": "0s",
|
"TTL": "0s",
|
||||||
"Timeout": "0s"
|
"Timeout": "0s",
|
||||||
|
"UDP": ""
|
||||||
},
|
},
|
||||||
"Checks": [],
|
"Checks": [],
|
||||||
"Connect": null,
|
"Connect": null,
|
||||||
|
|
|
@ -33,6 +33,7 @@ type CheckDefinition struct {
|
||||||
Body string
|
Body string
|
||||||
DisableRedirects bool
|
DisableRedirects bool
|
||||||
TCP string
|
TCP string
|
||||||
|
UDP string
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
DockerContainerID string
|
DockerContainerID string
|
||||||
Shell string
|
Shell string
|
||||||
|
@ -215,6 +216,7 @@ func (c *CheckDefinition) CheckType() *CheckType {
|
||||||
DisableRedirects: c.DisableRedirects,
|
DisableRedirects: c.DisableRedirects,
|
||||||
OutputMaxSize: c.OutputMaxSize,
|
OutputMaxSize: c.OutputMaxSize,
|
||||||
TCP: c.TCP,
|
TCP: c.TCP,
|
||||||
|
UDP: c.UDP,
|
||||||
Interval: c.Interval,
|
Interval: c.Interval,
|
||||||
DockerContainerID: c.DockerContainerID,
|
DockerContainerID: c.DockerContainerID,
|
||||||
Shell: c.Shell,
|
Shell: c.Shell,
|
||||||
|
|
|
@ -39,6 +39,7 @@ type CheckType struct {
|
||||||
Body string
|
Body string
|
||||||
DisableRedirects bool
|
DisableRedirects bool
|
||||||
TCP string
|
TCP string
|
||||||
|
UDP string
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
AliasNode string
|
AliasNode string
|
||||||
AliasService string
|
AliasService string
|
||||||
|
@ -179,13 +180,13 @@ func (t *CheckType) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
|
||||||
// Validate returns an error message if the check is invalid
|
// Validate returns an error message if the check is invalid
|
||||||
func (c *CheckType) Validate() error {
|
func (c *CheckType) Validate() error {
|
||||||
intervalCheck := c.IsScript() || c.HTTP != "" || c.TCP != "" || c.GRPC != "" || c.H2PING != ""
|
intervalCheck := c.IsScript() || c.HTTP != "" || c.TCP != "" || c.UDP != "" || c.GRPC != "" || c.H2PING != ""
|
||||||
|
|
||||||
if c.Interval > 0 && c.TTL > 0 {
|
if c.Interval > 0 && c.TTL > 0 {
|
||||||
return fmt.Errorf("Interval and TTL cannot both be specified")
|
return fmt.Errorf("Interval and TTL cannot both be specified")
|
||||||
}
|
}
|
||||||
if intervalCheck && c.Interval <= 0 {
|
if intervalCheck && c.Interval <= 0 {
|
||||||
return fmt.Errorf("Interval must be > 0 for Script, HTTP, H2PING, or TCP checks")
|
return fmt.Errorf("Interval must be > 0 for Script, HTTP, H2PING, TCP or UDP checks")
|
||||||
}
|
}
|
||||||
if intervalCheck && c.IsAlias() {
|
if intervalCheck && c.IsAlias() {
|
||||||
return fmt.Errorf("Interval cannot be set for Alias checks")
|
return fmt.Errorf("Interval cannot be set for Alias checks")
|
||||||
|
@ -241,6 +242,10 @@ func (c *CheckType) IsTCP() bool {
|
||||||
return c.TCP != "" && c.Interval > 0
|
return c.TCP != "" && c.Interval > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CheckType) IsUDP() bool {
|
||||||
|
return c.UDP != "" && c.Interval > 0
|
||||||
|
}
|
||||||
|
|
||||||
// IsDocker returns true when checking a docker container.
|
// IsDocker returns true when checking a docker container.
|
||||||
func (c *CheckType) IsDocker() bool {
|
func (c *CheckType) IsDocker() bool {
|
||||||
return c.IsScript() && c.DockerContainerID != "" && c.Interval > 0
|
return c.IsScript() && c.DockerContainerID != "" && c.Interval > 0
|
||||||
|
@ -266,6 +271,8 @@ func (c *CheckType) Type() string {
|
||||||
return "ttl"
|
return "ttl"
|
||||||
case c.IsTCP():
|
case c.IsTCP():
|
||||||
return "tcp"
|
return "tcp"
|
||||||
|
case c.IsUDP():
|
||||||
|
return "udp"
|
||||||
case c.IsAlias():
|
case c.IsAlias():
|
||||||
return "alias"
|
return "alias"
|
||||||
case c.IsDocker():
|
case c.IsDocker():
|
||||||
|
|
|
@ -1670,7 +1670,7 @@ type HealthCheck struct {
|
||||||
ServiceID string // optional associated service
|
ServiceID string // optional associated service
|
||||||
ServiceName string // optional service name
|
ServiceName string // optional service name
|
||||||
ServiceTags []string // optional service tags
|
ServiceTags []string // optional service tags
|
||||||
Type string // Check type: http/ttl/tcp/etc
|
Type string // Check type: http/ttl/tcp/udp/etc
|
||||||
|
|
||||||
Interval string // from definition
|
Interval string // from definition
|
||||||
Timeout string // from definition
|
Timeout string // from definition
|
||||||
|
@ -1735,6 +1735,7 @@ type HealthCheckDefinition struct {
|
||||||
Body string `json:",omitempty"`
|
Body string `json:",omitempty"`
|
||||||
DisableRedirects bool `json:",omitempty"`
|
DisableRedirects bool `json:",omitempty"`
|
||||||
TCP string `json:",omitempty"`
|
TCP string `json:",omitempty"`
|
||||||
|
UDP string `json:",omitempty"`
|
||||||
H2PING string `json:",omitempty"`
|
H2PING string `json:",omitempty"`
|
||||||
H2PingUseTLS bool `json:",omitempty"`
|
H2PingUseTLS bool `json:",omitempty"`
|
||||||
Interval time.Duration `json:",omitempty"`
|
Interval time.Duration `json:",omitempty"`
|
||||||
|
@ -1885,6 +1886,7 @@ func (c *HealthCheck) CheckType() *CheckType {
|
||||||
Body: c.Definition.Body,
|
Body: c.Definition.Body,
|
||||||
DisableRedirects: c.Definition.DisableRedirects,
|
DisableRedirects: c.Definition.DisableRedirects,
|
||||||
TCP: c.Definition.TCP,
|
TCP: c.Definition.TCP,
|
||||||
|
UDP: c.Definition.UDP,
|
||||||
H2PING: c.Definition.H2PING,
|
H2PING: c.Definition.H2PING,
|
||||||
H2PingUseTLS: c.Definition.H2PingUseTLS,
|
H2PingUseTLS: c.Definition.H2PingUseTLS,
|
||||||
Interval: c.Definition.Interval,
|
Interval: c.Definition.Interval,
|
||||||
|
|
|
@ -333,6 +333,7 @@ type AgentServiceCheck struct {
|
||||||
Method string `json:",omitempty"`
|
Method string `json:",omitempty"`
|
||||||
Body string `json:",omitempty"`
|
Body string `json:",omitempty"`
|
||||||
TCP string `json:",omitempty"`
|
TCP string `json:",omitempty"`
|
||||||
|
UDP string `json:",omitempty"`
|
||||||
Status string `json:",omitempty"`
|
Status string `json:",omitempty"`
|
||||||
Notes string `json:",omitempty"`
|
Notes string `json:",omitempty"`
|
||||||
TLSServerName string `json:",omitempty"`
|
TLSServerName string `json:",omitempty"`
|
||||||
|
|
|
@ -62,6 +62,7 @@ type HealthCheckDefinition struct {
|
||||||
TLSServerName string
|
TLSServerName string
|
||||||
TLSSkipVerify bool
|
TLSSkipVerify bool
|
||||||
TCP string
|
TCP string
|
||||||
|
UDP string
|
||||||
GRPC string
|
GRPC string
|
||||||
GRPCUseTLS bool
|
GRPCUseTLS bool
|
||||||
IntervalDuration time.Duration `json:"-"`
|
IntervalDuration time.Duration `json:"-"`
|
||||||
|
|
|
@ -56,6 +56,28 @@ func TestAPI_ClientTxn(t *testing.T) {
|
||||||
DeregisterCriticalServiceAfter: ReadableDuration(160 * time.Second),
|
DeregisterCriticalServiceAfter: ReadableDuration(160 * time.Second),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
CheckID: "bor",
|
||||||
|
Status: "critical",
|
||||||
|
Definition: HealthCheckDefinition{
|
||||||
|
UDP: "1.1.1.1",
|
||||||
|
Interval: ReadableDuration(5 * time.Second),
|
||||||
|
Timeout: ReadableDuration(10 * time.Second),
|
||||||
|
DeregisterCriticalServiceAfter: ReadableDuration(20 * time.Second),
|
||||||
|
},
|
||||||
|
Type: "udp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CheckID: "bur",
|
||||||
|
Status: "passing",
|
||||||
|
Definition: HealthCheckDefinition{
|
||||||
|
UDP: "2.2.2.2",
|
||||||
|
Interval: ReadableDuration(5 * time.Second),
|
||||||
|
Timeout: ReadableDuration(10 * time.Second),
|
||||||
|
DeregisterCriticalServiceAfter: ReadableDuration(20 * time.Second),
|
||||||
|
},
|
||||||
|
Type: "udp",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = catalog.Register(reg, nil)
|
_, err = catalog.Register(reg, nil)
|
||||||
|
@ -115,6 +137,18 @@ func TestAPI_ClientTxn(t *testing.T) {
|
||||||
Check: HealthCheck{Node: "foo", CheckID: "baz"},
|
Check: HealthCheck{Node: "foo", CheckID: "baz"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
&TxnOp{
|
||||||
|
Check: &CheckTxnOp{
|
||||||
|
Verb: CheckGet,
|
||||||
|
Check: HealthCheck{Node: "foo", CheckID: "bor"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&TxnOp{
|
||||||
|
Check: &CheckTxnOp{
|
||||||
|
Verb: CheckGet,
|
||||||
|
Check: HealthCheck{Node: "foo", CheckID: "bur"},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
ok, ret, _, err := txn.Txn(ops, nil)
|
ok, ret, _, err := txn.Txn(ops, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -141,7 +175,7 @@ func TestAPI_ClientTxn(t *testing.T) {
|
||||||
t.Fatalf("transaction failure")
|
t.Fatalf("transaction failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ret == nil || len(ret.Errors) != 0 || len(ret.Results) != 6 {
|
if ret == nil || len(ret.Errors) != 0 || len(ret.Results) != 8 {
|
||||||
t.Fatalf("bad: %v", ret)
|
t.Fatalf("bad: %v", ret)
|
||||||
}
|
}
|
||||||
expected := TxnResults{
|
expected := TxnResults{
|
||||||
|
@ -230,6 +264,48 @@ func TestAPI_ClientTxn(t *testing.T) {
|
||||||
ModifyIndex: ret.Results[4].Check.CreateIndex,
|
ModifyIndex: ret.Results[4].Check.CreateIndex,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
&TxnResult{
|
||||||
|
Check: &HealthCheck{
|
||||||
|
Node: "foo",
|
||||||
|
CheckID: "bor",
|
||||||
|
Status: "critical",
|
||||||
|
Definition: HealthCheckDefinition{
|
||||||
|
UDP: "1.1.1.1",
|
||||||
|
Interval: ReadableDuration(5 * time.Second),
|
||||||
|
IntervalDuration: 5 * time.Second,
|
||||||
|
Timeout: ReadableDuration(10 * time.Second),
|
||||||
|
TimeoutDuration: 10 * time.Second,
|
||||||
|
DeregisterCriticalServiceAfter: ReadableDuration(20 * time.Second),
|
||||||
|
DeregisterCriticalServiceAfterDuration: 20 * time.Second,
|
||||||
|
},
|
||||||
|
Type: "udp",
|
||||||
|
Partition: splitDefaultPartition,
|
||||||
|
Namespace: splitDefaultNamespace,
|
||||||
|
CreateIndex: ret.Results[4].Check.CreateIndex,
|
||||||
|
ModifyIndex: ret.Results[4].Check.CreateIndex,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&TxnResult{
|
||||||
|
Check: &HealthCheck{
|
||||||
|
Node: "foo",
|
||||||
|
CheckID: "bur",
|
||||||
|
Status: "passing",
|
||||||
|
Definition: HealthCheckDefinition{
|
||||||
|
UDP: "2.2.2.2",
|
||||||
|
Interval: ReadableDuration(5 * time.Second),
|
||||||
|
IntervalDuration: 5 * time.Second,
|
||||||
|
Timeout: ReadableDuration(10 * time.Second),
|
||||||
|
TimeoutDuration: 10 * time.Second,
|
||||||
|
DeregisterCriticalServiceAfter: ReadableDuration(20 * time.Second),
|
||||||
|
DeregisterCriticalServiceAfterDuration: 20 * time.Second,
|
||||||
|
},
|
||||||
|
Type: "udp",
|
||||||
|
Partition: splitDefaultPartition,
|
||||||
|
Namespace: splitDefaultNamespace,
|
||||||
|
CreateIndex: ret.Results[4].Check.CreateIndex,
|
||||||
|
ModifyIndex: ret.Results[4].Check.CreateIndex,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
require.Equal(t, expected, ret.Results)
|
require.Equal(t, expected, ret.Results)
|
||||||
|
|
||||||
|
|
|
@ -149,10 +149,10 @@ function install_unversioned_tool {
|
||||||
local install="$2"
|
local install="$2"
|
||||||
|
|
||||||
if ! command -v "${command}" &>/dev/null ; then
|
if ! command -v "${command}" &>/dev/null ; then
|
||||||
status_stage "installing tool: ${install}"
|
echo "installing tool: ${install}"
|
||||||
go install "${install}"
|
go install "${install}"
|
||||||
else
|
else
|
||||||
debug "skipping tool: ${install} (installed)"
|
echo "skipping tool: ${install} (installed)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
@ -183,7 +183,7 @@ function install_versioned_tool {
|
||||||
err "dev version of '${command}' requested but not installed"
|
err "dev version of '${command}' requested but not installed"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
status "skipping tool: ${installbase} (using development version)"
|
echo "skipping tool: ${installbase} (using development version)"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -210,10 +210,10 @@ function install_versioned_tool {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $should_install ]]; then
|
if [[ -n $should_install ]]; then
|
||||||
status_stage "installing tool (${install_reason}): ${install}"
|
echo "installing tool (${install_reason}): ${install}"
|
||||||
go install "${install}"
|
go install "${install}"
|
||||||
else
|
else
|
||||||
debug "skipping tool: ${install} (installed)"
|
echo "skipping tool: ${install} (installed)"
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ func CheckTypeToStructs(s *CheckType, t *structs.CheckType) {
|
||||||
t.Body = s.Body
|
t.Body = s.Body
|
||||||
t.DisableRedirects = s.DisableRedirects
|
t.DisableRedirects = s.DisableRedirects
|
||||||
t.TCP = s.TCP
|
t.TCP = s.TCP
|
||||||
|
t.UDP = s.UDP
|
||||||
t.Interval = structs.DurationFromProto(s.Interval)
|
t.Interval = structs.DurationFromProto(s.Interval)
|
||||||
t.AliasNode = s.AliasNode
|
t.AliasNode = s.AliasNode
|
||||||
t.AliasService = s.AliasService
|
t.AliasService = s.AliasService
|
||||||
|
@ -57,6 +58,7 @@ func CheckTypeFromStructs(t *structs.CheckType, s *CheckType) {
|
||||||
s.Body = t.Body
|
s.Body = t.Body
|
||||||
s.DisableRedirects = t.DisableRedirects
|
s.DisableRedirects = t.DisableRedirects
|
||||||
s.TCP = t.TCP
|
s.TCP = t.TCP
|
||||||
|
s.UDP = t.UDP
|
||||||
s.Interval = structs.DurationToProto(t.Interval)
|
s.Interval = structs.DurationToProto(t.Interval)
|
||||||
s.AliasNode = t.AliasNode
|
s.AliasNode = t.AliasNode
|
||||||
s.AliasService = t.AliasService
|
s.AliasService = t.AliasService
|
||||||
|
@ -138,6 +140,7 @@ func HealthCheckDefinitionToStructs(s *HealthCheckDefinition, t *structs.HealthC
|
||||||
t.Body = s.Body
|
t.Body = s.Body
|
||||||
t.DisableRedirects = s.DisableRedirects
|
t.DisableRedirects = s.DisableRedirects
|
||||||
t.TCP = s.TCP
|
t.TCP = s.TCP
|
||||||
|
t.UDP = s.UDP
|
||||||
t.H2PING = s.H2PING
|
t.H2PING = s.H2PING
|
||||||
t.H2PingUseTLS = s.H2PingUseTLS
|
t.H2PingUseTLS = s.H2PingUseTLS
|
||||||
t.Interval = structs.DurationFromProto(s.Interval)
|
t.Interval = structs.DurationFromProto(s.Interval)
|
||||||
|
@ -165,6 +168,7 @@ func HealthCheckDefinitionFromStructs(t *structs.HealthCheckDefinition, s *Healt
|
||||||
s.Body = t.Body
|
s.Body = t.Body
|
||||||
s.DisableRedirects = t.DisableRedirects
|
s.DisableRedirects = t.DisableRedirects
|
||||||
s.TCP = t.TCP
|
s.TCP = t.TCP
|
||||||
|
s.UDP = t.UDP
|
||||||
s.H2PING = t.H2PING
|
s.H2PING = t.H2PING
|
||||||
s.H2PingUseTLS = t.H2PingUseTLS
|
s.H2PingUseTLS = t.H2PingUseTLS
|
||||||
s.Interval = structs.DurationToProto(t.Interval)
|
s.Interval = structs.DurationToProto(t.Interval)
|
||||||
|
|
|
@ -276,6 +276,7 @@ type HealthCheckDefinition struct {
|
||||||
Body string `protobuf:"bytes,18,opt,name=Body,proto3" json:"Body,omitempty"`
|
Body string `protobuf:"bytes,18,opt,name=Body,proto3" json:"Body,omitempty"`
|
||||||
DisableRedirects bool `protobuf:"varint,22,opt,name=DisableRedirects,proto3" json:"DisableRedirects,omitempty"`
|
DisableRedirects bool `protobuf:"varint,22,opt,name=DisableRedirects,proto3" json:"DisableRedirects,omitempty"`
|
||||||
TCP string `protobuf:"bytes,5,opt,name=TCP,proto3" json:"TCP,omitempty"`
|
TCP string `protobuf:"bytes,5,opt,name=TCP,proto3" json:"TCP,omitempty"`
|
||||||
|
UDP string `protobuf:"bytes,23,opt,name=UDP,proto3" json:"UDP,omitempty"`
|
||||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||||
Interval *durationpb.Duration `protobuf:"bytes,6,opt,name=Interval,proto3" json:"Interval,omitempty"`
|
Interval *durationpb.Duration `protobuf:"bytes,6,opt,name=Interval,proto3" json:"Interval,omitempty"`
|
||||||
// mog: func-to=uint func-from=uint32
|
// mog: func-to=uint func-from=uint32
|
||||||
|
@ -385,6 +386,13 @@ func (x *HealthCheckDefinition) GetTCP() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *HealthCheckDefinition) GetUDP() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.UDP
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (x *HealthCheckDefinition) GetInterval() *durationpb.Duration {
|
func (x *HealthCheckDefinition) GetInterval() *durationpb.Duration {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Interval
|
return x.Interval
|
||||||
|
@ -513,6 +521,7 @@ type CheckType struct {
|
||||||
Body string `protobuf:"bytes,26,opt,name=Body,proto3" json:"Body,omitempty"`
|
Body string `protobuf:"bytes,26,opt,name=Body,proto3" json:"Body,omitempty"`
|
||||||
DisableRedirects bool `protobuf:"varint,31,opt,name=DisableRedirects,proto3" json:"DisableRedirects,omitempty"`
|
DisableRedirects bool `protobuf:"varint,31,opt,name=DisableRedirects,proto3" json:"DisableRedirects,omitempty"`
|
||||||
TCP string `protobuf:"bytes,8,opt,name=TCP,proto3" json:"TCP,omitempty"`
|
TCP string `protobuf:"bytes,8,opt,name=TCP,proto3" json:"TCP,omitempty"`
|
||||||
|
UDP string `protobuf:"bytes,32,opt,name=UDP,proto3" json:"UDP,omitempty"`
|
||||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||||
Interval *durationpb.Duration `protobuf:"bytes,9,opt,name=Interval,proto3" json:"Interval,omitempty"`
|
Interval *durationpb.Duration `protobuf:"bytes,9,opt,name=Interval,proto3" json:"Interval,omitempty"`
|
||||||
AliasNode string `protobuf:"bytes,10,opt,name=AliasNode,proto3" json:"AliasNode,omitempty"`
|
AliasNode string `protobuf:"bytes,10,opt,name=AliasNode,proto3" json:"AliasNode,omitempty"`
|
||||||
|
@ -656,6 +665,13 @@ func (x *CheckType) GetTCP() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *CheckType) GetUDP() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.UDP
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (x *CheckType) GetInterval() *durationpb.Duration {
|
func (x *CheckType) GetInterval() *durationpb.Duration {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Interval
|
return x.Interval
|
||||||
|
@ -843,7 +859,7 @@ var file_proto_pbservice_healthcheck_proto_rawDesc = []byte{
|
||||||
0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x23, 0x0a, 0x0b,
|
0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x23, 0x0a, 0x0b,
|
||||||
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x56,
|
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x56,
|
||||||
0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75,
|
0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75,
|
||||||
0x65, 0x22, 0xae, 0x07, 0x0a, 0x15, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63,
|
0x65, 0x22, 0xc0, 0x07, 0x0a, 0x15, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63,
|
||||||
0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x48,
|
0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x48,
|
||||||
0x54, 0x54, 0x50, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x54, 0x54, 0x50, 0x12,
|
0x54, 0x54, 0x50, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x54, 0x54, 0x50, 0x12,
|
||||||
0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65,
|
0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65,
|
||||||
|
@ -861,134 +877,136 @@ var file_proto_pbservice_healthcheck_proto_rawDesc = []byte{
|
||||||
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x73, 0x18,
|
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x73, 0x18,
|
||||||
0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65,
|
0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65,
|
||||||
0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x18, 0x05,
|
0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x18, 0x05,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x43, 0x50, 0x12, 0x35, 0x0a, 0x08, 0x49, 0x6e, 0x74,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x43, 0x50, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x44, 0x50,
|
||||||
0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f,
|
0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x44, 0x50, 0x12, 0x35, 0x0a, 0x08, 0x49,
|
||||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75,
|
0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
|
||||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,
|
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||||
0x12, 0x24, 0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a,
|
0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76,
|
||||||
0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d,
|
0x61, 0x6c, 0x12, 0x24, 0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78, 0x53,
|
||||||
0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75,
|
0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75,
|
||||||
0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
0x74, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x54, 0x69, 0x6d, 0x65,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
|
0x6f, 0x75, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
0x6f, 0x6e, 0x52, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x61, 0x0a, 0x1e, 0x44,
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61,
|
||||||
0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
|
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x61, 0x0a,
|
||||||
0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20,
|
0x1e, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x72, 0x69, 0x74, 0x69,
|
||||||
|
0x63, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x18,
|
||||||
|
0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||||
|
0x52, 0x1e, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x72, 0x69, 0x74,
|
||||||
|
0x69, 0x63, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72,
|
||||||
|
0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x72, 0x67, 0x73, 0x18, 0x0a,
|
||||||
|
0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x72, 0x67, 0x73,
|
||||||
|
0x12, 0x2c, 0x0a, 0x11, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69,
|
||||||
|
0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x44, 0x6f, 0x63,
|
||||||
|
0x6b, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x14,
|
||||||
|
0x0a, 0x05, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x53,
|
||||||
|
0x68, 0x65, 0x6c, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x48, 0x32, 0x50, 0x49, 0x4e, 0x47, 0x18, 0x14,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x48, 0x32, 0x50, 0x49, 0x4e, 0x47, 0x12, 0x22, 0x0a, 0x0c,
|
||||||
|
0x48, 0x32, 0x50, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53, 0x18, 0x15, 0x20, 0x01,
|
||||||
|
0x28, 0x08, 0x52, 0x0c, 0x48, 0x32, 0x50, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53,
|
||||||
|
0x12, 0x12, 0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||||
|
0x47, 0x52, 0x50, 0x43, 0x12, 0x1e, 0x0a, 0x0a, 0x47, 0x52, 0x50, 0x43, 0x55, 0x73, 0x65, 0x54,
|
||||||
|
0x4c, 0x53, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x47, 0x52, 0x50, 0x43, 0x55, 0x73,
|
||||||
|
0x65, 0x54, 0x4c, 0x53, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4e, 0x6f, 0x64,
|
||||||
|
0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4e, 0x6f,
|
||||||
|
0x64, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69,
|
||||||
|
0x63, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x53,
|
||||||
|
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x11, 0x20,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1e,
|
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03,
|
||||||
0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63,
|
0x54, 0x54, 0x4c, 0x1a, 0x4f, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74,
|
||||||
0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x1e,
|
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x0a, 0x0a, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x72, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x03,
|
0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
|
||||||
0x28, 0x09, 0x52, 0x0a, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x2c,
|
0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x48, 0x65,
|
||||||
0x0a, 0x11, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
|
0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||||
0x72, 0x49, 0x44, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x44, 0x6f, 0x63, 0x6b, 0x65,
|
0x3a, 0x02, 0x38, 0x01, 0x22, 0xe2, 0x09, 0x0a, 0x09, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x79,
|
||||||
0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05,
|
0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x44, 0x18, 0x01, 0x20,
|
||||||
0x53, 0x68, 0x65, 0x6c, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x53, 0x68, 0x65,
|
0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04,
|
||||||
0x6c, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x48, 0x32, 0x50, 0x49, 0x4e, 0x47, 0x18, 0x14, 0x20, 0x01,
|
0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65,
|
||||||
0x28, 0x09, 0x52, 0x06, 0x48, 0x32, 0x50, 0x49, 0x4e, 0x47, 0x12, 0x22, 0x0a, 0x0c, 0x48, 0x32,
|
0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x50, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08,
|
0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x4e, 0x6f, 0x74, 0x65,
|
||||||
0x52, 0x0c, 0x48, 0x32, 0x50, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53, 0x12, 0x12,
|
0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x12, 0x1e,
|
||||||
0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x52,
|
0x0a, 0x0a, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x72, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03,
|
||||||
0x50, 0x43, 0x12, 0x1e, 0x0a, 0x0a, 0x47, 0x52, 0x50, 0x43, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53,
|
0x28, 0x09, 0x52, 0x0a, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x12,
|
||||||
0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x47, 0x52, 0x50, 0x43, 0x55, 0x73, 0x65, 0x54,
|
0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x54,
|
||||||
0x4c, 0x53, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x18,
|
0x54, 0x50, 0x12, 0x36, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x14, 0x20, 0x03,
|
||||||
0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4e, 0x6f, 0x64, 0x65,
|
0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x68, 0x65,
|
||||||
0x12, 0x22, 0x0a, 0x0c, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74,
|
||||||
0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x53, 0x65, 0x72,
|
0x72, 0x79, 0x52, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x4d, 0x65,
|
||||||
0x76, 0x69, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x11, 0x20, 0x01, 0x28,
|
0x74, 0x68, 0x6f, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x65, 0x74, 0x68,
|
||||||
|
0x6f, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09,
|
||||||
|
0x52, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c,
|
||||||
|
0x65, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x73, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08,
|
||||||
|
0x52, 0x10, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63,
|
||||||
|
0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x03, 0x54, 0x43, 0x50, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x18, 0x20, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x03, 0x55, 0x44, 0x50, 0x12, 0x35, 0x0a, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76,
|
||||||
|
0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||||
|
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74,
|
||||||
|
0x69, 0x6f, 0x6e, 0x52, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a,
|
||||||
|
0x09, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09,
|
||||||
|
0x52, 0x09, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x41,
|
||||||
|
0x6c, 0x69, 0x61, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x0c, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||||
|
0x2c, 0x0a, 0x11, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
|
||||||
|
0x65, 0x72, 0x49, 0x44, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x44, 0x6f, 0x63, 0x6b,
|
||||||
|
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x14, 0x0a,
|
||||||
|
0x05, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x53, 0x68,
|
||||||
|
0x65, 0x6c, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x48, 0x32, 0x50, 0x49, 0x4e, 0x47, 0x18, 0x1c, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x06, 0x48, 0x32, 0x50, 0x49, 0x4e, 0x47, 0x12, 0x22, 0x0a, 0x0c, 0x48,
|
||||||
|
0x32, 0x50, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53, 0x18, 0x1e, 0x20, 0x01, 0x28,
|
||||||
|
0x08, 0x52, 0x0c, 0x48, 0x32, 0x50, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53, 0x12,
|
||||||
|
0x12, 0x0a, 0x04, 0x47, 0x52, 0x50, 0x43, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47,
|
||||||
|
0x52, 0x50, 0x43, 0x12, 0x1e, 0x0a, 0x0a, 0x47, 0x52, 0x50, 0x43, 0x55, 0x73, 0x65, 0x54, 0x4c,
|
||||||
|
0x53, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x47, 0x52, 0x50, 0x43, 0x55, 0x73, 0x65,
|
||||||
|
0x54, 0x4c, 0x53, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||||
|
0x4e, 0x61, 0x6d, 0x65, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x54, 0x4c, 0x53, 0x53,
|
||||||
|
0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53,
|
||||||
|
0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08,
|
||||||
|
0x52, 0x0d, 0x54, 0x4c, 0x53, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12,
|
||||||
|
0x33, 0x0a, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b,
|
||||||
|
0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||||
|
0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x54, 0x69, 0x6d,
|
||||||
|
0x65, 0x6f, 0x75, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x12, 0x20, 0x01, 0x28,
|
||||||
0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x54, 0x54,
|
0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x54, 0x54,
|
||||||
0x4c, 0x1a, 0x4f, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
0x4c, 0x12, 0x32, 0x0a, 0x14, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x65, 0x66, 0x6f,
|
||||||
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
|
0x72, 0x65, 0x50, 0x61, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||||
0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
|
||||||
0x0b, 0x32, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64,
|
|
||||||
0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
|
|
||||||
0x38, 0x01, 0x22, 0xd0, 0x09, 0x0a, 0x09, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65,
|
|
||||||
0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28,
|
|
||||||
0x09, 0x52, 0x07, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61,
|
|
||||||
0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16,
|
|
||||||
0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
|
||||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x18,
|
|
||||||
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a,
|
|
||||||
0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x72, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09,
|
|
||||||
0x52, 0x0a, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x12, 0x0a, 0x04,
|
|
||||||
0x48, 0x54, 0x54, 0x50, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x54, 0x54, 0x50,
|
|
||||||
0x12, 0x36, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b,
|
|
||||||
0x32, 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b,
|
|
||||||
0x54, 0x79, 0x70, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
|
||||||
0x52, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68,
|
|
||||||
0x6f, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
|
||||||
0x12, 0x12, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
|
||||||
0x42, 0x6f, 0x64, 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52,
|
|
||||||
0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x73, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10,
|
|
||||||
0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x73,
|
|
||||||
0x12, 0x10, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54,
|
|
||||||
0x43, 0x50, 0x12, 0x35, 0x0a, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x09,
|
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
|
||||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
|
|
||||||
0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x6c, 0x69,
|
|
||||||
0x61, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x41, 0x6c,
|
|
||||||
0x69, 0x61, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x6c, 0x69, 0x61, 0x73,
|
|
||||||
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x41,
|
|
||||||
0x6c, 0x69, 0x61, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x44,
|
|
||||||
0x6f, 0x63, 0x6b, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x44,
|
|
||||||
0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x43, 0x6f,
|
|
||||||
0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x53, 0x68, 0x65,
|
|
||||||
0x6c, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12,
|
|
||||||
0x16, 0x0a, 0x06, 0x48, 0x32, 0x50, 0x49, 0x4e, 0x47, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x52,
|
|
||||||
0x06, 0x48, 0x32, 0x50, 0x49, 0x4e, 0x47, 0x12, 0x22, 0x0a, 0x0c, 0x48, 0x32, 0x50, 0x69, 0x6e,
|
|
||||||
0x67, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x48,
|
|
||||||
0x32, 0x50, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53, 0x12, 0x12, 0x0a, 0x04, 0x47,
|
|
||||||
0x52, 0x50, 0x43, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x52, 0x50, 0x43, 0x12,
|
|
||||||
0x1e, 0x0a, 0x0a, 0x47, 0x52, 0x50, 0x43, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53, 0x18, 0x0f, 0x20,
|
|
||||||
0x01, 0x28, 0x08, 0x52, 0x0a, 0x47, 0x52, 0x50, 0x43, 0x55, 0x73, 0x65, 0x54, 0x4c, 0x53, 0x12,
|
|
||||||
0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65,
|
|
||||||
0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x54, 0x4c, 0x53, 0x53, 0x65, 0x72, 0x76, 0x65,
|
|
||||||
0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x4c, 0x53, 0x53, 0x6b, 0x69, 0x70,
|
|
||||||
0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x54, 0x4c,
|
|
||||||
0x53, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x33, 0x0a, 0x07, 0x54,
|
|
||||||
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67,
|
|
||||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44,
|
|
||||||
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
|
|
||||||
0x12, 0x2b, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
|
|
||||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
|
||||||
0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x32, 0x0a,
|
|
||||||
0x14, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x50, 0x61,
|
0x14, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x50, 0x61,
|
||||||
0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x53, 0x75, 0x63,
|
0x73, 0x73, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65,
|
||||||
0x63, 0x65, 0x73, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x50, 0x61, 0x73, 0x73, 0x69, 0x6e,
|
0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x1d,
|
||||||
0x67, 0x12, 0x34, 0x0a, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65, 0x66,
|
0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65,
|
||||||
0x6f, 0x72, 0x65, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x05,
|
0x66, 0x6f, 0x72, 0x65, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x36, 0x0a, 0x16, 0x46,
|
||||||
0x52, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65,
|
0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x69,
|
||||||
0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x36, 0x0a, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75,
|
0x74, 0x69, 0x63, 0x61, 0x6c, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x16, 0x46, 0x61, 0x69,
|
||||||
0x72, 0x65, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
|
0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x69, 0x74, 0x69,
|
||||||
0x6c, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65,
|
0x63, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x54, 0x54, 0x50,
|
||||||
0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x12,
|
0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x54, 0x54,
|
||||||
0x1c, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x54, 0x54, 0x50, 0x18, 0x17, 0x20, 0x01,
|
0x50, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x47, 0x52, 0x50, 0x43, 0x18, 0x18,
|
||||||
0x28, 0x09, 0x52, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x54, 0x54, 0x50, 0x12, 0x1c, 0x0a,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x47, 0x52, 0x50, 0x43, 0x12,
|
||||||
0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x47, 0x52, 0x50, 0x43, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09,
|
0x61, 0x0a, 0x1e, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x72, 0x69,
|
||||||
0x52, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x47, 0x52, 0x50, 0x43, 0x12, 0x61, 0x0a, 0x1e, 0x44,
|
0x74, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65,
|
||||||
0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
|
0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||||
0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x18, 0x13, 0x20,
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
0x6f, 0x6e, 0x52, 0x1e, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x72,
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1e,
|
0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x66, 0x74,
|
||||||
0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63,
|
0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78, 0x53,
|
||||||
0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x24,
|
0x69, 0x7a, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75,
|
||||||
0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x18,
|
0x74, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x1a, 0x4f, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64,
|
||||||
0x19, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78,
|
0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
||||||
0x53, 0x69, 0x7a, 0x65, 0x1a, 0x4f, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c,
|
||||||
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||||
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
|
0x63, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x48,
|
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x88, 0x01, 0x0a, 0x0b, 0x63, 0x6f,
|
||||||
0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
|
0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74,
|
||||||
0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x88, 0x01, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x65,
|
0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67,
|
||||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65,
|
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
|
||||||
0x63, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75,
|
0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f,
|
0x2f, 0x70, 0x62, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58,
|
||||||
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x73,
|
0xaa, 0x02, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0xca, 0x02, 0x07, 0x53, 0x65, 0x72,
|
||||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x53,
|
0x76, 0x69, 0x63, 0x65, 0xe2, 0x02, 0x13, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5c, 0x47,
|
||||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0xca, 0x02, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x53, 0x65, 0x72,
|
||||||
0xe2, 0x02, 0x13, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65,
|
0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
|
||||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -63,6 +63,7 @@ message HealthCheckDefinition {
|
||||||
string Body = 18;
|
string Body = 18;
|
||||||
bool DisableRedirects = 22;
|
bool DisableRedirects = 22;
|
||||||
string TCP = 5;
|
string TCP = 5;
|
||||||
|
string UDP = 23;
|
||||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||||
google.protobuf.Duration Interval = 6;
|
google.protobuf.Duration Interval = 6;
|
||||||
|
|
||||||
|
@ -112,6 +113,7 @@ message CheckType {
|
||||||
string Body = 26;
|
string Body = 26;
|
||||||
bool DisableRedirects = 31;
|
bool DisableRedirects = 31;
|
||||||
string TCP = 8;
|
string TCP = 8;
|
||||||
|
string UDP = 32;
|
||||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||||
google.protobuf.Duration Interval = 9;
|
google.protobuf.Duration Interval = 9;
|
||||||
|
|
||||||
|
@ -125,6 +127,7 @@ message CheckType {
|
||||||
bool GRPCUseTLS = 15;
|
bool GRPCUseTLS = 15;
|
||||||
string TLSServerName = 27;
|
string TLSServerName = 27;
|
||||||
bool TLSSkipVerify = 16;
|
bool TLSSkipVerify = 16;
|
||||||
|
|
||||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||||
google.protobuf.Duration Timeout = 17;
|
google.protobuf.Duration Timeout = 17;
|
||||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||||
|
|
|
@ -98,7 +98,7 @@ the following selectors and filter operations being supported:
|
||||||
## Register Check
|
## Register Check
|
||||||
|
|
||||||
This endpoint adds a new check to the local agent. Checks may be of script,
|
This endpoint adds a new check to the local agent. Checks may be of script,
|
||||||
HTTP, TCP, or TTL type. The agent is responsible for managing the status of the
|
HTTP, TCP, UDP, or TTL type. The agent is responsible for managing the status of the
|
||||||
check and keeping the Catalog in sync.
|
check and keeping the Catalog in sync.
|
||||||
|
|
||||||
| Method | Path | Produces |
|
| Method | Path | Produces |
|
||||||
|
@ -133,7 +133,7 @@ The table below shows this endpoint's support for
|
||||||
one of several [other methods to specify the namespace](#methods-to-specify-namespace).
|
one of several [other methods to specify the namespace](#methods-to-specify-namespace).
|
||||||
|
|
||||||
- `Interval` `(string: "")` - Specifies the frequency at which to run this
|
- `Interval` `(string: "")` - Specifies the frequency at which to run this
|
||||||
check. This is required for HTTP and TCP checks.
|
check. This is required for HTTP, TCP, and UDP checks.
|
||||||
|
|
||||||
- `Notes` `(string: "")` - Specifies arbitrary information for humans. This is
|
- `Notes` `(string: "")` - Specifies arbitrary information for humans. This is
|
||||||
not used by Consul internally.
|
not used by Consul internally.
|
||||||
|
@ -212,7 +212,7 @@ The table below shows this endpoint's support for
|
||||||
be set for `HTTP` checks. Each header can have multiple values.
|
be set for `HTTP` checks. Each header can have multiple values.
|
||||||
|
|
||||||
- `Timeout` `(duration: 10s)` - Specifies a timeout for outgoing connections in the
|
- `Timeout` `(duration: 10s)` - Specifies a timeout for outgoing connections in the
|
||||||
case of a Script, HTTP, TCP, or gRPC check. Can be specified in the form of "10s"
|
case of a Script, HTTP, TCP, UDP, or gRPC check. Can be specified in the form of "10s"
|
||||||
or "5m" (i.e., 10 seconds or 5 minutes, respectively).
|
or "5m" (i.e., 10 seconds or 5 minutes, respectively).
|
||||||
|
|
||||||
- `OutputMaxSize` `(positive int: 4096)` - Allow to put a maximum size of text
|
- `OutputMaxSize` `(positive int: 4096)` - Allow to put a maximum size of text
|
||||||
|
@ -237,6 +237,11 @@ The table below shows this endpoint's support for
|
||||||
made to both addresses, and the first successful connection attempt will
|
made to both addresses, and the first successful connection attempt will
|
||||||
result in a successful check.
|
result in a successful check.
|
||||||
|
|
||||||
|
- `UDP` `(string: "")` - Specifies a `UDP` IP address/hostname and port.
|
||||||
|
The check sends datagrams to the value specified at the interval specified in the `Interval` configuration.
|
||||||
|
If the datagram is sent successfully or a timeout is returned, the check is set to the `passing` state.
|
||||||
|
The check is logged as `critical` if the datagram is sent unsuccessfully.
|
||||||
|
|
||||||
- `TTL` `(duration: 10s)` - Specifies this is a TTL check, and the TTL endpoint
|
- `TTL` `(duration: 10s)` - Specifies this is a TTL check, and the TTL endpoint
|
||||||
must be used periodically to update the state of the check. If the check is not
|
must be used periodically to update the state of the check. If the check is not
|
||||||
set to passing within the specified duration, then the check will be set to the failed state.
|
set to passing within the specified duration, then the check will be set to the failed state.
|
||||||
|
|
|
@ -85,6 +85,12 @@ There are several different kinds of checks:
|
||||||
It is possible to configure a custom TCP check timeout value by specifying the
|
It is possible to configure a custom TCP check timeout value by specifying the
|
||||||
`timeout` field in the check definition.
|
`timeout` field in the check definition.
|
||||||
|
|
||||||
|
- `UDP + Interval` - These checks direct the client to periodically send UDP datagrams
|
||||||
|
to the specified IP/hostname and port. The duration specified in the `interval` field sets the amount of time
|
||||||
|
between attempts, such as `30s` to indicate 30 seconds. The check is logged as healthy if any response from the UDP server is received. Any other result sets the status to `critical`.
|
||||||
|
The default interval for, UDP checks is `10s`, but you can configure a custom UDP check timeout value by specifying the
|
||||||
|
`timeout` field in the check definition. If any timeout on read exists, the check is still considered healthy.
|
||||||
|
|
||||||
- `Time to Live (TTL)` ((#ttl)) - These checks retain their last known state
|
- `Time to Live (TTL)` ((#ttl)) - These checks retain their last known state
|
||||||
for a given TTL. The state of the check must be updated periodically over the HTTP
|
for a given TTL. The state of the check must be updated periodically over the HTTP
|
||||||
interface. If an external system fails to update the status within a given TTL,
|
interface. If an external system fails to update the status within a given TTL,
|
||||||
|
@ -243,6 +249,35 @@ check = {
|
||||||
|
|
||||||
</CodeTabs>
|
</CodeTabs>
|
||||||
|
|
||||||
|
A UDP check:
|
||||||
|
|
||||||
|
<CodeTabs heading="UDP Check">
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
check = {
|
||||||
|
id = "dns"
|
||||||
|
name = "DNS UDP on port 53"
|
||||||
|
udp = "localhost:53"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "1s"
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"check": {
|
||||||
|
"id": "dns",
|
||||||
|
"name": "DNS UDP on port 53",
|
||||||
|
"udp": "localhost:53",
|
||||||
|
"interval": "10s",
|
||||||
|
"timeout": "1s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</CodeTabs>
|
||||||
|
|
||||||
A TTL check:
|
A TTL check:
|
||||||
|
|
||||||
<CodeTabs heading="TTL Check">
|
<CodeTabs heading="TTL Check">
|
||||||
|
@ -429,7 +464,7 @@ used for any interaction with the catalog for the check, including
|
||||||
For Alias checks, this token is used if a remote blocking query is necessary
|
For Alias checks, this token is used if a remote blocking query is necessary
|
||||||
to watch the state of the aliased node or service.
|
to watch the state of the aliased node or service.
|
||||||
|
|
||||||
Script, TCP, HTTP, Docker, and gRPC checks must include an `interval` field. This
|
Script, TCP, UDP, HTTP, Docker, and gRPC checks must include an `interval` field. This
|
||||||
field is parsed by Go's `time` package, and has the following
|
field is parsed by Go's `time` package, and has the following
|
||||||
[formatting specification](https://golang.org/pkg/time/#ParseDuration):
|
[formatting specification](https://golang.org/pkg/time/#ParseDuration):
|
||||||
|
|
||||||
|
|
|
@ -82,14 +82,15 @@ Defines the Consul checks for the service. Each check may contain these fields.
|
||||||
| `h2pingUseTls` | `boolean` | optional | Specifies whether TLS is used for an h2ping check. |
|
| `h2pingUseTls` | `boolean` | optional | Specifies whether TLS is used for an h2ping check. |
|
||||||
| `header` | `object` | optional | Specifies a set of headers that should be set for HTTP checks. Each header can have multiple values. |
|
| `header` | `object` | optional | Specifies a set of headers that should be set for HTTP checks. Each header can have multiple values. |
|
||||||
| `http` | `string` | optional | Specifies this is an HTTP check. Must be a URL against which request is performed every `interval`. |
|
| `http` | `string` | optional | Specifies this is an HTTP check. Must be a URL against which request is performed every `interval`. |
|
||||||
| `interval` | `string` | optional | Specifies the frequency at which to run this check. Required for HTTP and TCP checks. |
|
| `interval` | `string` | optional | Specifies the frequency at which to run this check. Required for HTTP, TCP, and UDP checks. |
|
||||||
| `method` | `string` | optional | Specifies the HTTP method to be used for an HTTP check. When no value is specified, `GET` is used. |
|
| `method` | `string` | optional | Specifies the HTTP method to be used for an HTTP check. When no value is specified, `GET` is used. |
|
||||||
| `name` | `string` | optional | The name of the check. |
|
| `name` | `string` | optional | The name of the check. |
|
||||||
| `notes` | `string` | optional | Specifies arbitrary information for humans. This is not used by Consul internally. |
|
| `notes` | `string` | optional | Specifies arbitrary information for humans. This is not used by Consul internally. |
|
||||||
| `status` | `string` | optional | Specifies the initial status the health check. Must be one of `passing`, `warning`, `critical`, `maintenance`, or`null`. |
|
| `status` | `string` | optional | Specifies the initial status the health check. Must be one of `passing`, `warning`, `critical`, `maintenance`, or`null`. |
|
||||||
| `successBeforePassing` | `integer` | optional | Specifies the number of consecutive successful results required before check status transitions to passing. |
|
| `successBeforePassing` | `integer` | optional | Specifies the number of consecutive successful results required before check status transitions to passing. |
|
||||||
| `tcp` | `string` | optional | Specifies this is a TCP check. Must be an IP/hostname plus port to which a TCP connection is made every `interval`. |
|
| `tcp` | `string` | optional | Specifies this is a TCP check. Must be an IP/hostname plus port to which a TCP connection is made every `interval`. |
|
||||||
| `timeout` | `string` | optional | Specifies a timeout for outgoing connections in the case of a Script, HTTP, TCP, or gRPC check. Must be a duration string, such as `10s` or `5m`. |
|
| `udp` | `string` | optional | Specifies this is a UDP check. Must be an IP/hostname plus port to which UDP datagrams are sent every `interval`. |
|
||||||
|
| `timeout` | `string` | optional | Specifies a timeout for outgoing connections. Applies to script, HTTP, TCP, UDP, and gRPC checks. Must be a duration string, such as `10s` or `5m`. |
|
||||||
| `tlsServerName` | `string` | optional | Specifies an optional string used to set the SNI host when connecting via TLS. |
|
| `tlsServerName` | `string` | optional | Specifies an optional string used to set the SNI host when connecting via TLS. |
|
||||||
| `tlsSkipVerify` | `boolean` | optional | Specifies if the certificate for an HTTPS check should not be verified. |
|
| `tlsSkipVerify` | `boolean` | optional | Specifies if the certificate for an HTTPS check should not be verified. |
|
||||||
| `ttl` | `string` | optional | Specifies this is a TTL check. Must be a duration string, such as `10s` or `5m`. |
|
| `ttl` | `string` | optional | Specifies this is a TTL check. Must be a duration string, such as `10s` or `5m`. |
|
||||||
|
|
Loading…
Reference in New Issue