consul: Adding methods to dump node info
This commit is contained in:
parent
c6b326a362
commit
75f9a126ae
|
@ -241,6 +241,8 @@ func (s *StateStore) initialize() error {
|
|||
"NodeChecks": MDBTables{s.checkTable},
|
||||
"ServiceChecks": MDBTables{s.checkTable},
|
||||
"CheckServiceNodes": MDBTables{s.nodeTable, s.serviceTable, s.checkTable},
|
||||
"NodeInfo": MDBTables{s.nodeTable, s.serviceTable, s.checkTable},
|
||||
"NodeDump": MDBTables{s.nodeTable, s.serviceTable, s.checkTable},
|
||||
"KVSGet": MDBTables{s.kvsTable},
|
||||
"KVSList": MDBTables{s.kvsTable},
|
||||
}
|
||||
|
@ -743,6 +745,99 @@ func (s *StateStore) parseCheckServiceNodes(tx *MDBTxn, res []interface{}, err e
|
|||
return nodes
|
||||
}
|
||||
|
||||
// NodeInfo is used to generate the full info about a node.
|
||||
func (s *StateStore) NodeInfo(node string) (uint64, *structs.NodeInfo) {
|
||||
tables := s.queryTables["NodeInfo"]
|
||||
tx, err := tables.StartTxn(true)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Failed to start txn: %v", err))
|
||||
}
|
||||
defer tx.Abort()
|
||||
|
||||
idx, err := tables.LastIndexTxn(tx)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Failed to get last index: %v", err))
|
||||
}
|
||||
|
||||
res, err := s.nodeTable.GetTxn(tx, "id", node)
|
||||
dump := s.parseNodeInfo(tx, res, err)
|
||||
var n *structs.NodeInfo
|
||||
if len(dump) > 0 {
|
||||
n = dump[0]
|
||||
}
|
||||
return idx, n
|
||||
}
|
||||
|
||||
// NodeDump is used to generate the NodeInfo for all nodes. This is very expensive,
|
||||
// and should generally be avoided for programatic access.
|
||||
func (s *StateStore) NodeDump() (uint64, structs.NodeDump) {
|
||||
tables := s.queryTables["NodeDump"]
|
||||
tx, err := tables.StartTxn(true)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Failed to start txn: %v", err))
|
||||
}
|
||||
defer tx.Abort()
|
||||
|
||||
idx, err := tables.LastIndexTxn(tx)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Failed to get last index: %v", err))
|
||||
}
|
||||
|
||||
res, err := s.nodeTable.GetTxn(tx, "id")
|
||||
return idx, s.parseNodeInfo(tx, res, err)
|
||||
}
|
||||
|
||||
// parseNodeInfo is used to scan over the results of a node
|
||||
// iteration and generate a NodeDump
|
||||
func (s *StateStore) parseNodeInfo(tx *MDBTxn, res []interface{}, err error) structs.NodeDump {
|
||||
dump := make(structs.NodeDump, 0, len(res))
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] consul.state: Failed to get nodes: %v", err)
|
||||
return dump
|
||||
}
|
||||
|
||||
for _, r := range res {
|
||||
// Copy the address and node
|
||||
node := r.(*structs.Node)
|
||||
info := &structs.NodeInfo{
|
||||
Node: node.Node,
|
||||
Address: node.Address,
|
||||
}
|
||||
|
||||
// Get any services of the node
|
||||
res, err = s.serviceTable.GetTxn(tx, "id", node.Node)
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] consul.state: Failed to get node services: %v", err)
|
||||
}
|
||||
info.Services = make([]*structs.NodeService, 0, len(res))
|
||||
for _, r := range res {
|
||||
service := r.(*structs.ServiceNode)
|
||||
srv := &structs.NodeService{
|
||||
ID: service.ServiceID,
|
||||
Service: service.ServiceName,
|
||||
Tags: service.ServiceTags,
|
||||
Port: service.ServicePort,
|
||||
}
|
||||
info.Services = append(info.Services, srv)
|
||||
}
|
||||
|
||||
// Get any checks of the node
|
||||
res, err = s.checkTable.GetTxn(tx, "node", node.Node)
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] consul.state: Failed to get node checks: %v", err)
|
||||
}
|
||||
info.Checks = make([]*structs.HealthCheck, 0, len(res))
|
||||
for _, r := range res {
|
||||
chk := r.(*structs.HealthCheck)
|
||||
info.Checks = append(info.Checks, chk)
|
||||
}
|
||||
|
||||
// Add the node info
|
||||
dump = append(dump, info)
|
||||
}
|
||||
return dump
|
||||
}
|
||||
|
||||
// KVSSet is used to create or update a KV entry
|
||||
func (s *StateStore) KVSSet(index uint64, d *structs.DirEntry) error {
|
||||
// Start a new txn
|
||||
|
|
|
@ -1068,6 +1068,108 @@ func TestSS_Register_Deregister_Query(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNodeInfo(t *testing.T) {
|
||||
store, err := testStateStore()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
defer store.Close()
|
||||
|
||||
if err := store.EnsureNode(1, structs.Node{"foo", "127.0.0.1"}); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, 8000}); err != nil {
|
||||
t.Fatalf("err: %v")
|
||||
}
|
||||
check := &structs.HealthCheck{
|
||||
Node: "foo",
|
||||
CheckID: "db",
|
||||
Name: "Can connect",
|
||||
Status: structs.HealthPassing,
|
||||
ServiceID: "db1",
|
||||
}
|
||||
if err := store.EnsureCheck(3, check); err != nil {
|
||||
t.Fatalf("err: %v")
|
||||
}
|
||||
check = &structs.HealthCheck{
|
||||
Node: "foo",
|
||||
CheckID: SerfCheckID,
|
||||
Name: SerfCheckName,
|
||||
Status: structs.HealthPassing,
|
||||
}
|
||||
if err := store.EnsureCheck(4, check); err != nil {
|
||||
t.Fatalf("err: %v")
|
||||
}
|
||||
|
||||
idx, info := store.NodeInfo("foo")
|
||||
if idx != 4 {
|
||||
t.Fatalf("bad: %v", idx)
|
||||
}
|
||||
if info == nil {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
|
||||
if info.Node != "foo" {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
if info.Services[0].ID != "db1" {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
if len(info.Checks) != 2 {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
if info.Checks[0].CheckID != "db" {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
if info.Checks[1].CheckID != SerfCheckID {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeDump(t *testing.T) {
|
||||
store, err := testStateStore()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
defer store.Close()
|
||||
|
||||
if err := store.EnsureNode(1, structs.Node{"foo", "127.0.0.1"}); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if err := store.EnsureService(2, "foo", &structs.NodeService{"db1", "db", []string{"master"}, 8000}); err != nil {
|
||||
t.Fatalf("err: %v")
|
||||
}
|
||||
if err := store.EnsureNode(3, structs.Node{"baz", "127.0.0.2"}); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if err := store.EnsureService(4, "baz", &structs.NodeService{"db1", "db", []string{"master"}, 8000}); err != nil {
|
||||
t.Fatalf("err: %v")
|
||||
}
|
||||
|
||||
idx, dump := store.NodeDump()
|
||||
if idx != 4 {
|
||||
t.Fatalf("bad: %v", idx)
|
||||
}
|
||||
if len(dump) != 2 {
|
||||
t.Fatalf("Bad: %v", dump)
|
||||
}
|
||||
|
||||
info := dump[0]
|
||||
if info.Node != "baz" {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
if info.Services[0].ID != "db1" {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
info = dump[1]
|
||||
if info.Node != "foo" {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
if info.Services[0].ID != "db1" {
|
||||
t.Fatalf("Bad: %v", info)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKVSSet_Get(t *testing.T) {
|
||||
store, err := testStateStore()
|
||||
if err != nil {
|
||||
|
|
|
@ -220,6 +220,21 @@ type CheckServiceNode struct {
|
|||
}
|
||||
type CheckServiceNodes []CheckServiceNode
|
||||
|
||||
// NodeInfo is used to dump all associated information about
|
||||
// a node. This is currently used for the UI only, as it is
|
||||
// rather expensive to generate.
|
||||
type NodeInfo struct {
|
||||
Node string
|
||||
Address string
|
||||
Services []*NodeService
|
||||
Checks []*HealthCheck
|
||||
}
|
||||
|
||||
// NodeDump is used to dump all the nodes with all their
|
||||
// associated data. This is currently used for the UI only,
|
||||
// as it is rather expensive to generate.
|
||||
type NodeDump []*NodeInfo
|
||||
|
||||
type IndexedNodes struct {
|
||||
Nodes Nodes
|
||||
QueryMeta
|
||||
|
|
Loading…
Reference in New Issue