From cefd35f7dae11f6f8675d3267bbfb5ed63d9c0c1 Mon Sep 17 00:00:00 2001 From: Ingo Oppermann Date: Fri, 14 Jul 2023 11:22:08 +0200 Subject: [PATCH] Refactor cluster.About() data --- Makefile | 2 +- cluster/cluster.go | 142 +++++++++++++++++++++---------- cluster/node/node.go | 85 ++++++++++++++++-- cluster/proxy/node.go | 1 + cluster/raft/raft.go | 15 +++- docs/docs.go | 91 +++++++++++--------- docs/swagger.json | 91 +++++++++++--------- docs/swagger.yaml | 65 +++++++------- http/api/cluster.go | 76 +++++++---------- http/handler/api/cluster.go | 76 ++++++++++++----- http/handler/api/cluster_node.go | 37 +++----- 11 files changed, 431 insertions(+), 250 deletions(-) diff --git a/Makefile b/Makefile index 06df56cf..b429a601 100644 --- a/Makefile +++ b/Makefile @@ -90,7 +90,7 @@ coverage: go tool cover -html=test/cover.out -o test/cover.html ## commit: Prepare code for commit (vet, fmt, test) -commit: vet fmt lint test build +commit: vet fmt lint test vulncheck build @echo "No errors found. Ready for a commit." ## release: Build a release binary of core diff --git a/cluster/cluster.go b/cluster/cluster.go index ed2eb0ad..a536b499 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -1301,34 +1301,59 @@ func (c *cluster) applyCommand(cmd *store.Command) error { return nil } -type ClusterRaftServer struct { - ID string - Address string - Voter bool - Leader bool -} - -type ClusterRaftStats struct { +type ClusterRaft struct { + Address string State string LastContact time.Duration NumPeers uint64 + LogTerm uint64 + LogIndex uint64 } -type ClusterRaft struct { - Server []ClusterRaftServer - Stats ClusterRaftStats +type ClusterNodeResources struct { + IsThrottling bool // Whether this core is currently throttling + NCPU float64 // Number of CPU on this node + CPU float64 // Current CPU load, 0-100*ncpu + CPULimit float64 // Defined CPU load limit, 0-100*ncpu + Mem uint64 // Currently used memory in bytes + MemLimit uint64 // Defined memory limit in bytes +} + +type ClusterNode struct { + ID string + Name string + Version string + Status string + Error error + Voter bool + Leader bool + Address string + CreatedAt time.Time + Uptime time.Duration + LastContact time.Duration + Latency time.Duration + Core ClusterNodeCore + Resources ClusterNodeResources +} + +type ClusterNodeCore struct { + Address string + Status string + Error error + LastContact time.Duration + Latency time.Duration } type ClusterAbout struct { - ID string - Address string - ClusterAPIAddress string - CoreAPIAddress string - Raft ClusterRaft - Nodes []proxy.NodeAbout - Version ClusterVersion - Degraded bool - DegradedErr error + ID string + Name string + Leader bool + Address string + Raft ClusterRaft + Nodes []ClusterNode + Version ClusterVersion + Degraded bool + DegradedErr error } func (c *cluster) About() (ClusterAbout, error) { @@ -1336,48 +1361,79 @@ func (c *cluster) About() (ClusterAbout, error) { about := ClusterAbout{ ID: c.id, - Address: c.Address(), Degraded: degraded, DegradedErr: degradedErr, + Version: Version, } if address, err := c.ClusterAPIAddress(""); err == nil { - about.ClusterAPIAddress = address - } - - if address, err := c.CoreAPIAddress(""); err == nil { - about.CoreAPIAddress = address + about.Address = address } stats := c.raft.Stats() - about.Raft.Stats.State = stats.State - about.Raft.Stats.LastContact = stats.LastContact - about.Raft.Stats.NumPeers = stats.NumPeers + about.Raft.Address = stats.Address + about.Raft.State = stats.State + about.Raft.LastContact = stats.LastContact + about.Raft.NumPeers = stats.NumPeers + about.Raft.LogIndex = stats.LogIndex + about.Raft.LogTerm = stats.LogTerm servers, err := c.raft.Servers() if err != nil { - c.logger.Error().WithError(err).Log("Raft configuration") - return ClusterAbout{}, err + c.logger.Warn().WithError(err).Log("Raft configuration") } - for _, server := range servers { - node := ClusterRaftServer{ - ID: server.ID, - Address: server.Address, - Voter: server.Voter, - Leader: server.Leader, + serversMap := map[string]raft.Server{} + + for _, s := range servers { + serversMap[s.ID] = s + } + + c.nodesLock.Lock() + for id, node := range c.nodes { + nodeAbout := node.About() + + node := ClusterNode{ + ID: id, + Name: nodeAbout.Name, + Version: nodeAbout.Version, + Status: nodeAbout.Status, + Error: nodeAbout.Error, + Address: nodeAbout.Address, + LastContact: nodeAbout.LastContact, + Latency: nodeAbout.Latency, + CreatedAt: nodeAbout.Core.CreatedAt, + Uptime: nodeAbout.Core.Uptime, + Core: ClusterNodeCore{ + Address: nodeAbout.Core.Address, + Status: nodeAbout.Core.Status, + Error: nodeAbout.Core.Error, + LastContact: nodeAbout.Core.LastContact, + Latency: nodeAbout.Core.Latency, + }, + Resources: ClusterNodeResources{ + IsThrottling: nodeAbout.Resources.IsThrottling, + NCPU: nodeAbout.Resources.NCPU, + CPU: nodeAbout.Resources.CPU, + CPULimit: nodeAbout.Resources.CPULimit, + Mem: nodeAbout.Resources.Mem, + MemLimit: nodeAbout.Resources.MemLimit, + }, } - about.Raft.Server = append(about.Raft.Server, node) - } + if id == c.id { + about.Name = nodeAbout.Name + } - about.Version = Version + if s, ok := serversMap[id]; ok { + node.Voter = s.Voter + node.Leader = s.Leader + } - nodes := c.ProxyReader().ListNodes() - for _, node := range nodes { - about.Nodes = append(about.Nodes, node.About()) + about.Nodes = append(about.Nodes, node) } + c.nodesLock.Unlock() return about, nil } diff --git a/cluster/node/node.go b/cluster/node/node.go index 847b6914..e650292b 100644 --- a/cluster/node/node.go +++ b/cluster/node/node.go @@ -16,6 +16,7 @@ import ( type Node interface { Stop() error + About() About Version() string IPs() []string Status() (string, error) @@ -42,7 +43,7 @@ type node struct { lastContactErr error lastCoreContact time.Time lastCoreContactErr error - latency time.Duration + latency float64 pingLock sync.RWMutex runLock sync.Mutex @@ -96,8 +97,9 @@ func (n *node) start(id string) error { address, config, err := n.CoreEssentials() n.proxyNode = proxy.NewNode(id, address, config) + n.lastCoreContactErr = err + if err != nil { - n.lastCoreContactErr = err go func(ctx context.Context) { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() @@ -143,6 +145,74 @@ func (n *node) Stop() error { return nil } +var maxLastContact time.Duration = 5 * time.Second + +type AboutCore struct { + Address string + State string + StateError error + Status string + Error error + CreatedAt time.Time + Uptime time.Duration + LastContact time.Duration + Latency time.Duration +} + +type About struct { + ID string + Name string + Version string + Address string + Status string + LastContact time.Duration + Latency time.Duration + Error error + Core AboutCore + Resources proxy.NodeResources +} + +func (n *node) About() About { + a := About{ + ID: n.id, + Version: n.Version(), + Address: n.address, + } + + n.pingLock.RLock() + a.LastContact = time.Since(n.lastContact) + if a.LastContact > maxLastContact { + a.Status = "offline" + } else { + a.Status = "online" + } + a.Latency = time.Duration(n.latency * float64(time.Second)) + a.Error = n.lastContactErr + + coreError := n.lastCoreContactErr + n.pingLock.RUnlock() + + about := n.CoreAbout() + + a.Name = about.Name + a.Core.Address = about.Address + a.Core.State = about.State + a.Core.StateError = about.Error + a.Core.CreatedAt = about.CreatedAt + a.Core.Uptime = about.Uptime + a.Core.LastContact = time.Since(about.LastContact) + if a.Core.LastContact > maxLastContact { + a.Core.Status = "offline" + } else { + a.Core.Status = "online" + } + a.Core.Error = coreError + a.Core.Latency = about.Latency + a.Resources = about.Resources + + return a +} + func (n *node) Version() string { n.pingLock.RLock() defer n.pingLock.RUnlock() @@ -159,7 +229,7 @@ func (n *node) Status() (string, error) { defer n.pingLock.RUnlock() since := time.Since(n.lastContact) - if since > 5*time.Second { + if since > maxLastContact { return "offline", fmt.Errorf("the cluster API didn't respond for %s because: %w", since, n.lastContactErr) } @@ -171,7 +241,7 @@ func (n *node) CoreStatus() (string, error) { defer n.pingLock.RUnlock() since := time.Since(n.lastCoreContact) - if since > 5*time.Second { + if since > maxLastContact { return "offline", fmt.Errorf("the core API didn't respond for %s because: %w", since, n.lastCoreContactErr) } @@ -211,6 +281,10 @@ func (n *node) CoreAPIAddress() (string, error) { return n.client.CoreAPIAddress() } +func (n *node) CoreAbout() proxy.NodeAbout { + return n.proxyNode.About() +} + func (n *node) Barrier(name string) (bool, error) { return n.client.Barrier(name) } @@ -232,7 +306,8 @@ func (n *node) ping(ctx context.Context) { n.pingLock.Lock() n.version = version n.lastContact = time.Now() - n.latency = time.Since(start) + n.lastContactErr = nil + n.latency = n.latency*0.2 + time.Since(start).Seconds()*0.8 n.pingLock.Unlock() } else { n.pingLock.Lock() diff --git a/cluster/proxy/node.go b/cluster/proxy/node.go index c5c9ac87..95a8eac9 100644 --- a/cluster/proxy/node.go +++ b/cluster/proxy/node.go @@ -541,6 +541,7 @@ func (n *node) About() NodeAbout { Name: about.Name, Address: n.address, State: state.String(), + Error: n.peerErr, CreatedAt: createdAt, Uptime: time.Since(createdAt), LastContact: n.lastContact, diff --git a/cluster/raft/raft.go b/cluster/raft/raft.go index d970b46e..f92bcb98 100644 --- a/cluster/raft/raft.go +++ b/cluster/raft/raft.go @@ -83,9 +83,12 @@ type Server struct { } type Stats struct { + Address string State string LastContact time.Duration NumPeers uint64 + LogTerm uint64 + LogIndex uint64 } type Config struct { @@ -194,7 +197,9 @@ func (r *raft) Servers() ([]Server, error) { } func (r *raft) Stats() Stats { - stats := Stats{} + stats := Stats{ + Address: r.raftAddress, + } s := r.raft.Stats() @@ -219,6 +224,14 @@ func (r *raft) Stats() Stats { stats.NumPeers = x } + if x, err := strconv.ParseUint(s["last_log_term"], 10, 64); err == nil { + stats.LogTerm = x + } + + if x, err := strconv.ParseUint(s["last_log_index"], 10, 64); err == nil { + stats.LogIndex = x + } + return stats } diff --git a/docs/docs.go b/docs/docs.go index 7192b35f..a5d85308 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4437,12 +4437,6 @@ const docTemplate = `{ "address": { "type": "string" }, - "cluster_api_address": { - "type": "string" - }, - "core_api_address": { - "type": "string" - }, "degraded": { "type": "boolean" }, @@ -4452,6 +4446,12 @@ const docTemplate = `{ "id": { "type": "string" }, + "leader": { + "type": "boolean" + }, + "name": { + "type": "string" + }, "nodes": { "type": "array", "items": { @@ -4500,31 +4500,65 @@ const docTemplate = `{ "address": { "type": "string" }, + "core": { + "$ref": "#/definitions/api.ClusterNodeCore" + }, "created_at": { + "description": "RFC 3339", + "type": "string" + }, + "error": { "type": "string" }, "id": { "type": "string" }, - "last_contact": { - "description": "unix timestamp", - "type": "integer" + "last_contact_ms": { + "type": "number" }, "latency_ms": { - "description": "milliseconds", "type": "number" }, + "leader": { + "type": "boolean" + }, "name": { "type": "string" }, "resources": { "$ref": "#/definitions/api.ClusterNodeResources" }, - "state": { + "status": { "type": "string" }, "uptime_seconds": { "type": "integer" + }, + "version": { + "type": "string" + }, + "voter": { + "type": "boolean" + } + } + }, + "api.ClusterNodeCore": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "error": { + "type": "string" + }, + "last_contact_ms": { + "type": "number" + }, + "latency_ms": { + "type": "number" + }, + "status": { + "type": "string" } } }, @@ -4580,43 +4614,20 @@ const docTemplate = `{ } }, "api.ClusterRaft": { - "type": "object", - "properties": { - "server": { - "type": "array", - "items": { - "$ref": "#/definitions/api.ClusterRaftServer" - } - }, - "stats": { - "$ref": "#/definitions/api.ClusterRaftStats" - } - } - }, - "api.ClusterRaftServer": { "type": "object", "properties": { "address": { - "description": "raft address", "type": "string" }, - "id": { - "type": "string" - }, - "leader": { - "type": "boolean" - }, - "voter": { - "type": "boolean" - } - } - }, - "api.ClusterRaftStats": { - "type": "object", - "properties": { "last_contact_ms": { "type": "number" }, + "log_index": { + "type": "integer" + }, + "log_term": { + "type": "integer" + }, "num_peers": { "type": "integer" }, diff --git a/docs/swagger.json b/docs/swagger.json index 53842c4f..3868090e 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4429,12 +4429,6 @@ "address": { "type": "string" }, - "cluster_api_address": { - "type": "string" - }, - "core_api_address": { - "type": "string" - }, "degraded": { "type": "boolean" }, @@ -4444,6 +4438,12 @@ "id": { "type": "string" }, + "leader": { + "type": "boolean" + }, + "name": { + "type": "string" + }, "nodes": { "type": "array", "items": { @@ -4492,31 +4492,65 @@ "address": { "type": "string" }, + "core": { + "$ref": "#/definitions/api.ClusterNodeCore" + }, "created_at": { + "description": "RFC 3339", + "type": "string" + }, + "error": { "type": "string" }, "id": { "type": "string" }, - "last_contact": { - "description": "unix timestamp", - "type": "integer" + "last_contact_ms": { + "type": "number" }, "latency_ms": { - "description": "milliseconds", "type": "number" }, + "leader": { + "type": "boolean" + }, "name": { "type": "string" }, "resources": { "$ref": "#/definitions/api.ClusterNodeResources" }, - "state": { + "status": { "type": "string" }, "uptime_seconds": { "type": "integer" + }, + "version": { + "type": "string" + }, + "voter": { + "type": "boolean" + } + } + }, + "api.ClusterNodeCore": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "error": { + "type": "string" + }, + "last_contact_ms": { + "type": "number" + }, + "latency_ms": { + "type": "number" + }, + "status": { + "type": "string" } } }, @@ -4572,43 +4606,20 @@ } }, "api.ClusterRaft": { - "type": "object", - "properties": { - "server": { - "type": "array", - "items": { - "$ref": "#/definitions/api.ClusterRaftServer" - } - }, - "stats": { - "$ref": "#/definitions/api.ClusterRaftStats" - } - } - }, - "api.ClusterRaftServer": { "type": "object", "properties": { "address": { - "description": "raft address", "type": "string" }, - "id": { - "type": "string" - }, - "leader": { - "type": "boolean" - }, - "voter": { - "type": "boolean" - } - } - }, - "api.ClusterRaftStats": { - "type": "object", - "properties": { "last_contact_ms": { "type": "number" }, + "log_index": { + "type": "integer" + }, + "log_term": { + "type": "integer" + }, "num_peers": { "type": "integer" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 755984b1..7b2c8c87 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -69,16 +69,16 @@ definitions: properties: address: type: string - cluster_api_address: - type: string - core_api_address: - type: string degraded: type: boolean degraded_error: type: string id: type: string + leader: + type: boolean + name: + type: string nodes: items: $ref: '#/definitions/api.ClusterNode' @@ -110,24 +110,46 @@ definitions: properties: address: type: string + core: + $ref: '#/definitions/api.ClusterNodeCore' created_at: + description: RFC 3339 + type: string + error: type: string id: type: string - last_contact: - description: unix timestamp - type: integer - latency_ms: - description: milliseconds + last_contact_ms: type: number + latency_ms: + type: number + leader: + type: boolean name: type: string resources: $ref: '#/definitions/api.ClusterNodeResources' - state: + status: type: string uptime_seconds: type: integer + version: + type: string + voter: + type: boolean + type: object + api.ClusterNodeCore: + properties: + address: + type: string + error: + type: string + last_contact_ms: + type: number + latency_ms: + type: number + status: + type: string type: object api.ClusterNodeFiles: properties: @@ -165,30 +187,15 @@ definitions: type: string type: object api.ClusterRaft: - properties: - server: - items: - $ref: '#/definitions/api.ClusterRaftServer' - type: array - stats: - $ref: '#/definitions/api.ClusterRaftStats' - type: object - api.ClusterRaftServer: properties: address: - description: raft address type: string - id: - type: string - leader: - type: boolean - voter: - type: boolean - type: object - api.ClusterRaftStats: - properties: last_contact_ms: type: number + log_index: + type: integer + log_term: + type: integer num_peers: type: integer state: diff --git a/http/api/cluster.go b/http/api/cluster.go index 28a335da..d4d64301 100644 --- a/http/api/cluster.go +++ b/http/api/cluster.go @@ -3,32 +3,31 @@ package api import ( "encoding/json" "time" - - "github.com/datarhei/core/v16/cluster/proxy" ) type ClusterNode struct { ID string `json:"id"` Name string `json:"name"` + Version string `json:"version"` + Status string `json:"status"` + Error string `json:"error"` + Voter bool `json:"voter"` + Leader bool `json:"leader"` Address string `json:"address"` - CreatedAt string `json:"created_at"` + CreatedAt string `json:"created_at"` // RFC 3339 Uptime int64 `json:"uptime_seconds"` - LastContact int64 `json:"last_contact"` // unix timestamp - Latency float64 `json:"latency_ms"` // milliseconds - State string `json:"state"` + LastContact float64 `json:"last_contact_ms"` + Latency float64 `json:"latency_ms"` + Core ClusterNodeCore `json:"core"` Resources ClusterNodeResources `json:"resources"` } -func (n *ClusterNode) Marshal(about proxy.NodeAbout) { - n.ID = about.ID - n.Name = about.Name - n.Address = about.Address - n.CreatedAt = about.CreatedAt.Format(time.RFC3339) - n.Uptime = int64(about.Uptime.Seconds()) - n.LastContact = about.LastContact.Unix() - n.Latency = about.Latency.Seconds() * 1000 - n.State = about.State - n.Resources = ClusterNodeResources(about.Resources) +type ClusterNodeCore struct { + Address string `json:"address"` + Status string `json:"status"` + Error string `json:"error"` + LastContact float64 `json:"last_contact_ms"` + Latency float64 `json:"latency_ms"` } type ClusterNodeResources struct { @@ -40,39 +39,30 @@ type ClusterNodeResources struct { MemLimit uint64 `json:"memory_limit_bytes"` // bytes } -type ClusterNodeFiles struct { - LastUpdate int64 `json:"last_update"` // unix timestamp - Files map[string][]string `json:"files"` -} - -type ClusterRaftServer struct { - ID string `json:"id"` - Address string `json:"address"` // raft address - Voter bool `json:"voter"` - Leader bool `json:"leader"` -} - -type ClusterRaftStats struct { +type ClusterRaft struct { + Address string `json:"address"` State string `json:"state"` LastContact float64 `json:"last_contact_ms"` NumPeers uint64 `json:"num_peers"` -} - -type ClusterRaft struct { - Server []ClusterRaftServer `json:"server"` - Stats ClusterRaftStats `json:"stats"` + LogTerm uint64 `json:"log_term"` + LogIndex uint64 `json:"log_index"` } type ClusterAbout struct { - ID string `json:"id"` - Address string `json:"address"` - ClusterAPIAddress string `json:"cluster_api_address"` - CoreAPIAddress string `json:"core_api_address"` - Raft ClusterRaft `json:"raft"` - Nodes []ClusterNode `json:"nodes"` - Version string `json:"version"` - Degraded bool `json:"degraded"` - DegradedErr string `json:"degraded_error"` + ID string `json:"id"` + Name string `json:"name"` + Leader bool `json:"leader"` + Address string `json:"address"` + Raft ClusterRaft `json:"raft"` + Nodes []ClusterNode `json:"nodes"` + Version string `json:"version"` + Degraded bool `json:"degraded"` + DegradedErr string `json:"degraded_error"` +} + +type ClusterNodeFiles struct { + LastUpdate int64 `json:"last_update"` // unix timestamp + Files map[string][]string `json:"files"` } type ClusterProcess struct { diff --git a/http/handler/api/cluster.go b/http/handler/api/cluster.go index ea355fff..eeee6740 100644 --- a/http/handler/api/cluster.go +++ b/http/handler/api/cluster.go @@ -3,6 +3,7 @@ package api import ( "fmt" "net/http" + "time" "github.com/datarhei/core/v16/cluster" "github.com/datarhei/core/v16/cluster/proxy" @@ -56,18 +57,19 @@ func (h *ClusterHandler) About(c echo.Context) error { state, _ := h.cluster.About() about := api.ClusterAbout{ - ID: state.ID, - Address: state.Address, - ClusterAPIAddress: state.ClusterAPIAddress, - CoreAPIAddress: state.CoreAPIAddress, + ID: state.ID, + Name: state.Name, + Leader: state.Leader, + Address: state.Address, Raft: api.ClusterRaft{ - Server: []api.ClusterRaftServer{}, - Stats: api.ClusterRaftStats{ - State: state.Raft.Stats.State, - LastContact: state.Raft.Stats.LastContact.Seconds() * 1000, - NumPeers: state.Raft.Stats.NumPeers, - }, + Address: state.Raft.Address, + State: state.Raft.State, + LastContact: state.Raft.LastContact.Seconds() * 1000, + NumPeers: state.Raft.NumPeers, + LogTerm: state.Raft.LogTerm, + LogIndex: state.Raft.LogIndex, }, + Nodes: []api.ClusterNode{}, Version: state.Version.String(), Degraded: state.Degraded, } @@ -76,25 +78,53 @@ func (h *ClusterHandler) About(c echo.Context) error { about.DegradedErr = state.DegradedErr.Error() } - for _, n := range state.Raft.Server { - about.Raft.Server = append(about.Raft.Server, api.ClusterRaftServer{ - ID: n.ID, - Address: n.Address, - Voter: n.Voter, - Leader: n.Leader, - }) - } - for _, node := range state.Nodes { - n := api.ClusterNode{} - n.Marshal(node) - - about.Nodes = append(about.Nodes, n) + about.Nodes = append(about.Nodes, h.marshalClusterNode(node)) } return c.JSON(http.StatusOK, about) } +func (h *ClusterHandler) marshalClusterNode(node cluster.ClusterNode) api.ClusterNode { + n := api.ClusterNode{ + ID: node.ID, + Name: node.Name, + Version: node.Version, + Status: node.Status, + Voter: node.Voter, + Leader: node.Leader, + Address: node.Address, + CreatedAt: node.CreatedAt.Format(time.RFC3339), + Uptime: int64(node.Uptime.Seconds()), + LastContact: node.LastContact.Seconds() * 1000, + Latency: node.Latency.Seconds() * 1000, + Core: api.ClusterNodeCore{ + Address: node.Core.Address, + Status: node.Core.Status, + LastContact: node.Core.LastContact.Seconds() * 1000, + Latency: node.Core.Latency.Seconds() * 1000, + }, + Resources: api.ClusterNodeResources{ + IsThrottling: node.Resources.IsThrottling, + NCPU: node.Resources.NCPU, + CPU: node.Resources.CPU, + CPULimit: node.Resources.CPULimit, + Mem: node.Resources.Mem, + MemLimit: node.Resources.MemLimit, + }, + } + + if node.Error != nil { + n.Error = node.Error.Error() + } + + if node.Core.Error != nil { + n.Core.Error = node.Core.Error.Error() + } + + return n +} + // Healthy returns whether the cluster is healthy // @Summary Whether the cluster is healthy // @Description Whether the cluster is healthy diff --git a/http/handler/api/cluster_node.go b/http/handler/api/cluster_node.go index 5fe2f79f..312b835b 100644 --- a/http/handler/api/cluster_node.go +++ b/http/handler/api/cluster_node.go @@ -24,16 +24,12 @@ import ( // @Security ApiKeyAuth // @Router /api/v3/cluster/node [get] func (h *ClusterHandler) GetNodes(c echo.Context) error { - nodes := h.proxy.ListNodes() + about, _ := h.cluster.About() list := []api.ClusterNode{} - for _, node := range nodes { - about := node.About() - n := api.ClusterNode{} - n.Marshal(about) - - list = append(list, n) + for _, node := range about.Nodes { + list = append(list, h.marshalClusterNode(node)) } return c.JSON(http.StatusOK, list) @@ -53,26 +49,17 @@ func (h *ClusterHandler) GetNodes(c echo.Context) error { func (h *ClusterHandler) GetNode(c echo.Context) error { id := util.PathParam(c, "id") - peer, err := h.proxy.GetNodeReader(id) - if err != nil { - return api.Err(http.StatusNotFound, "", "node not found: %s", err.Error()) + about, _ := h.cluster.About() + + for _, node := range about.Nodes { + if node.ID != id { + continue + } + + return c.JSON(http.StatusOK, h.marshalClusterNode(node)) } - about := peer.About() - - node := api.ClusterNode{ - ID: about.ID, - Name: about.Name, - Address: about.Address, - CreatedAt: about.CreatedAt.Format(time.RFC3339), - Uptime: int64(about.Uptime.Seconds()), - LastContact: about.LastContact.Unix(), - Latency: about.Latency.Seconds() * 1000, - State: about.State, - Resources: api.ClusterNodeResources(about.Resources), - } - - return c.JSON(http.StatusOK, node) + return api.Err(http.StatusNotFound, "", "node not found") } // GetNodeVersion returns the proxy node version with the given ID