From d6b7dd5b62a423037c7019145c54343129e7fb02 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 21 Apr 2014 16:08:26 -0700 Subject: [PATCH] agent: Support server-side filtering of passing checks. Fixes #57. --- command/agent/health_endpoint.go | 21 +++++++++ command/agent/health_endpoint_test.go | 45 ++++++++++++++++++++ website/source/docs/agent/http.html.markdown | 4 ++ 3 files changed, 70 insertions(+) diff --git a/command/agent/health_endpoint.go b/command/agent/health_endpoint.go index e77444e39..8462e0a4b 100644 --- a/command/agent/health_endpoint.go +++ b/command/agent/health_endpoint.go @@ -106,5 +106,26 @@ func (s *HTTPServer) HealthServiceNodes(resp http.ResponseWriter, req *http.Requ if err := s.agent.RPC("Health.ServiceNodes", &args, &out); err != nil { return nil, err } + + // Filter to only passing if specified + if _, ok := params["passing"]; ok { + out.Nodes = filterNonPassing(out.Nodes) + } return out.Nodes, nil } + +// filterNonPassing is used to filter out any nodes that have check that are not passing +func filterNonPassing(nodes structs.CheckServiceNodes) structs.CheckServiceNodes { + n := len(nodes) + for i := 0; i < n; i++ { + node := nodes[i] + for _, check := range node.Checks { + if check.Status != structs.HealthPassing { + nodes[i], nodes[n-1] = nodes[n-1], structs.CheckServiceNode{} + n-- + i-- + } + } + } + return nodes[:n] +} diff --git a/command/agent/health_endpoint_test.go b/command/agent/health_endpoint_test.go index b8bf1bef5..e51f26084 100644 --- a/command/agent/health_endpoint_test.go +++ b/command/agent/health_endpoint_test.go @@ -138,3 +138,48 @@ func TestHealthServiceNodes(t *testing.T) { t.Fatalf("bad: %v", obj) } } + +func TestHealthServiceNodes_PassingFilter(t *testing.T) { + dir, srv := makeHTTPServer(t) + defer os.RemoveAll(dir) + defer srv.Shutdown() + defer srv.agent.Shutdown() + + // Wait for a leader + time.Sleep(100 * time.Millisecond) + + // Create a failing service check + args := &structs.RegisterRequest{ + Datacenter: "dc1", + Node: srv.agent.config.NodeName, + Address: "127.0.0.1", + Check: &structs.HealthCheck{ + Node: srv.agent.config.NodeName, + Name: "consul check", + ServiceID: "consul", + Status: structs.HealthCritical, + }, + } + var out struct{} + if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { + t.Fatalf("err: %v", err) + } + + req, err := http.NewRequest("GET", "/v1/health/service/consul?passing", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + + resp := httptest.NewRecorder() + obj, err := srv.HealthServiceNodes(resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + assertIndex(t, resp) + + // Should be 0 health check for consul + nodes := obj.(structs.CheckServiceNodes) + if len(nodes) != 0 { + t.Fatalf("bad: %v", obj) + } +} diff --git a/website/source/docs/agent/http.html.markdown b/website/source/docs/agent/http.html.markdown index 8d4079422..6f031564a 100644 --- a/website/source/docs/agent/http.html.markdown +++ b/website/source/docs/agent/http.html.markdown @@ -681,6 +681,10 @@ endpoint automatically returns the status of the associated health check, as well as any system level health checks. This allows a client to avoid sending traffic to nodes failing health tests, or who are reporting warnings. +Providing the "?passing" query parameter will filter results to only nodes +with all checks in the passing state. This can be used to avoid some filtering +logic on the client side. (Added in Consul 0.2) + Users can also built in support for dynamic load balancing and other features by incorporating the use of health checks.