mirror of https://github.com/hashicorp/consul
consul: Adding methods to dump node info
parent
3fe10ccb57
commit
87eba3da8d
|
@ -241,6 +241,8 @@ func (s *StateStore) initialize() error {
|
||||||
"NodeChecks": MDBTables{s.checkTable},
|
"NodeChecks": MDBTables{s.checkTable},
|
||||||
"ServiceChecks": MDBTables{s.checkTable},
|
"ServiceChecks": MDBTables{s.checkTable},
|
||||||
"CheckServiceNodes": MDBTables{s.nodeTable, s.serviceTable, 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},
|
"KVSGet": MDBTables{s.kvsTable},
|
||||||
"KVSList": MDBTables{s.kvsTable},
|
"KVSList": MDBTables{s.kvsTable},
|
||||||
}
|
}
|
||||||
|
@ -743,6 +745,99 @@ func (s *StateStore) parseCheckServiceNodes(tx *MDBTxn, res []interface{}, err e
|
||||||
return nodes
|
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
|
// KVSSet is used to create or update a KV entry
|
||||||
func (s *StateStore) KVSSet(index uint64, d *structs.DirEntry) error {
|
func (s *StateStore) KVSSet(index uint64, d *structs.DirEntry) error {
|
||||||
// Start a new txn
|
// 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) {
|
func TestKVSSet_Get(t *testing.T) {
|
||||||
store, err := testStateStore()
|
store, err := testStateStore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -220,6 +220,21 @@ type CheckServiceNode struct {
|
||||||
}
|
}
|
||||||
type CheckServiceNodes []CheckServiceNode
|
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 {
|
type IndexedNodes struct {
|
||||||
Nodes Nodes
|
Nodes Nodes
|
||||||
QueryMeta
|
QueryMeta
|
||||||
|
|
Loading…
Reference in New Issue