Browse Source

agent: Adding UI services endpoint

pull/98/head
Armon Dadgar 11 years ago committed by Jack Pearkes
parent
commit
416ff8f7d6
  1. 1
      command/agent/http.go
  2. 75
      command/agent/ui_endpoint.go
  3. 94
      command/agent/ui_endpoint_test.go

1
command/agent/http.go

@ -108,6 +108,7 @@ func (s *HTTPServer) registerHandlers(enableDebug bool) {
// API's are under /internal/ui/ to avoid conflict
s.mux.HandleFunc("/v1/internal/ui/nodes", s.wrap(s.UINodes))
s.mux.HandleFunc("/v1/internal/ui/node/", s.wrap(s.UINodeInfo))
s.mux.HandleFunc("/v1/internal/ui/services", s.wrap(s.UIServices))
}
}

75
command/agent/ui_endpoint.go

@ -3,9 +3,19 @@ package agent
import (
"github.com/hashicorp/consul/consul/structs"
"net/http"
"sort"
"strings"
)
// ServiceSummary is used to summarize a service
type ServiceSummary struct {
Name string
Nodes []string
ChecksPassing int
ChecksWarning int
ChecksCritical int
}
// UINodes is used to list the nodes in a given datacenter. We return a
// NodeDump which provides overview information for all the nodes
func (s *HTTPServer) UINodes(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
@ -86,3 +96,68 @@ START:
*dump = out.Dump
return nil
}
// UIServices is used to list the services in a given datacenter. We return a
// ServiceSummary which provides overview information for the service
func (s *HTTPServer) UIServices(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
// Get the datacenter
var dc string
s.parseDC(req, &dc)
// Get the full node dump...
var dump structs.NodeDump
if err := s.getNodeDump(resp, dc, "", &dump); err != nil {
return nil, err
}
// Generate the summary
return summarizeServices(dump), nil
}
func summarizeServices(dump structs.NodeDump) []*ServiceSummary {
// Collect the summary information
var services []string
summary := make(map[string]*ServiceSummary)
getService := func(service string) *ServiceSummary {
serv, ok := summary[service]
if !ok {
serv = &ServiceSummary{Name: service}
summary[service] = serv
services = append(services, service)
}
return serv
}
// Aggregate all the node information
for _, node := range dump {
for _, service := range node.Services {
sum := getService(service.Service)
sum.Nodes = append(sum.Nodes, node.Node)
}
for _, check := range node.Checks {
if check.ServiceName == "" {
continue
}
sum := getService(check.ServiceName)
switch check.Status {
case structs.HealthPassing:
sum.ChecksPassing++
case structs.HealthWarning:
sum.ChecksWarning++
case structs.HealthCritical:
sum.ChecksCritical++
}
}
}
// Return the services in sorted order
sort.Strings(services)
output := make([]*ServiceSummary, len(summary))
for idx, service := range services {
// Sort the nodes
sum := summary[service]
sort.Strings(sum.Nodes)
output[idx] = sum
}
return output
}

94
command/agent/ui_endpoint_test.go

@ -10,6 +10,7 @@ import (
"net/http/httptest"
"os"
"path/filepath"
"reflect"
"testing"
"time"
)
@ -109,3 +110,96 @@ func TestUiNodeInfo(t *testing.T) {
t.Fatalf("bad: %v", node)
}
}
func TestSummarizeServices(t *testing.T) {
dump := structs.NodeDump{
&structs.NodeInfo{
Node: "foo",
Address: "127.0.0.1",
Services: []*structs.NodeService{
&structs.NodeService{
Service: "api",
},
&structs.NodeService{
Service: "web",
},
},
Checks: []*structs.HealthCheck{
&structs.HealthCheck{
Status: structs.HealthCritical,
ServiceName: "",
},
&structs.HealthCheck{
Status: structs.HealthPassing,
ServiceName: "web",
},
&structs.HealthCheck{
Status: structs.HealthWarning,
ServiceName: "api",
},
},
},
&structs.NodeInfo{
Node: "bar",
Address: "127.0.0.2",
Services: []*structs.NodeService{
&structs.NodeService{
Service: "web",
},
},
Checks: []*structs.HealthCheck{
&structs.HealthCheck{
Status: structs.HealthCritical,
ServiceName: "web",
},
},
},
&structs.NodeInfo{
Node: "zip",
Address: "127.0.0.3",
Services: []*structs.NodeService{
&structs.NodeService{
Service: "cache",
},
},
},
}
summary := summarizeServices(dump)
if len(summary) != 3 {
t.Fatalf("bad: %v", summary)
}
expectAPI := &ServiceSummary{
Name: "api",
Nodes: []string{"foo"},
ChecksPassing: 0,
ChecksWarning: 1,
ChecksCritical: 0,
}
if !reflect.DeepEqual(summary[0], expectAPI) {
t.Fatalf("bad: %v", summary[0])
}
expectCache := &ServiceSummary{
Name: "cache",
Nodes: []string{"zip"},
ChecksPassing: 0,
ChecksWarning: 0,
ChecksCritical: 0,
}
if !reflect.DeepEqual(summary[1], expectCache) {
t.Fatalf("bad: %v", summary[1])
}
expectWeb := &ServiceSummary{
Name: "web",
Nodes: []string{"bar", "foo"},
ChecksPassing: 1,
ChecksWarning: 0,
ChecksCritical: 1,
}
if !reflect.DeepEqual(summary[2], expectWeb) {
t.Fatalf("bad: %v", summary[2])
}
}

Loading…
Cancel
Save