Store check type in catalog (#6561)
This commit is contained in:
parent
db9cc99497
commit
caf658d0d3
|
@ -2269,6 +2269,7 @@ func (a *Agent) addServiceInternal(req *addServiceRequest) error {
|
|||
ServiceID: service.ID,
|
||||
ServiceName: service.Service,
|
||||
ServiceTags: service.Tags,
|
||||
Type: chkType.Type(),
|
||||
}
|
||||
if chkType.Status != "" {
|
||||
check.Status = chkType.Status
|
||||
|
@ -3617,6 +3618,7 @@ func (a *Agent) EnableServiceMaintenance(serviceID, reason, token string) error
|
|||
ServiceID: service.ID,
|
||||
ServiceName: service.Service,
|
||||
Status: api.HealthCritical,
|
||||
Type: "maintenance",
|
||||
}
|
||||
a.AddCheck(check, nil, true, token, ConfigSourceLocal)
|
||||
a.logger.Printf("[INFO] agent: Service %q entered maintenance mode", serviceID)
|
||||
|
@ -3663,6 +3665,7 @@ func (a *Agent) EnableNodeMaintenance(reason, token string) {
|
|||
Name: "Node Maintenance Mode",
|
||||
Notes: reason,
|
||||
Status: api.HealthCritical,
|
||||
Type: "maintenance",
|
||||
}
|
||||
a.AddCheck(check, nil, true, token, ConfigSourceLocal)
|
||||
a.logger.Printf("[INFO] agent: Node entered maintenance mode")
|
||||
|
|
|
@ -492,6 +492,9 @@ func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Requ
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// Store the type of check based on the definition
|
||||
health.Type = chkType.Type()
|
||||
|
||||
if health.ServiceID != "" {
|
||||
// fixup the service name so that vetCheckRegister requires the right ACLs
|
||||
service := s.agent.State.Service(health.ServiceID)
|
||||
|
|
|
@ -2478,6 +2478,11 @@ func testAgent_RegisterService(t *testing.T, extraHCL string) {
|
|||
if len(checks) != 3 {
|
||||
t.Fatalf("bad: %v", checks)
|
||||
}
|
||||
for _, c := range checks {
|
||||
if c.Type != "ttl" {
|
||||
t.Fatalf("expected ttl check type, got %s", c.Type)
|
||||
}
|
||||
}
|
||||
|
||||
if len(a.checkTTLs) != 3 {
|
||||
t.Fatalf("missing test check ttls: %v", a.checkTTLs)
|
||||
|
@ -4115,6 +4120,11 @@ func TestAgent_RegisterCheck_Service(t *testing.T) {
|
|||
if result["memcache_check2"].ServiceID != "memcache" {
|
||||
t.Fatalf("bad: %#v", result["memcached_check2"])
|
||||
}
|
||||
|
||||
// Make sure the new check has the right type
|
||||
if result["memcache_check2"].Type != "ttl" {
|
||||
t.Fatalf("expected TTL type, got %s", result["memcache_check2"].Type)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgent_Monitor(t *testing.T) {
|
||||
|
|
|
@ -393,6 +393,7 @@ func testAgent_AddService(t *testing.T, extraHCL string) {
|
|||
ServiceID: "svcid1",
|
||||
ServiceName: "svcname1",
|
||||
ServiceTags: []string{"tag1"},
|
||||
Type: "ttl",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -438,6 +439,7 @@ func testAgent_AddService(t *testing.T, extraHCL string) {
|
|||
ServiceID: "svcid2",
|
||||
ServiceName: "svcname2",
|
||||
ServiceTags: []string{"tag2"},
|
||||
Type: "ttl",
|
||||
},
|
||||
"check-noname": &structs.HealthCheck{
|
||||
Node: "node1",
|
||||
|
@ -447,6 +449,7 @@ func testAgent_AddService(t *testing.T, extraHCL string) {
|
|||
ServiceID: "svcid2",
|
||||
ServiceName: "svcname2",
|
||||
ServiceTags: []string{"tag2"},
|
||||
Type: "ttl",
|
||||
},
|
||||
"service:svcid2:3": &structs.HealthCheck{
|
||||
Node: "node1",
|
||||
|
@ -456,6 +459,7 @@ func testAgent_AddService(t *testing.T, extraHCL string) {
|
|||
ServiceID: "svcid2",
|
||||
ServiceName: "svcname2",
|
||||
ServiceTags: []string{"tag2"},
|
||||
Type: "ttl",
|
||||
},
|
||||
"service:svcid2:4": &structs.HealthCheck{
|
||||
Node: "node1",
|
||||
|
@ -465,6 +469,7 @@ func testAgent_AddService(t *testing.T, extraHCL string) {
|
|||
ServiceID: "svcid2",
|
||||
ServiceName: "svcname2",
|
||||
ServiceTags: []string{"tag2"},
|
||||
Type: "ttl",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -828,8 +833,23 @@ func testAgent_RemoveServiceRemovesAllChecks(t *testing.T, extraHCL string) {
|
|||
svc := &structs.NodeService{ID: "redis", Service: "redis", Port: 8000}
|
||||
chk1 := &structs.CheckType{CheckID: "chk1", Name: "chk1", TTL: time.Minute}
|
||||
chk2 := &structs.CheckType{CheckID: "chk2", Name: "chk2", TTL: 2 * time.Minute}
|
||||
hchk1 := &structs.HealthCheck{Node: "node1", CheckID: "chk1", Name: "chk1", Status: "critical", ServiceID: "redis", ServiceName: "redis"}
|
||||
hchk2 := &structs.HealthCheck{Node: "node1", CheckID: "chk2", Name: "chk2", Status: "critical", ServiceID: "redis", ServiceName: "redis"}
|
||||
hchk1 := &structs.HealthCheck{
|
||||
Node: "node1",
|
||||
CheckID: "chk1",
|
||||
Name: "chk1",
|
||||
Status: "critical",
|
||||
ServiceID: "redis",
|
||||
ServiceName: "redis",
|
||||
Type: "ttl",
|
||||
}
|
||||
hchk2 := &structs.HealthCheck{Node: "node1",
|
||||
CheckID: "chk2",
|
||||
Name: "chk2",
|
||||
Status: "critical",
|
||||
ServiceID: "redis",
|
||||
ServiceName: "redis",
|
||||
Type: "ttl",
|
||||
}
|
||||
|
||||
// register service with chk1
|
||||
if err := a.AddService(svc, []*structs.CheckType{chk1}, false, "", ConfigSourceLocal); err != nil {
|
||||
|
|
|
@ -520,6 +520,59 @@ func TestCatalogServices_NodeMetaFilter(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCatalogRegister_checkRegistration(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := NewTestAgent(t, t.Name(), "")
|
||||
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{
|
||||
TCP: "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 != "tcp" {
|
||||
r.Fatalf("expected check type tcp, got %s", checks[0].Type)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCatalogServiceNodes(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := NewTestAgent(t, t.Name(), "")
|
||||
|
|
|
@ -127,6 +127,13 @@ func (c *Catalog) Register(args *structs.RegisterRequest, reply *struct{}) error
|
|||
check.Node = args.Node
|
||||
}
|
||||
checkPreApply(check)
|
||||
|
||||
// Populate check type for cases when a check is registered in the catalog directly
|
||||
// and not via anti-entropy
|
||||
if check.Type == "" {
|
||||
chkType := check.CheckType()
|
||||
check.Type = chkType.Type()
|
||||
}
|
||||
}
|
||||
|
||||
// Check the complete register request against the given ACL policy.
|
||||
|
|
|
@ -336,6 +336,7 @@ func TestHealthServiceChecks(t *testing.T) {
|
|||
Node: a.Config.NodeName,
|
||||
Name: "consul check",
|
||||
ServiceID: "consul",
|
||||
Type: "grpc",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -357,6 +358,9 @@ func TestHealthServiceChecks(t *testing.T) {
|
|||
if len(nodes) != 1 {
|
||||
t.Fatalf("bad: %v", obj)
|
||||
}
|
||||
if nodes[0].Type != "grpc" {
|
||||
t.Fatalf("expected grpc check type, got %s", nodes[0].Type)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthServiceChecks_NodeMetaFilter(t *testing.T) {
|
||||
|
@ -970,6 +974,59 @@ func TestHealthServiceNodes_PassingFilter(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestHealthServiceNodes_CheckType(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := NewTestAgent(t, t.Name(), "")
|
||||
defer a.Shutdown()
|
||||
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
||||
|
||||
req, _ := http.NewRequest("GET", "/v1/health/service/consul?dc=dc1", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
obj, err := a.srv.HealthServiceNodes(resp, req)
|
||||
require.NoError(t, err)
|
||||
assertIndex(t, resp)
|
||||
|
||||
// Should be 1 health check for consul
|
||||
nodes := obj.(structs.CheckServiceNodes)
|
||||
if len(nodes) != 1 {
|
||||
t.Fatalf("expected 1 node, got %d", len(nodes))
|
||||
}
|
||||
|
||||
args := &structs.RegisterRequest{
|
||||
Datacenter: "dc1",
|
||||
Node: a.Config.NodeName,
|
||||
Address: "127.0.0.1",
|
||||
NodeMeta: map[string]string{"somekey": "somevalue"},
|
||||
Check: &structs.HealthCheck{
|
||||
Node: a.Config.NodeName,
|
||||
Name: "consul check",
|
||||
ServiceID: "consul",
|
||||
Type: "grpc",
|
||||
},
|
||||
}
|
||||
|
||||
var out struct{}
|
||||
require.NoError(t, a.RPC("Catalog.Register", args, &out))
|
||||
|
||||
req, _ = http.NewRequest("GET", "/v1/health/service/consul?dc=dc1", nil)
|
||||
resp = httptest.NewRecorder()
|
||||
obj, err = a.srv.HealthServiceNodes(resp, req)
|
||||
require.NoError(t, err)
|
||||
|
||||
assertIndex(t, resp)
|
||||
|
||||
// Should be a non-nil empty list for checks
|
||||
nodes = obj.(structs.CheckServiceNodes)
|
||||
require.Len(t, nodes, 1)
|
||||
require.Len(t, nodes[0].Checks, 2)
|
||||
|
||||
for _, check := range nodes[0].Checks {
|
||||
if check.Name == "consul check" && check.Type != "grpc" {
|
||||
t.Fatalf("exptected grpc check type, got %s", check.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthServiceNodes_WanTranslation(t *testing.T) {
|
||||
t.Parallel()
|
||||
a1 := NewTestAgent(t, t.Name(), `
|
||||
|
|
|
@ -126,3 +126,24 @@ func (c *CheckType) IsDocker() bool {
|
|||
func (c *CheckType) IsGRPC() bool {
|
||||
return c.GRPC != "" && c.Interval > 0
|
||||
}
|
||||
|
||||
func (c *CheckType) Type() string {
|
||||
switch {
|
||||
case c.IsGRPC():
|
||||
return "grpc"
|
||||
case c.IsHTTP():
|
||||
return "http"
|
||||
case c.IsTTL():
|
||||
return "ttl"
|
||||
case c.IsTCP():
|
||||
return "tcp"
|
||||
case c.IsAlias():
|
||||
return "alias"
|
||||
case c.IsDocker():
|
||||
return "docker"
|
||||
case c.IsScript():
|
||||
return "script"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1139,6 +1139,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
|
||||
|
||||
Definition HealthCheckDefinition `bexpr:"-"`
|
||||
|
||||
|
@ -1254,6 +1255,32 @@ func (c *HealthCheck) Clone() *HealthCheck {
|
|||
return clone
|
||||
}
|
||||
|
||||
func (c *HealthCheck) CheckType() *CheckType {
|
||||
return &CheckType{
|
||||
CheckID: c.CheckID,
|
||||
Name: c.Name,
|
||||
Status: c.Status,
|
||||
Notes: c.Notes,
|
||||
|
||||
ScriptArgs: c.Definition.ScriptArgs,
|
||||
AliasNode: c.Definition.AliasNode,
|
||||
AliasService: c.Definition.AliasService,
|
||||
HTTP: c.Definition.HTTP,
|
||||
GRPC: c.Definition.GRPC,
|
||||
GRPCUseTLS: c.Definition.GRPCUseTLS,
|
||||
Header: c.Definition.Header,
|
||||
Method: c.Definition.Method,
|
||||
TCP: c.Definition.TCP,
|
||||
Interval: c.Definition.Interval,
|
||||
DockerContainerID: c.Definition.DockerContainerID,
|
||||
Shell: c.Definition.Shell,
|
||||
TLSSkipVerify: c.Definition.TLSSkipVerify,
|
||||
Timeout: c.Definition.Timeout,
|
||||
TTL: c.Definition.TTL,
|
||||
DeregisterCriticalServiceAfter: c.Definition.DeregisterCriticalServiceAfter,
|
||||
}
|
||||
}
|
||||
|
||||
// HealthChecks is a collection of HealthCheck structs.
|
||||
type HealthChecks []*HealthCheck
|
||||
|
||||
|
|
|
@ -462,6 +462,11 @@ var expectedFieldConfigHealthCheck bexpr.FieldConfigurations = bexpr.FieldConfig
|
|||
SupportedOperations: []bexpr.MatchOperator{bexpr.MatchIsEmpty, bexpr.MatchIsNotEmpty, bexpr.MatchIn, bexpr.MatchNotIn},
|
||||
StructFieldName: "ServiceTags",
|
||||
},
|
||||
"Type": &bexpr.FieldConfiguration{
|
||||
CoerceFn: bexpr.CoerceString,
|
||||
SupportedOperations: []bexpr.MatchOperator{bexpr.MatchEqual, bexpr.MatchNotEqual, bexpr.MatchIn, bexpr.MatchNotIn, bexpr.MatchMatches, bexpr.MatchNotMatches},
|
||||
StructFieldName: "Type",
|
||||
},
|
||||
}
|
||||
|
||||
var expectedFieldConfigCheckServiceNode bexpr.FieldConfigurations = bexpr.FieldConfigurations{
|
||||
|
|
|
@ -52,6 +52,7 @@ type AgentCheck struct {
|
|||
Output string
|
||||
ServiceID string
|
||||
ServiceName string
|
||||
Type string
|
||||
Definition HealthCheckDefinition
|
||||
}
|
||||
|
||||
|
|
|
@ -777,6 +777,9 @@ func TestAPI_AgentChecks(t *testing.T) {
|
|||
if chk.Status != HealthCritical {
|
||||
t.Fatalf("check not critical: %v", chk)
|
||||
}
|
||||
if chk.Type != "ttl" {
|
||||
t.Fatalf("expected type ttl, got %s", chk.Type)
|
||||
}
|
||||
|
||||
if err := agent.CheckDeregister("foo"); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
|
@ -951,6 +954,9 @@ func TestAPI_AgentChecks_serviceBound(t *testing.T) {
|
|||
if check.ServiceID != "redis" {
|
||||
t.Fatalf("missing service association for check: %v", check)
|
||||
}
|
||||
if check.Type != "ttl" {
|
||||
t.Fatalf("expected type ttl, got %s", check.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPI_AgentChecks_Docker(t *testing.T) {
|
||||
|
@ -997,6 +1003,9 @@ func TestAPI_AgentChecks_Docker(t *testing.T) {
|
|||
if check.ServiceID != "redis" {
|
||||
t.Fatalf("missing service association for check: %v", check)
|
||||
}
|
||||
if check.Type != "docker" {
|
||||
t.Fatalf("expected type ttl, got %s", check.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPI_AgentJoin(t *testing.T) {
|
||||
|
@ -1159,6 +1168,9 @@ func TestAPI_ServiceMaintenance(t *testing.T) {
|
|||
if strings.Contains(check.CheckID, "maintenance") {
|
||||
t.Fatalf("should have removed health check")
|
||||
}
|
||||
if check.Type != "maintenance" {
|
||||
t.Fatalf("expected type 'maintenance', got %s", check.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1207,6 +1219,9 @@ func TestAPI_NodeMaintenance(t *testing.T) {
|
|||
if strings.Contains(check.CheckID, "maintenance") {
|
||||
t.Fatalf("should have removed health check")
|
||||
}
|
||||
if check.Type != "maintenance" {
|
||||
t.Fatalf("expected type 'maintenance', got %s", check.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ type HealthCheck struct {
|
|||
ServiceID string
|
||||
ServiceName string
|
||||
ServiceTags []string
|
||||
Type string
|
||||
|
||||
Definition HealthCheckDefinition
|
||||
|
||||
|
|
|
@ -223,6 +223,7 @@ func TestAPI_HealthChecks(t *testing.T) {
|
|||
ServiceID: "foo",
|
||||
ServiceName: "foo",
|
||||
ServiceTags: []string{"bar"},
|
||||
Type: "ttl",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -272,8 +273,11 @@ func TestAPI_HealthChecks_NodeMetaFilter(t *testing.T) {
|
|||
if meta.LastIndex == 0 {
|
||||
r.Fatalf("bad: %v", meta)
|
||||
}
|
||||
if len(checks) == 0 {
|
||||
r.Fatalf("Bad: %v", checks)
|
||||
if len(checks) != 1 {
|
||||
r.Fatalf("expected 1 check, got %d", len(checks))
|
||||
}
|
||||
if checks[0].Type != "ttl" {
|
||||
r.Fatalf("expected type ttl, got %s", checks[0].Type)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -356,6 +360,12 @@ func TestAPI_HealthService_SingleTag(t *testing.T) {
|
|||
require.NotEqual(r, meta.LastIndex, 0)
|
||||
require.Len(r, services, 1)
|
||||
require.Equal(r, services[0].Service.ID, "foo1")
|
||||
|
||||
for _, check := range services[0].Checks {
|
||||
if check.CheckID == "service:foo1" && check.Type != "ttl" {
|
||||
r.Fatalf("expected type ttl, got %s", check.Type)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
func TestAPI_HealthService_MultipleTags(t *testing.T) {
|
||||
|
|
|
@ -194,6 +194,7 @@ func TestAPI_ClientTxn(t *testing.T) {
|
|||
DeregisterCriticalServiceAfter: ReadableDuration(20 * time.Second),
|
||||
DeregisterCriticalServiceAfterDuration: 20 * time.Second,
|
||||
},
|
||||
Type: "tcp",
|
||||
CreateIndex: ret.Results[4].Check.CreateIndex,
|
||||
ModifyIndex: ret.Results[4].Check.CreateIndex,
|
||||
},
|
||||
|
@ -212,6 +213,7 @@ func TestAPI_ClientTxn(t *testing.T) {
|
|||
DeregisterCriticalServiceAfter: ReadableDuration(160 * time.Second),
|
||||
DeregisterCriticalServiceAfterDuration: 160 * time.Second,
|
||||
},
|
||||
Type: "tcp",
|
||||
CreateIndex: ret.Results[4].Check.CreateIndex,
|
||||
ModifyIndex: ret.Results[4].Check.CreateIndex,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue