* 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 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 map[structs.CheckID]*checks.CheckGRPC
|
||||
|
||||
|
@ -401,6 +404,7 @@ func New(bd BaseDeps) (*Agent, error) {
|
|||
checkHTTPs: make(map[structs.CheckID]*checks.CheckHTTP),
|
||||
checkH2PINGs: make(map[structs.CheckID]*checks.CheckH2PING),
|
||||
checkTCPs: make(map[structs.CheckID]*checks.CheckTCP),
|
||||
checkUDPs: make(map[structs.CheckID]*checks.CheckUDP),
|
||||
checkGRPCs: make(map[structs.CheckID]*checks.CheckGRPC),
|
||||
checkDockers: make(map[structs.CheckID]*checks.CheckDocker),
|
||||
checkAliases: make(map[structs.CheckID]*checks.CheckAlias),
|
||||
|
@ -1497,6 +1501,9 @@ func (a *Agent) ShutdownAgent() error {
|
|||
for _, chk := range a.checkTCPs {
|
||||
chk.Stop()
|
||||
}
|
||||
for _, chk := range a.checkUDPs {
|
||||
chk.Stop()
|
||||
}
|
||||
for _, chk := range a.checkGRPCs {
|
||||
chk.Stop()
|
||||
}
|
||||
|
@ -2796,6 +2803,31 @@ func (a *Agent) addCheck(check *structs.HealthCheck, chkType *structs.CheckType,
|
|||
tcp.Start()
|
||||
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():
|
||||
if existing, ok := a.checkGRPCs[cid]; ok {
|
||||
existing.Stop()
|
||||
|
@ -3095,6 +3127,10 @@ func (a *Agent) cancelCheckMonitors(checkID structs.CheckID) {
|
|||
check.Stop()
|
||||
delete(a.checkTCPs, checkID)
|
||||
}
|
||||
if check, ok := a.checkUDPs[checkID]; ok {
|
||||
check.Stop()
|
||||
delete(a.checkUDPs, checkID)
|
||||
}
|
||||
if check, ok := a.checkGRPCs[checkID]; ok {
|
||||
check.Stop()
|
||||
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
|
||||
// support as a result of https://github.com/hashicorp/consul/issues/3587.
|
||||
func TestAgent_RegisterCheck_Scripts(t *testing.T) {
|
||||
|
@ -3276,6 +3318,10 @@ func testAgent_RegisterService(t *testing.T, extraHCL string) {
|
|||
{
|
||||
TTL: 30 * time.Second,
|
||||
},
|
||||
{
|
||||
UDP: "1.1.1.1",
|
||||
Interval: 5 * time.Second,
|
||||
},
|
||||
},
|
||||
Weights: &structs.Weights{
|
||||
Passing: 100,
|
||||
|
@ -3307,12 +3353,12 @@ func testAgent_RegisterService(t *testing.T, extraHCL string) {
|
|||
|
||||
// Ensure we have a check mapping
|
||||
checks := a.State.Checks(structs.WildcardEnterpriseMetaInDefaultPartition())
|
||||
if len(checks) != 3 {
|
||||
if len(checks) != 4 {
|
||||
t.Fatalf("bad: %v", checks)
|
||||
}
|
||||
for _, c := range checks {
|
||||
if c.Type != "ttl" {
|
||||
t.Fatalf("expected ttl check type, got %s", c.Type)
|
||||
if c.Type != "ttl" && c.Type != "udp" {
|
||||
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"),
|
||||
TTL: 30 * time.Second,
|
||||
},
|
||||
{
|
||||
CheckID: types.CheckID("check_3"),
|
||||
UDP: "1.1.1.1",
|
||||
Interval: 5 * time.Second,
|
||||
},
|
||||
},
|
||||
Weights: &structs.Weights{
|
||||
Passing: 100,
|
||||
|
@ -3387,6 +3438,11 @@ func testAgent_RegisterService_ReRegister(t *testing.T, extraHCL string) {
|
|||
CheckID: types.CheckID("check_3"),
|
||||
TTL: 30 * time.Second,
|
||||
},
|
||||
{
|
||||
CheckID: types.CheckID("check_3"),
|
||||
UDP: "1.1.1.1",
|
||||
Interval: 5 * time.Second,
|
||||
},
|
||||
},
|
||||
Weights: &structs.Weights{
|
||||
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) {
|
||||
if 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
|
||||
// registration. This doesn't need to test validation exhaustively since
|
||||
// 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) {
|
||||
if testing.Short() {
|
||||
t.Skip("too slow for testing.Short")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package checks
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
|
@ -703,6 +704,135 @@ func (c *CheckTCP) check() {
|
|||
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
|
||||
// determine the health of an application running inside a
|
||||
// Docker Container. We assume that the script is compatible
|
||||
|
|
|
@ -2,20 +2,25 @@ package checks
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/agent/mock"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/sdk/freeport"
|
||||
"github.com/hashicorp/consul/sdk/testutil"
|
||||
"github.com/hashicorp/consul/sdk/testutil/retry"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
|
@ -1141,6 +1146,152 @@ func TestCheckTCPPassing(t *testing.T) {
|
|||
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) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -403,6 +403,7 @@ type CheckDefinition struct {
|
|||
DisableRedirects *bool `mapstructure:"disable_redirects"`
|
||||
OutputMaxSize *int `mapstructure:"output_max_size"`
|
||||
TCP *string `mapstructure:"tcp"`
|
||||
UDP *string `mapstructure:"udp"`
|
||||
Interval *string `mapstructure:"interval"`
|
||||
DockerContainerID *string `mapstructure:"docker_container_id" alias:"dockercontainerid"`
|
||||
Shell *string `mapstructure:"shell"`
|
||||
|
|
|
@ -118,7 +118,8 @@
|
|||
"TLSSkipVerify": false,
|
||||
"TTL": "0s",
|
||||
"Timeout": "0s",
|
||||
"Token": "hidden"
|
||||
"Token": "hidden",
|
||||
"UDP": ""
|
||||
}
|
||||
],
|
||||
"ClientAddrs": [],
|
||||
|
@ -324,7 +325,8 @@
|
|||
"TLSServerName": "",
|
||||
"TLSSkipVerify": false,
|
||||
"TTL": "0s",
|
||||
"Timeout": "0s"
|
||||
"Timeout": "0s",
|
||||
"UDP": ""
|
||||
},
|
||||
"Checks": [],
|
||||
"Connect": null,
|
||||
|
|
|
@ -33,6 +33,7 @@ type CheckDefinition struct {
|
|||
Body string
|
||||
DisableRedirects bool
|
||||
TCP string
|
||||
UDP string
|
||||
Interval time.Duration
|
||||
DockerContainerID string
|
||||
Shell string
|
||||
|
@ -215,6 +216,7 @@ func (c *CheckDefinition) CheckType() *CheckType {
|
|||
DisableRedirects: c.DisableRedirects,
|
||||
OutputMaxSize: c.OutputMaxSize,
|
||||
TCP: c.TCP,
|
||||
UDP: c.UDP,
|
||||
Interval: c.Interval,
|
||||
DockerContainerID: c.DockerContainerID,
|
||||
Shell: c.Shell,
|
||||
|
|
|
@ -39,6 +39,7 @@ type CheckType struct {
|
|||
Body string
|
||||
DisableRedirects bool
|
||||
TCP string
|
||||
UDP string
|
||||
Interval time.Duration
|
||||
AliasNode 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
|
||||
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 {
|
||||
return fmt.Errorf("Interval and TTL cannot both be specified")
|
||||
}
|
||||
if intervalCheck && c.Interval <= 0 {
|
||||
return fmt.Errorf("Interval must be > 0 for Script, HTTP, H2PING, or TCP checks")
|
||||
return fmt.Errorf("Interval must be > 0 for Script, HTTP, H2PING, TCP or UDP checks")
|
||||
}
|
||||
if intervalCheck && c.IsAlias() {
|
||||
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
|
||||
}
|
||||
|
||||
func (c *CheckType) IsUDP() bool {
|
||||
return c.UDP != "" && c.Interval > 0
|
||||
}
|
||||
|
||||
// IsDocker returns true when checking a docker container.
|
||||
func (c *CheckType) IsDocker() bool {
|
||||
return c.IsScript() && c.DockerContainerID != "" && c.Interval > 0
|
||||
|
@ -266,6 +271,8 @@ func (c *CheckType) Type() string {
|
|||
return "ttl"
|
||||
case c.IsTCP():
|
||||
return "tcp"
|
||||
case c.IsUDP():
|
||||
return "udp"
|
||||
case c.IsAlias():
|
||||
return "alias"
|
||||
case c.IsDocker():
|
||||
|
|
|
@ -1670,7 +1670,7 @@ type HealthCheck struct {
|
|||
ServiceID string // optional associated service
|
||||
ServiceName string // optional service name
|
||||
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
|
||||
Timeout string // from definition
|
||||
|
@ -1735,6 +1735,7 @@ type HealthCheckDefinition struct {
|
|||
Body string `json:",omitempty"`
|
||||
DisableRedirects bool `json:",omitempty"`
|
||||
TCP string `json:",omitempty"`
|
||||
UDP string `json:",omitempty"`
|
||||
H2PING string `json:",omitempty"`
|
||||
H2PingUseTLS bool `json:",omitempty"`
|
||||
Interval time.Duration `json:",omitempty"`
|
||||
|
@ -1885,6 +1886,7 @@ func (c *HealthCheck) CheckType() *CheckType {
|
|||
Body: c.Definition.Body,
|
||||
DisableRedirects: c.Definition.DisableRedirects,
|
||||
TCP: c.Definition.TCP,
|
||||
UDP: c.Definition.UDP,
|
||||
H2PING: c.Definition.H2PING,
|
||||
H2PingUseTLS: c.Definition.H2PingUseTLS,
|
||||
Interval: c.Definition.Interval,
|
||||
|
|
|
@ -333,6 +333,7 @@ type AgentServiceCheck struct {
|
|||
Method string `json:",omitempty"`
|
||||
Body string `json:",omitempty"`
|
||||
TCP string `json:",omitempty"`
|
||||
UDP string `json:",omitempty"`
|
||||
Status string `json:",omitempty"`
|
||||
Notes string `json:",omitempty"`
|
||||
TLSServerName string `json:",omitempty"`
|
||||
|
|
|
@ -62,6 +62,7 @@ type HealthCheckDefinition struct {
|
|||
TLSServerName string
|
||||
TLSSkipVerify bool
|
||||
TCP string
|
||||
UDP string
|
||||
GRPC string
|
||||
GRPCUseTLS bool
|
||||
IntervalDuration time.Duration `json:"-"`
|
||||
|
|
|
@ -56,6 +56,28 @@ func TestAPI_ClientTxn(t *testing.T) {
|
|||
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)
|
||||
|
@ -115,6 +137,18 @@ func TestAPI_ClientTxn(t *testing.T) {
|
|||
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)
|
||||
if err != nil {
|
||||
|
@ -141,7 +175,7 @@ func TestAPI_ClientTxn(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
expected := TxnResults{
|
||||
|
@ -230,6 +264,48 @@ func TestAPI_ClientTxn(t *testing.T) {
|
|||
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)
|
||||
|
||||
|
|
|
@ -149,10 +149,10 @@ function install_unversioned_tool {
|
|||
local install="$2"
|
||||
|
||||
if ! command -v "${command}" &>/dev/null ; then
|
||||
status_stage "installing tool: ${install}"
|
||||
echo "installing tool: ${install}"
|
||||
go install "${install}"
|
||||
else
|
||||
debug "skipping tool: ${install} (installed)"
|
||||
echo "skipping tool: ${install} (installed)"
|
||||
fi
|
||||
|
||||
return 0
|
||||
|
@ -183,7 +183,7 @@ function install_versioned_tool {
|
|||
err "dev version of '${command}' requested but not installed"
|
||||
return 1
|
||||
fi
|
||||
status "skipping tool: ${installbase} (using development version)"
|
||||
echo "skipping tool: ${installbase} (using development version)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
@ -210,10 +210,10 @@ function install_versioned_tool {
|
|||
fi
|
||||
|
||||
if [[ -n $should_install ]]; then
|
||||
status_stage "installing tool (${install_reason}): ${install}"
|
||||
echo "installing tool (${install_reason}): ${install}"
|
||||
go install "${install}"
|
||||
else
|
||||
debug "skipping tool: ${install} (installed)"
|
||||
echo "skipping tool: ${install} (installed)"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ func CheckTypeToStructs(s *CheckType, t *structs.CheckType) {
|
|||
t.Body = s.Body
|
||||
t.DisableRedirects = s.DisableRedirects
|
||||
t.TCP = s.TCP
|
||||
t.UDP = s.UDP
|
||||
t.Interval = structs.DurationFromProto(s.Interval)
|
||||
t.AliasNode = s.AliasNode
|
||||
t.AliasService = s.AliasService
|
||||
|
@ -57,6 +58,7 @@ func CheckTypeFromStructs(t *structs.CheckType, s *CheckType) {
|
|||
s.Body = t.Body
|
||||
s.DisableRedirects = t.DisableRedirects
|
||||
s.TCP = t.TCP
|
||||
s.UDP = t.UDP
|
||||
s.Interval = structs.DurationToProto(t.Interval)
|
||||
s.AliasNode = t.AliasNode
|
||||
s.AliasService = t.AliasService
|
||||
|
@ -138,6 +140,7 @@ func HealthCheckDefinitionToStructs(s *HealthCheckDefinition, t *structs.HealthC
|
|||
t.Body = s.Body
|
||||
t.DisableRedirects = s.DisableRedirects
|
||||
t.TCP = s.TCP
|
||||
t.UDP = s.UDP
|
||||
t.H2PING = s.H2PING
|
||||
t.H2PingUseTLS = s.H2PingUseTLS
|
||||
t.Interval = structs.DurationFromProto(s.Interval)
|
||||
|
@ -165,6 +168,7 @@ func HealthCheckDefinitionFromStructs(t *structs.HealthCheckDefinition, s *Healt
|
|||
s.Body = t.Body
|
||||
s.DisableRedirects = t.DisableRedirects
|
||||
s.TCP = t.TCP
|
||||
s.UDP = t.UDP
|
||||
s.H2PING = t.H2PING
|
||||
s.H2PingUseTLS = t.H2PingUseTLS
|
||||
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"`
|
||||
DisableRedirects bool `protobuf:"varint,22,opt,name=DisableRedirects,proto3" json:"DisableRedirects,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
|
||||
Interval *durationpb.Duration `protobuf:"bytes,6,opt,name=Interval,proto3" json:"Interval,omitempty"`
|
||||
// mog: func-to=uint func-from=uint32
|
||||
|
@ -385,6 +386,13 @@ func (x *HealthCheckDefinition) GetTCP() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (x *HealthCheckDefinition) GetUDP() string {
|
||||
if x != nil {
|
||||
return x.UDP
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HealthCheckDefinition) GetInterval() *durationpb.Duration {
|
||||
if x != nil {
|
||||
return x.Interval
|
||||
|
@ -513,6 +521,7 @@ type CheckType struct {
|
|||
Body string `protobuf:"bytes,26,opt,name=Body,proto3" json:"Body,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"`
|
||||
UDP string `protobuf:"bytes,32,opt,name=UDP,proto3" json:"UDP,omitempty"`
|
||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||
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"`
|
||||
|
@ -656,6 +665,13 @@ func (x *CheckType) GetTCP() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (x *CheckType) GetUDP() string {
|
||||
if x != nil {
|
||||
return x.UDP
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CheckType) GetInterval() *durationpb.Duration {
|
||||
if x != nil {
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
|
@ -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,
|
||||
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,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x43, 0x50, 0x12, 0x35, 0x0a, 0x08, 0x49, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x06, 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, 0x24, 0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a,
|
||||
0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d,
|
||||
0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75,
|
||||
0x74, 0x18, 0x07, 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, 0x61, 0x0a, 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,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x43, 0x50, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x44, 0x50,
|
||||
0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x44, 0x50, 0x12, 0x35, 0x0a, 0x08, 0x49,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x06, 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, 0x24, 0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78, 0x53,
|
||||
0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75,
|
||||
0x74, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x54, 0x69, 0x6d, 0x65,
|
||||
0x6f, 0x75, 0x74, 0x18, 0x07, 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, 0x61, 0x0a,
|
||||
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,
|
||||
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,
|
||||
0x74, 0x6f, 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, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x03, 0x6b, 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, 0xe2, 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, 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,
|
||||
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,
|
||||
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
|
||||
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,
|
||||
0x4c, 0x12, 0x32, 0x0a, 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, 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,
|
||||
0x63, 0x65, 0x73, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x50, 0x61, 0x73, 0x73, 0x69, 0x6e,
|
||||
0x67, 0x12, 0x34, 0x0a, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65, 0x66,
|
||||
0x6f, 0x72, 0x65, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x05,
|
||||
0x52, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65,
|
||||
0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x36, 0x0a, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75,
|
||||
0x72, 0x65, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
|
||||
0x6c, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65,
|
||||
0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x12,
|
||||
0x1c, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x54, 0x54, 0x50, 0x18, 0x17, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x54, 0x54, 0x50, 0x12, 0x1c, 0x0a,
|
||||
0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x47, 0x52, 0x50, 0x43, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x47, 0x52, 0x50, 0x43, 0x12, 0x61, 0x0a, 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, 0x13, 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, 0x24,
|
||||
0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x18,
|
||||
0x19, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78,
|
||||
0x53, 0x69, 0x7a, 0x65, 0x1a, 0x4f, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e,
|
||||
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x03, 0x6b, 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, 0x42, 0x88, 0x01, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65,
|
||||
0x63, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f,
|
||||
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x53,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0xca, 0x02, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0xe2, 0x02, 0x13, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65,
|
||||
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x73, 0x73, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65,
|
||||
0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x1d,
|
||||
0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65,
|
||||
0x66, 0x6f, 0x72, 0x65, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x36, 0x0a, 0x16, 0x46,
|
||||
0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x69,
|
||||
0x74, 0x69, 0x63, 0x61, 0x6c, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x16, 0x46, 0x61, 0x69,
|
||||
0x6c, 0x75, 0x72, 0x65, 0x73, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x69, 0x74, 0x69,
|
||||
0x63, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x54, 0x54, 0x50,
|
||||
0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x54, 0x54,
|
||||
0x50, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x47, 0x52, 0x50, 0x43, 0x18, 0x18,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x47, 0x52, 0x50, 0x43, 0x12,
|
||||
0x61, 0x0a, 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, 0x13, 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, 0x24, 0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4d, 0x61, 0x78, 0x53,
|
||||
0x69, 0x7a, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75,
|
||||
0x74, 0x4d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x1a, 0x4f, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64,
|
||||
0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 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, 0x42, 0x88, 0x01, 0x0a, 0x0b, 0x63, 0x6f,
|
||||
0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74,
|
||||
0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
|
||||
0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2f, 0x70, 0x62, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58,
|
||||
0xaa, 0x02, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0xca, 0x02, 0x07, 0x53, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0xe2, 0x02, 0x13, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5c, 0x47,
|
||||
0x50, 0x42, 0x4d, 0x65, 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 (
|
||||
|
|
|
@ -63,6 +63,7 @@ message HealthCheckDefinition {
|
|||
string Body = 18;
|
||||
bool DisableRedirects = 22;
|
||||
string TCP = 5;
|
||||
string UDP = 23;
|
||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||
google.protobuf.Duration Interval = 6;
|
||||
|
||||
|
@ -112,6 +113,7 @@ message CheckType {
|
|||
string Body = 26;
|
||||
bool DisableRedirects = 31;
|
||||
string TCP = 8;
|
||||
string UDP = 32;
|
||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||
google.protobuf.Duration Interval = 9;
|
||||
|
||||
|
@ -125,6 +127,7 @@ message CheckType {
|
|||
bool GRPCUseTLS = 15;
|
||||
string TLSServerName = 27;
|
||||
bool TLSSkipVerify = 16;
|
||||
|
||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||
google.protobuf.Duration Timeout = 17;
|
||||
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||
|
|
|
@ -98,7 +98,7 @@ the following selectors and filter operations being supported:
|
|||
## Register Check
|
||||
|
||||
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.
|
||||
|
||||
| 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).
|
||||
|
||||
- `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
|
||||
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.
|
||||
|
||||
- `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).
|
||||
|
||||
- `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
|
||||
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
|
||||
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.
|
||||
|
|
|
@ -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
|
||||
`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
|
||||
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,
|
||||
|
@ -243,6 +249,35 @@ check = {
|
|||
|
||||
</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:
|
||||
|
||||
<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
|
||||
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
|
||||
[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. |
|
||||
| `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`. |
|
||||
| `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. |
|
||||
| `name` | `string` | optional | The name of the check. |
|
||||
| `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`. |
|
||||
| `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`. |
|
||||
| `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. |
|
||||
| `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`. |
|
||||
|
|
Loading…
Reference in New Issue