mirror of https://github.com/status-im/consul.git
agent: RPC changes and blocking query support
This commit is contained in:
parent
1996deaa18
commit
c58c53f448
|
@ -57,51 +57,43 @@ func (s *HTTPServer) CatalogDatacenters(resp http.ResponseWriter, req *http.Requ
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTTPServer) CatalogNodes(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
func (s *HTTPServer) CatalogNodes(resp http.ResponseWriter, req *http.Request) (uint64, interface{}, error) {
|
||||||
// Set default DC
|
// Setup the request
|
||||||
dc := s.agent.config.Datacenter
|
args := structs.DCSpecificRequest{}
|
||||||
|
if done := s.parse(resp, req, &args.Datacenter, &args.BlockingQuery); done {
|
||||||
// Check for other DC
|
return 0, nil, nil
|
||||||
if other := req.URL.Query().Get("dc"); other != "" {
|
|
||||||
dc = other
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var out structs.Nodes
|
var out structs.IndexedNodes
|
||||||
if err := s.agent.RPC("Catalog.ListNodes", dc, &out); err != nil {
|
if err := s.agent.RPC("Catalog.ListNodes", &args, &out); err != nil {
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out.Index, out.Nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTTPServer) CatalogServices(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
func (s *HTTPServer) CatalogServices(resp http.ResponseWriter, req *http.Request) (uint64, interface{}, error) {
|
||||||
// Set default DC
|
// Set default DC
|
||||||
dc := s.agent.config.Datacenter
|
args := structs.DCSpecificRequest{}
|
||||||
|
if done := s.parse(resp, req, &args.Datacenter, &args.BlockingQuery); done {
|
||||||
// Check for other DC
|
return 0, nil, nil
|
||||||
if other := req.URL.Query().Get("dc"); other != "" {
|
|
||||||
dc = other
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var out structs.Services
|
var out structs.IndexedServices
|
||||||
if err := s.agent.RPC("Catalog.ListServices", dc, &out); err != nil {
|
if err := s.agent.RPC("Catalog.ListServices", &args, &out); err != nil {
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out.Index, out.Services, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTTPServer) CatalogServiceNodes(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
func (s *HTTPServer) CatalogServiceNodes(resp http.ResponseWriter, req *http.Request) (uint64, interface{}, error) {
|
||||||
// Set default DC
|
// Set default DC
|
||||||
args := structs.ServiceSpecificRequest{
|
args := structs.ServiceSpecificRequest{}
|
||||||
Datacenter: s.agent.config.Datacenter,
|
if done := s.parse(resp, req, &args.Datacenter, &args.BlockingQuery); done {
|
||||||
}
|
return 0, nil, nil
|
||||||
|
|
||||||
// Check for other DC
|
|
||||||
params := req.URL.Query()
|
|
||||||
if other := params.Get("dc"); other != "" {
|
|
||||||
args.Datacenter = other
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a tag
|
// Check for a tag
|
||||||
|
params := req.URL.Query()
|
||||||
if _, ok := params["tag"]; ok {
|
if _, ok := params["tag"]; ok {
|
||||||
args.ServiceTag = params.Get("tag")
|
args.ServiceTag = params.Get("tag")
|
||||||
args.TagFilter = true
|
args.TagFilter = true
|
||||||
|
@ -112,27 +104,22 @@ func (s *HTTPServer) CatalogServiceNodes(resp http.ResponseWriter, req *http.Req
|
||||||
if args.ServiceName == "" {
|
if args.ServiceName == "" {
|
||||||
resp.WriteHeader(400)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte("Missing service name"))
|
resp.Write([]byte("Missing service name"))
|
||||||
return nil, nil
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the RPC request
|
// Make the RPC request
|
||||||
var out structs.ServiceNodes
|
var out structs.IndexedServiceNodes
|
||||||
if err := s.agent.RPC("Catalog.ServiceNodes", &args, &out); err != nil {
|
if err := s.agent.RPC("Catalog.ServiceNodes", &args, &out); err != nil {
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out.Index, out.ServiceNodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTTPServer) CatalogNodeServices(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
func (s *HTTPServer) CatalogNodeServices(resp http.ResponseWriter, req *http.Request) (uint64, interface{}, error) {
|
||||||
// Set default Datacenter
|
// Set default Datacenter
|
||||||
args := structs.NodeSpecificRequest{
|
args := structs.NodeSpecificRequest{}
|
||||||
Datacenter: s.agent.config.Datacenter,
|
if done := s.parse(resp, req, &args.Datacenter, &args.BlockingQuery); done {
|
||||||
}
|
return 0, nil, nil
|
||||||
|
|
||||||
// Check for other DC
|
|
||||||
params := req.URL.Query()
|
|
||||||
if other := params.Get("dc"); other != "" {
|
|
||||||
args.Datacenter = other
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull out the node name
|
// Pull out the node name
|
||||||
|
@ -140,13 +127,13 @@ func (s *HTTPServer) CatalogNodeServices(resp http.ResponseWriter, req *http.Req
|
||||||
if args.Node == "" {
|
if args.Node == "" {
|
||||||
resp.WriteHeader(400)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte("Missing node name"))
|
resp.Write([]byte("Missing node name"))
|
||||||
return nil, nil
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the RPC request
|
// Make the RPC request
|
||||||
out := new(structs.NodeServices)
|
var out structs.IndexedNodeServices
|
||||||
if err := s.agent.RPC("Catalog.NodeServices", &args, out); err != nil {
|
if err := s.agent.RPC("Catalog.NodeServices", &args, &out); err != nil {
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out.Index, out.NodeServices, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,11 +114,15 @@ func TestCatalogNodes(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := srv.CatalogNodes(nil, req)
|
idx, obj, err := srv.CatalogNodes(nil, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
|
||||||
nodes := obj.(structs.Nodes)
|
nodes := obj.(structs.Nodes)
|
||||||
if len(nodes) != 2 {
|
if len(nodes) != 2 {
|
||||||
t.Fatalf("bad: %v", obj)
|
t.Fatalf("bad: %v", obj)
|
||||||
|
@ -153,11 +157,15 @@ func TestCatalogServices(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := srv.CatalogServices(nil, req)
|
idx, obj, err := srv.CatalogServices(nil, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
|
||||||
services := obj.(structs.Services)
|
services := obj.(structs.Services)
|
||||||
if len(services) != 2 {
|
if len(services) != 2 {
|
||||||
t.Fatalf("bad: %v", obj)
|
t.Fatalf("bad: %v", obj)
|
||||||
|
@ -193,11 +201,15 @@ func TestCatalogServiceNodes(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := srv.CatalogServiceNodes(nil, req)
|
idx, obj, err := srv.CatalogServiceNodes(nil, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
|
||||||
nodes := obj.(structs.ServiceNodes)
|
nodes := obj.(structs.ServiceNodes)
|
||||||
if len(nodes) != 1 {
|
if len(nodes) != 1 {
|
||||||
t.Fatalf("bad: %v", obj)
|
t.Fatalf("bad: %v", obj)
|
||||||
|
@ -233,11 +245,15 @@ func TestCatalogNodeServices(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := srv.CatalogNodeServices(nil, req)
|
idx, obj, err := srv.CatalogNodeServices(nil, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
|
||||||
services := obj.(*structs.NodeServices)
|
services := obj.(*structs.NodeServices)
|
||||||
if len(services.Services) != 1 {
|
if len(services.Services) != 1 {
|
||||||
t.Fatalf("bad: %v", obj)
|
t.Fatalf("bad: %v", obj)
|
||||||
|
|
|
@ -257,7 +257,7 @@ func (d *DNSServer) nodeLookup(datacenter, node string, req, resp *dns.Msg) {
|
||||||
Datacenter: datacenter,
|
Datacenter: datacenter,
|
||||||
Node: node,
|
Node: node,
|
||||||
}
|
}
|
||||||
var out structs.NodeServices
|
var out structs.IndexedNodeServices
|
||||||
if err := d.agent.RPC("Catalog.NodeServices", &args, &out); err != nil {
|
if err := d.agent.RPC("Catalog.NodeServices", &args, &out); err != nil {
|
||||||
d.logger.Printf("[ERR] dns: rpc error: %v", err)
|
d.logger.Printf("[ERR] dns: rpc error: %v", err)
|
||||||
resp.SetRcode(req, dns.RcodeServerFailure)
|
resp.SetRcode(req, dns.RcodeServerFailure)
|
||||||
|
@ -265,15 +265,15 @@ func (d *DNSServer) nodeLookup(datacenter, node string, req, resp *dns.Msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have no address, return not found!
|
// If we have no address, return not found!
|
||||||
if out.Node.Address == "" {
|
if out.NodeServices.Node.Address == "" {
|
||||||
resp.SetRcode(req, dns.RcodeNameError)
|
resp.SetRcode(req, dns.RcodeNameError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the IP
|
// Parse the IP
|
||||||
ip := net.ParseIP(out.Node.Address)
|
ip := net.ParseIP(out.NodeServices.Node.Address)
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
d.logger.Printf("[ERR] dns: failed to parse IP %v", out.Node)
|
d.logger.Printf("[ERR] dns: failed to parse IP %v", out.NodeServices.Node)
|
||||||
resp.SetRcode(req, dns.RcodeServerFailure)
|
resp.SetRcode(req, dns.RcodeServerFailure)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,7 @@ func (d *DNSServer) serviceLookup(datacenter, service, tag string, req, resp *dn
|
||||||
ServiceTag: tag,
|
ServiceTag: tag,
|
||||||
TagFilter: tag != "",
|
TagFilter: tag != "",
|
||||||
}
|
}
|
||||||
var out structs.CheckServiceNodes
|
var out structs.IndexedCheckServiceNodes
|
||||||
if err := d.agent.RPC("Health.ServiceNodes", &args, &out); err != nil {
|
if err := d.agent.RPC("Health.ServiceNodes", &args, &out); err != nil {
|
||||||
d.logger.Printf("[ERR] dns: rpc error: %v", err)
|
d.logger.Printf("[ERR] dns: rpc error: %v", err)
|
||||||
resp.SetRcode(req, dns.RcodeServerFailure)
|
resp.SetRcode(req, dns.RcodeServerFailure)
|
||||||
|
@ -310,21 +310,21 @@ func (d *DNSServer) serviceLookup(datacenter, service, tag string, req, resp *dn
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have no nodes, return not found!
|
// If we have no nodes, return not found!
|
||||||
if len(out) == 0 {
|
if len(out.Nodes) == 0 {
|
||||||
resp.SetRcode(req, dns.RcodeNameError)
|
resp.SetRcode(req, dns.RcodeNameError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out any service nodes due to health checks
|
// Filter out any service nodes due to health checks
|
||||||
out = d.filterServiceNodes(out)
|
out.Nodes = d.filterServiceNodes(out.Nodes)
|
||||||
|
|
||||||
// Add various responses depending on the request
|
// Add various responses depending on the request
|
||||||
qType := req.Question[0].Qtype
|
qType := req.Question[0].Qtype
|
||||||
if qType == dns.TypeANY || qType == dns.TypeA {
|
if qType == dns.TypeANY || qType == dns.TypeA {
|
||||||
d.serviceARecords(out, req, resp)
|
d.serviceARecords(out.Nodes, req, resp)
|
||||||
}
|
}
|
||||||
if qType == dns.TypeANY || qType == dns.TypeSRV {
|
if qType == dns.TypeANY || qType == dns.TypeSRV {
|
||||||
d.serviceSRVRecords(datacenter, out, req, resp)
|
d.serviceSRVRecords(datacenter, out.Nodes, req, resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,16 +6,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *HTTPServer) HealthChecksInState(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
func (s *HTTPServer) HealthChecksInState(resp http.ResponseWriter, req *http.Request) (uint64, interface{}, error) {
|
||||||
// Set default DC
|
// Set default DC
|
||||||
args := structs.ChecksInStateRequest{
|
args := structs.ChecksInStateRequest{}
|
||||||
Datacenter: s.agent.config.Datacenter,
|
if done := s.parse(resp, req, &args.Datacenter, &args.BlockingQuery); done {
|
||||||
}
|
return 0, nil, nil
|
||||||
|
|
||||||
// Check for other DC
|
|
||||||
params := req.URL.Query()
|
|
||||||
if other := params.Get("dc"); other != "" {
|
|
||||||
args.Datacenter = other
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull out the service name
|
// Pull out the service name
|
||||||
|
@ -23,27 +18,22 @@ func (s *HTTPServer) HealthChecksInState(resp http.ResponseWriter, req *http.Req
|
||||||
if args.State == "" {
|
if args.State == "" {
|
||||||
resp.WriteHeader(400)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte("Missing check state"))
|
resp.Write([]byte("Missing check state"))
|
||||||
return nil, nil
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the RPC request
|
// Make the RPC request
|
||||||
var out structs.HealthChecks
|
var out structs.IndexedHealthChecks
|
||||||
if err := s.agent.RPC("Health.ChecksInState", &args, &out); err != nil {
|
if err := s.agent.RPC("Health.ChecksInState", &args, &out); err != nil {
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out.Index, out.HealthChecks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTTPServer) HealthNodeChecks(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
func (s *HTTPServer) HealthNodeChecks(resp http.ResponseWriter, req *http.Request) (uint64, interface{}, error) {
|
||||||
// Set default DC
|
// Set default DC
|
||||||
args := structs.NodeSpecificRequest{
|
args := structs.NodeSpecificRequest{}
|
||||||
Datacenter: s.agent.config.Datacenter,
|
if done := s.parse(resp, req, &args.Datacenter, &args.BlockingQuery); done {
|
||||||
}
|
return 0, nil, nil
|
||||||
|
|
||||||
// Check for other DC
|
|
||||||
params := req.URL.Query()
|
|
||||||
if other := params.Get("dc"); other != "" {
|
|
||||||
args.Datacenter = other
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull out the service name
|
// Pull out the service name
|
||||||
|
@ -51,27 +41,22 @@ func (s *HTTPServer) HealthNodeChecks(resp http.ResponseWriter, req *http.Reques
|
||||||
if args.Node == "" {
|
if args.Node == "" {
|
||||||
resp.WriteHeader(400)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte("Missing node name"))
|
resp.Write([]byte("Missing node name"))
|
||||||
return nil, nil
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the RPC request
|
// Make the RPC request
|
||||||
var out structs.HealthChecks
|
var out structs.IndexedHealthChecks
|
||||||
if err := s.agent.RPC("Health.NodeChecks", &args, &out); err != nil {
|
if err := s.agent.RPC("Health.NodeChecks", &args, &out); err != nil {
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out.Index, out.HealthChecks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTTPServer) HealthServiceChecks(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
func (s *HTTPServer) HealthServiceChecks(resp http.ResponseWriter, req *http.Request) (uint64, interface{}, error) {
|
||||||
// Set default DC
|
// Set default DC
|
||||||
args := structs.ServiceSpecificRequest{
|
args := structs.ServiceSpecificRequest{}
|
||||||
Datacenter: s.agent.config.Datacenter,
|
if done := s.parse(resp, req, &args.Datacenter, &args.BlockingQuery); done {
|
||||||
}
|
return 0, nil, nil
|
||||||
|
|
||||||
// Check for other DC
|
|
||||||
params := req.URL.Query()
|
|
||||||
if other := params.Get("dc"); other != "" {
|
|
||||||
args.Datacenter = other
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull out the service name
|
// Pull out the service name
|
||||||
|
@ -79,30 +64,26 @@ func (s *HTTPServer) HealthServiceChecks(resp http.ResponseWriter, req *http.Req
|
||||||
if args.ServiceName == "" {
|
if args.ServiceName == "" {
|
||||||
resp.WriteHeader(400)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte("Missing service name"))
|
resp.Write([]byte("Missing service name"))
|
||||||
return nil, nil
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the RPC request
|
// Make the RPC request
|
||||||
var out structs.HealthChecks
|
var out structs.IndexedHealthChecks
|
||||||
if err := s.agent.RPC("Health.ServiceChecks", &args, &out); err != nil {
|
if err := s.agent.RPC("Health.ServiceChecks", &args, &out); err != nil {
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out.Index, out.HealthChecks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTTPServer) HealthServiceNodes(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
func (s *HTTPServer) HealthServiceNodes(resp http.ResponseWriter, req *http.Request) (uint64, interface{}, error) {
|
||||||
// Set default DC
|
// Set default DC
|
||||||
args := structs.ServiceSpecificRequest{
|
args := structs.ServiceSpecificRequest{}
|
||||||
Datacenter: s.agent.config.Datacenter,
|
if done := s.parse(resp, req, &args.Datacenter, &args.BlockingQuery); done {
|
||||||
}
|
return 0, nil, nil
|
||||||
|
|
||||||
// Check for other DC
|
|
||||||
params := req.URL.Query()
|
|
||||||
if other := params.Get("dc"); other != "" {
|
|
||||||
args.Datacenter = other
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a tag
|
// Check for a tag
|
||||||
|
params := req.URL.Query()
|
||||||
if _, ok := params["tag"]; ok {
|
if _, ok := params["tag"]; ok {
|
||||||
args.ServiceTag = params.Get("tag")
|
args.ServiceTag = params.Get("tag")
|
||||||
args.TagFilter = true
|
args.TagFilter = true
|
||||||
|
@ -113,13 +94,13 @@ func (s *HTTPServer) HealthServiceNodes(resp http.ResponseWriter, req *http.Requ
|
||||||
if args.ServiceName == "" {
|
if args.ServiceName == "" {
|
||||||
resp.WriteHeader(400)
|
resp.WriteHeader(400)
|
||||||
resp.Write([]byte("Missing service name"))
|
resp.Write([]byte("Missing service name"))
|
||||||
return nil, nil
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the RPC request
|
// Make the RPC request
|
||||||
var out structs.CheckServiceNodes
|
var out structs.IndexedCheckServiceNodes
|
||||||
if err := s.agent.RPC("Health.ServiceNodes", &args, &out); err != nil {
|
if err := s.agent.RPC("Health.ServiceNodes", &args, &out); err != nil {
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out.Index, out.Nodes, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,15 @@ func TestHealthChecksInState(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := srv.HealthChecksInState(nil, req)
|
idx, obj, err := srv.HealthChecksInState(nil, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
|
||||||
// Should be 1 health check for the server
|
// Should be 1 health check for the server
|
||||||
nodes := obj.(structs.HealthChecks)
|
nodes := obj.(structs.HealthChecks)
|
||||||
if len(nodes) != 1 {
|
if len(nodes) != 1 {
|
||||||
|
@ -50,11 +54,15 @@ func TestHealthNodeChecks(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := srv.HealthNodeChecks(nil, req)
|
idx, obj, err := srv.HealthNodeChecks(nil, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
|
||||||
// Should be 1 health check for the server
|
// Should be 1 health check for the server
|
||||||
nodes := obj.(structs.HealthChecks)
|
nodes := obj.(structs.HealthChecks)
|
||||||
if len(nodes) != 1 {
|
if len(nodes) != 1 {
|
||||||
|
@ -92,11 +100,15 @@ func TestHealthServiceChecks(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := srv.HealthServiceChecks(nil, req)
|
idx, obj, err := srv.HealthServiceChecks(nil, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
|
||||||
// Should be 1 health check for consul
|
// Should be 1 health check for consul
|
||||||
nodes := obj.(structs.HealthChecks)
|
nodes := obj.(structs.HealthChecks)
|
||||||
if len(nodes) != 1 {
|
if len(nodes) != 1 {
|
||||||
|
@ -118,11 +130,15 @@ func TestHealthServiceNodes(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := srv.HealthServiceNodes(nil, req)
|
idx, obj, err := srv.HealthServiceNodes(nil, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
|
||||||
// Should be 1 health check for consul
|
// Should be 1 health check for consul
|
||||||
nodes := obj.(structs.CheckServiceNodes)
|
nodes := obj.(structs.CheckServiceNodes)
|
||||||
if len(nodes) != 1 {
|
if len(nodes) != 1 {
|
||||||
|
|
|
@ -3,10 +3,12 @@ package agent
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/hashicorp/consul/consul/structs"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,15 +62,15 @@ func (s *HTTPServer) registerHandlers() {
|
||||||
s.mux.HandleFunc("/v1/catalog/register", s.wrap(s.CatalogRegister))
|
s.mux.HandleFunc("/v1/catalog/register", s.wrap(s.CatalogRegister))
|
||||||
s.mux.HandleFunc("/v1/catalog/deregister", s.wrap(s.CatalogDeregister))
|
s.mux.HandleFunc("/v1/catalog/deregister", s.wrap(s.CatalogDeregister))
|
||||||
s.mux.HandleFunc("/v1/catalog/datacenters", s.wrap(s.CatalogDatacenters))
|
s.mux.HandleFunc("/v1/catalog/datacenters", s.wrap(s.CatalogDatacenters))
|
||||||
s.mux.HandleFunc("/v1/catalog/nodes", s.wrap(s.CatalogNodes))
|
s.mux.HandleFunc("/v1/catalog/nodes", s.wrapQuery(s.CatalogNodes))
|
||||||
s.mux.HandleFunc("/v1/catalog/services", s.wrap(s.CatalogServices))
|
s.mux.HandleFunc("/v1/catalog/services", s.wrapQuery(s.CatalogServices))
|
||||||
s.mux.HandleFunc("/v1/catalog/service/", s.wrap(s.CatalogServiceNodes))
|
s.mux.HandleFunc("/v1/catalog/service/", s.wrapQuery(s.CatalogServiceNodes))
|
||||||
s.mux.HandleFunc("/v1/catalog/node/", s.wrap(s.CatalogNodeServices))
|
s.mux.HandleFunc("/v1/catalog/node/", s.wrapQuery(s.CatalogNodeServices))
|
||||||
|
|
||||||
s.mux.HandleFunc("/v1/health/node/", s.wrap(s.HealthNodeChecks))
|
s.mux.HandleFunc("/v1/health/node/", s.wrapQuery(s.HealthNodeChecks))
|
||||||
s.mux.HandleFunc("/v1/health/checks/", s.wrap(s.HealthServiceChecks))
|
s.mux.HandleFunc("/v1/health/checks/", s.wrapQuery(s.HealthServiceChecks))
|
||||||
s.mux.HandleFunc("/v1/health/state/", s.wrap(s.HealthChecksInState))
|
s.mux.HandleFunc("/v1/health/state/", s.wrapQuery(s.HealthChecksInState))
|
||||||
s.mux.HandleFunc("/v1/health/service/", s.wrap(s.HealthServiceNodes))
|
s.mux.HandleFunc("/v1/health/service/", s.wrapQuery(s.HealthServiceNodes))
|
||||||
|
|
||||||
s.mux.HandleFunc("/v1/agent/services", s.wrap(s.AgentServices))
|
s.mux.HandleFunc("/v1/agent/services", s.wrap(s.AgentServices))
|
||||||
s.mux.HandleFunc("/v1/agent/checks", s.wrap(s.AgentChecks))
|
s.mux.HandleFunc("/v1/agent/checks", s.wrap(s.AgentChecks))
|
||||||
|
@ -118,6 +120,16 @@ func (s *HTTPServer) wrap(handler func(resp http.ResponseWriter, req *http.Reque
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapQuery is used to wrap query functions to make them more convenient
|
||||||
|
func (s *HTTPServer) wrapQuery(handler func(resp http.ResponseWriter, req *http.Request) (uint64, interface{}, error)) func(resp http.ResponseWriter, req *http.Request) {
|
||||||
|
f := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||||
|
idx, obj, err := handler(resp, req)
|
||||||
|
setIndex(resp, idx)
|
||||||
|
return obj, err
|
||||||
|
}
|
||||||
|
return s.wrap(f)
|
||||||
|
}
|
||||||
|
|
||||||
// Renders a simple index page
|
// Renders a simple index page
|
||||||
func (s *HTTPServer) Index(resp http.ResponseWriter, req *http.Request) {
|
func (s *HTTPServer) Index(resp http.ResponseWriter, req *http.Request) {
|
||||||
if req.URL.Path == "/" {
|
if req.URL.Path == "/" {
|
||||||
|
@ -132,3 +144,49 @@ func decodeBody(req *http.Request, out interface{}) error {
|
||||||
dec := json.NewDecoder(req.Body)
|
dec := json.NewDecoder(req.Body)
|
||||||
return dec.Decode(out)
|
return dec.Decode(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setIndex is used to set the index response header
|
||||||
|
func setIndex(resp http.ResponseWriter, index uint64) {
|
||||||
|
resp.Header().Add("X-Consul-Index", strconv.FormatUint(index, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseWait is used to parse the ?wait and ?index query params
|
||||||
|
// Returns true on error
|
||||||
|
func parseWait(resp http.ResponseWriter, req *http.Request, b *structs.BlockingQuery) bool {
|
||||||
|
query := req.URL.Query()
|
||||||
|
if wait := query.Get("wait"); wait != "" {
|
||||||
|
dur, err := time.ParseDuration(wait)
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeader(400)
|
||||||
|
resp.Write([]byte("Invalid wait time"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
b.MaxQueryTime = dur
|
||||||
|
}
|
||||||
|
if idx := query.Get("index"); idx != "" {
|
||||||
|
index, err := strconv.ParseUint(idx, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeader(400)
|
||||||
|
resp.Write([]byte("Invalid index"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
b.MinQueryIndex = index
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseDC is used to parse the ?dc query param
|
||||||
|
func (s *HTTPServer) parseDC(req *http.Request, dc *string) {
|
||||||
|
if other := req.URL.Query().Get("dc"); other != "" {
|
||||||
|
*dc = other
|
||||||
|
} else if *dc == "" {
|
||||||
|
*dc = s.agent.config.Datacenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse is a convenience method for endpoints that need
|
||||||
|
// to use both parseWait and parseDC.
|
||||||
|
func (s *HTTPServer) parse(resp http.ResponseWriter, req *http.Request, dc *string, b *structs.BlockingQuery) bool {
|
||||||
|
s.parseDC(req, dc)
|
||||||
|
return parseWait(resp, req, b)
|
||||||
|
}
|
||||||
|
|
|
@ -216,14 +216,16 @@ func (l *localState) setSyncState() error {
|
||||||
Datacenter: l.config.Datacenter,
|
Datacenter: l.config.Datacenter,
|
||||||
Node: l.config.NodeName,
|
Node: l.config.NodeName,
|
||||||
}
|
}
|
||||||
var services structs.NodeServices
|
var out1 structs.IndexedNodeServices
|
||||||
var checks structs.HealthChecks
|
var out2 structs.IndexedHealthChecks
|
||||||
if e := l.iface.RPC("Catalog.NodeServices", &req, &services); e != nil {
|
if e := l.iface.RPC("Catalog.NodeServices", &req, &out1); e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
if err := l.iface.RPC("Health.NodeChecks", &req, &checks); err != nil {
|
if err := l.iface.RPC("Health.NodeChecks", &req, &out2); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
services := out1.NodeServices
|
||||||
|
checks := out2.HealthChecks
|
||||||
|
|
||||||
l.Lock()
|
l.Lock()
|
||||||
defer l.Unlock()
|
defer l.Unlock()
|
||||||
|
|
|
@ -85,18 +85,18 @@ func TestAgentAntiEntropy_Services(t *testing.T) {
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
Node: agent.config.NodeName,
|
Node: agent.config.NodeName,
|
||||||
}
|
}
|
||||||
var services structs.NodeServices
|
var services structs.IndexedNodeServices
|
||||||
if err := agent.RPC("Catalog.NodeServices", &req, &services); err != nil {
|
if err := agent.RPC("Catalog.NodeServices", &req, &services); err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should have 4 services (consul included)
|
// We should have 4 services (consul included)
|
||||||
if len(services.Services) != 4 {
|
if len(services.NodeServices.Services) != 4 {
|
||||||
t.Fatalf("bad: %v", services.Services)
|
t.Fatalf("bad: %v", services.NodeServices.Services)
|
||||||
}
|
}
|
||||||
|
|
||||||
// All the services should match
|
// All the services should match
|
||||||
for id, serv := range services.Services {
|
for id, serv := range services.NodeServices.Services {
|
||||||
switch id {
|
switch id {
|
||||||
case "mysql":
|
case "mysql":
|
||||||
if !reflect.DeepEqual(serv, srv1) {
|
if !reflect.DeepEqual(serv, srv1) {
|
||||||
|
@ -208,18 +208,18 @@ func TestAgentAntiEntropy_Checks(t *testing.T) {
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
Node: agent.config.NodeName,
|
Node: agent.config.NodeName,
|
||||||
}
|
}
|
||||||
var checks structs.HealthChecks
|
var checks structs.IndexedHealthChecks
|
||||||
if err := agent.RPC("Health.NodeChecks", &req, &checks); err != nil {
|
if err := agent.RPC("Health.NodeChecks", &req, &checks); err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should have 4 services (serf included)
|
// We should have 4 services (serf included)
|
||||||
if len(checks) != 4 {
|
if len(checks.HealthChecks) != 4 {
|
||||||
t.Fatalf("bad: %v", checks)
|
t.Fatalf("bad: %v", checks)
|
||||||
}
|
}
|
||||||
|
|
||||||
// All the checks should match
|
// All the checks should match
|
||||||
for _, chk := range checks {
|
for _, chk := range checks.HealthChecks {
|
||||||
switch chk.CheckID {
|
switch chk.CheckID {
|
||||||
case "mysql":
|
case "mysql":
|
||||||
if !reflect.DeepEqual(chk, chk1) {
|
if !reflect.DeepEqual(chk, chk1) {
|
||||||
|
|
Loading…
Reference in New Issue