Skip to content

Commit

Permalink
added health endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ivcosla committed Aug 19, 2019
1 parent a0a985b commit cb709e8
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 0 deletions.
29 changes: 29 additions & 0 deletions pkg/hypervisor/hypervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ func (m *Node) ServeHTTP(w http.ResponseWriter, req *http.Request) {
r.Get("/user", m.users.UserInfo())
r.Post("/change-password", m.users.ChangePassword())
r.Get("/nodes", m.getNodes())
r.Get("/health", m.getHealth())
r.Get("/nodes/{pk}", m.getNode())
r.Get("/nodes/{pk}/apps", m.getApps())
r.Get("/nodes/{pk}/apps/{app}", m.getApp())
Expand All @@ -150,6 +151,34 @@ func (m *Node) ServeHTTP(w http.ResponseWriter, req *http.Request) {
r.ServeHTTP(w, req)
}

// VisorHealth represents a node's health report attached to it's pk for identification
type VisorHealth struct {
PK cipher.PubKey `json:"pk"`
*visor.HealthInfo
}

// provides summary of health information for every visor
func (m *Node) getHealth() http.HandlerFunc {
healthStatuses := make([]*VisorHealth, len(m.nodes))

return func(w http.ResponseWriter, r *http.Request) {
m.mu.RLock()
for pk, c := range m.nodes {
vh := &VisorHealth{PK: pk}

hi, err := c.Client.Health()
if err != nil {
httputil.WriteJSON(w, r, http.StatusInternalServerError, err)
return
}

vh.HealthInfo = hi
healthStatuses = append(healthStatuses, vh)
}

}
}

type summaryResp struct {
TCPAddr string `json:"tcp_addr"`
*visor.Summary
Expand Down
35 changes: 35 additions & 0 deletions pkg/visor/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"errors"
"time"

"net/http"

"github.com/google/uuid"
"github.com/skycoin/dmsg/cipher"

Expand Down Expand Up @@ -33,6 +35,39 @@ type RPC struct {
node *Node
}

/*
<<< NODE HEALTH >>>
*/

// HealthInfo carries information about visor's external services health represented as http status codes
type HealthInfo struct {
TransportDiscovery int `json:"transport_discovery"`
RouteFinder int `json:"route_finder"`
SetupNode int `json:"setup_node"`
}

// Health returns health information about the visor
func (r *RPC) Health(_ *struct{}, out *HealthInfo) error {
out.TransportDiscovery = http.StatusOK
out.RouteFinder = http.StatusOK
out.SetupNode = http.StatusOK

_, err := r.node.config.TransportDiscovery()
if err != nil {
out.TransportDiscovery = http.StatusNotFound
}

if r.node.config.Routing.RouteFinder == "" {
out.RouteFinder = http.StatusNotFound
}

if len(r.node.config.Routing.SetupNodes) == 0 {
out.SetupNode = http.StatusNotFound
}

return nil
}

/*
<<< NODE SUMMARY >>>
*/
Expand Down
9 changes: 9 additions & 0 deletions pkg/visor/rpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
type RPCClient interface {
Summary() (*Summary, error)

Health() (*HealthInfo, error)

Apps() ([]*AppState, error)
StartApp(appName string) error
StopApp(appName string) error
Expand Down Expand Up @@ -64,6 +66,13 @@ func (rc *rpcClient) Summary() (*Summary, error) {
return out, err
}

// Health calls Health
func (rc *rpcClient) Health() (*HealthInfo, error) {
hi := &HealthInfo{}
err := rc.Call("Health", &struct{}{}, hi)
return hi, err
}

// Apps calls Apps.
func (rc *rpcClient) Apps() ([]*AppState, error) {
states := make([]*AppState, 0)
Expand Down
21 changes: 21 additions & 0 deletions pkg/visor/rpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"net"
"net/http"
"net/rpc"
"os"
"testing"
Expand All @@ -19,6 +20,26 @@ import (
"github.com/skycoin/skywire/pkg/util/pathutil"
)

func TestHealth(t *testing.T) {
sPK, _ := cipher.GenerateKeyPair()

c := &Config{}
c.Transport.Discovery = "foo"
c.Routing.SetupNodes = []cipher.PubKey{sPK}
c.Routing.RouteFinder = "foo"

t.Run("Report all the services as available", func(t *testing.T) {
rpc := &RPC{&Node{config: c}}
h := &HealthInfo{}
err := rpc.Health(&struct{}{}, h)
require.NoError(t, err)

assert.Equal(t, h.TransportDiscovery, http.StatusOK)
assert.Equal(t, h.SetupNode, http.StatusOK)
assert.Equal(t, h.RouteFinder, http.StatusOK)
})
}

func TestListApps(t *testing.T) {
apps := []AppConfig{
{App: "foo", AutoStart: false, Port: 10},
Expand Down

0 comments on commit cb709e8

Please sign in to comment.