Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Health checks for services #426

Merged
merged 8 commits into from
Jul 2, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/hypervisor/statik/statik.go

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions internal/utclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"github.com/SkycoinProject/skywire-mainnet/internal/httpauth"
)

//go:generate mockery -name APIClient -case underscore -inpkg

var log = logging.MustGetLogger("utclient")

// Error is the object returned to the client when there's an error.
Expand All @@ -27,6 +29,7 @@ type Error struct {
// APIClient implements DMSG discovery API client.
type APIClient interface {
UpdateVisorUptime(context.Context) error
Health(ctx context.Context) (int, error)
}

// httpClient implements Client for uptime tracker API.
Expand Down Expand Up @@ -81,6 +84,23 @@ func (c *httpClient) UpdateVisorUptime(ctx context.Context) error {
return nil
}

// UpdateVisorUptime updates visor uptime.
func (c *httpClient) Health(ctx context.Context) (int, error) {
resp, err := c.Get(ctx, "/health")
if err != nil {
return 0, err
}

defer func() {
if err := resp.Body.Close(); err != nil {
log.WithError(err).Warn("Failed to close response body")
}
}()

return resp.StatusCode, nil

}

// extractError returns the decoded error message from Body.
func extractError(r io.Reader) error {
var apiError Error
Expand Down
49 changes: 49 additions & 0 deletions internal/utclient/mock_api_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 11 additions & 30 deletions internal/vpn/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ func NewClient(cfg ClientConfig, l logrus.FieldLogger, conn net.Conn) (*Client,
return nil, fmt.Errorf("error getting TP IP: %w", err)
}

arIP, err := addressResolverIPFromEnv()
if err != nil {
return nil, fmt.Errorf("error getting TP IP: %w", err)
}

rfIP, err := rfIPFromEnv()
if err != nil {
return nil, fmt.Errorf("error getting RF IP: %w", err)
Expand All @@ -58,34 +63,14 @@ func NewClient(cfg ClientConfig, l logrus.FieldLogger, conn net.Conn) (*Client,
return nil, fmt.Errorf("error getting STCP entities: %w", err)
}

var stcprARip net.IP
if _, ok := os.LookupEnv(STCPRAddressResolverAddrEnvKey); ok {
stcprARip, err = stcprAddressResolverIPFromEnv()
if err != nil {
return nil, fmt.Errorf("error getting stcpr AR IP: %w", err)
}
}

var stcphARip net.IP
if _, ok := os.LookupEnv(STCPHAddressResolverAddrEnvKey); ok {
stcphARip, err = stcphAddressResolverIPFromEnv()
if err != nil {
return nil, fmt.Errorf("error getting stcph AR IP: %w", err)
}
}

requiredDirectIPs := []net.IP{dmsgDiscIP, tpDiscIP, rfIP}
directIPs := make([]net.IP, 0, len(requiredDirectIPs)+len(dmsgSrvAddrs)+len(stcpEntities))
directIPs = append(directIPs, requiredDirectIPs...)
directIPs = append(directIPs, dmsgSrvAddrs...)
directIPs = append(directIPs, stcpEntities...)

if stcprARip != nil {
directIPs = append(directIPs, stcprARip)
}

if stcphARip != nil {
directIPs = append(directIPs, stcphARip)
if arIP != nil {
directIPs = append(directIPs, arIP)
}

defaultGateway, err := DefaultNetworkGateway()
Expand Down Expand Up @@ -281,6 +266,10 @@ func tpDiscIPFromEnv() (net.IP, error) {
return ipFromEnv(TPDiscAddrEnvKey)
}

func addressResolverIPFromEnv() (net.IP, error) {
return ipFromEnv(AddressResolverAddrEnvKey)
}

func rfIPFromEnv() (net.IP, error) {
return ipFromEnv(RFAddrEnvKey)
}
Expand Down Expand Up @@ -313,14 +302,6 @@ func stcpEntitiesFromEnv() ([]net.IP, error) {
return stcpEntities, nil
}

func stcprAddressResolverIPFromEnv() (net.IP, error) {
return ipFromEnv(STCPRAddressResolverAddrEnvKey)
}

func stcphAddressResolverIPFromEnv() (net.IP, error) {
return ipFromEnv(STCPHAddressResolverAddrEnvKey)
}

func (c *Client) shakeHands() (TUNIP, TUNGateway net.IP, encrypt bool, err error) {
unavailableIPs, err := LocalNetworkInterfaceIPs()
if err != nil {
Expand Down
30 changes: 10 additions & 20 deletions internal/vpn/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ const (
DmsgDiscAddrEnvKey = "ADDR_DMSG_DISC"
// TPDiscAddrEnvKey is env arg holding TP discovery address.
TPDiscAddrEnvKey = "ADDR_TP_DISC"
// AddressResolverAddrEnvKey is env arg holding address resolver address.
AddressResolverAddrEnvKey = "ADDR_ADDRESS_RESOLVER"
// RFAddrEnvKey is env arg holding RF address.
RFAddrEnvKey = "ADDR_RF"
// UptimeTrackerAddrEnvKey is env arg holding uptime tracker address.
UptimeTrackerAddrEnvKey = "ADDR_UPTIME_TRACKER"
// STCPRAddressResolverAddrEnvKey is env arg holding stcpr address resolver address.
STCPRAddressResolverAddrEnvKey = "ADDR_STCPR_ADDRESS_RESOLVER"
// STCPHAddressResolverAddrEnvKey is env arg holding stcph address resolver address.
STCPHAddressResolverAddrEnvKey = "ADDR_STCPH_ADDRESS_RESOLVER"

// STCPTableLenEnvKey is env arg holding Stcp table length.
STCPTableLenEnvKey = "STCP_TABLE_LEN"
Expand All @@ -41,14 +39,13 @@ const (
// DirectRoutesEnvConfig contains all the addresses which need to be communicated directly,
// not through the VPN service.
type DirectRoutesEnvConfig struct {
DmsgDiscovery string
DmsgServers []string
TPDiscovery string
RF string
UptimeTracker string
STCPRAddressResolver string
STCPHAddressResolver string
STCPTable map[cipher.PubKey]string
DmsgDiscovery string
DmsgServers []string
TPDiscovery string
RF string
UptimeTracker string
AddressResolver string
STCPTable map[cipher.PubKey]string
}

// AppEnvArgs forms env args to pass to the app process.
Expand All @@ -61,6 +58,7 @@ func AppEnvArgs(config DirectRoutesEnvConfig) map[string]string {

if config.TPDiscovery != "" {
envs[TPDiscAddrEnvKey] = config.TPDiscovery
envs[AddressResolverAddrEnvKey] = config.AddressResolver
}

if config.RF != "" {
Expand All @@ -71,14 +69,6 @@ func AppEnvArgs(config DirectRoutesEnvConfig) map[string]string {
envs[UptimeTrackerAddrEnvKey] = config.UptimeTracker
}

if config.STCPRAddressResolver != "" {
envs[STCPRAddressResolverAddrEnvKey] = config.STCPRAddressResolver
}

if config.STCPHAddressResolver != "" {
envs[STCPHAddressResolverAddrEnvKey] = config.STCPHAddressResolver
}

if len(config.STCPTable) != 0 {
envs[STCPTableLenEnvKey] = strconv.FormatInt(int64(len(config.STCPTable)), 10)

Expand Down
23 changes: 23 additions & 0 deletions pkg/routefinder/rfclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type HTTPError struct {
// Client implements route finding operations.
type Client interface {
FindRoutes(ctx context.Context, rts []routing.PathEdges, opts *RouteOptions) (map[routing.PathEdges][][]routing.Hop, error)
Health(ctx context.Context) (int, error)
}

// APIClient implements Client interface
Expand Down Expand Up @@ -85,9 +86,12 @@ func (c *apiClient) FindRoutes(ctx context.Context, rts []routing.PathEdges, opt
if err != nil {
return nil, err
}

req.Header.Set("Content-Type", "application/json")

ctx, cancel := context.WithTimeout(ctx, c.apiTimeout)
defer cancel()

req = req.WithContext(ctx)

res, err := c.client.Do(req)
Expand All @@ -98,6 +102,7 @@ func (c *apiClient) FindRoutes(ctx context.Context, rts []routing.PathEdges, opt
}
}()
}

if err != nil {
return nil, err
}
Expand All @@ -122,6 +127,24 @@ func (c *apiClient) FindRoutes(ctx context.Context, rts []routing.PathEdges, opt
return paths, nil
}

// Health checks route finder health.
func (c *apiClient) Health(_ context.Context) (int, error) {
res, err := http.Get(c.addr + "/health")
if err != nil {
return 0, err
}

if res != nil {
defer func() {
if err := res.Body.Close(); err != nil {
log.WithError(err).Warn("Failed to close HTTP response body")
}
}()
}

return res.StatusCode, nil
}

func sanitizedAddr(addr string) string {
if addr == "" {
return "http://localhost"
Expand Down
6 changes: 6 additions & 0 deletions pkg/routefinder/rfclient/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package rfclient

import (
"fmt"
"net/http"

"github.com/SkycoinProject/dmsg/cipher"
"golang.org/x/net/context"
Expand Down Expand Up @@ -48,3 +49,8 @@ func (r *mockClient) FindRoutes(ctx context.Context, rts []routing.PathEdges, op
},
}, nil
}

// Health implements Client for MockClient
func (r *mockClient) Health(_ context.Context) (int, error) {
return http.StatusOK, nil
}
19 changes: 19 additions & 0 deletions pkg/router/mock_router.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions pkg/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ type router struct {
trustedVisors map[cipher.PubKey]struct{}
tm *transport.Manager
rt routing.Table
rfc rfclient.Client // route finder client
rgs map[routing.RouteDescriptor]*RouteGroup // route groups to push incoming reads from transports.
rpcSrv *rpc.Server
accept chan routing.EdgeRules
Expand Down Expand Up @@ -167,7 +166,6 @@ func New(n *snet.Network, config *Config) (Router, error) {
tm: config.TransportManager,
rt: routing.NewTable(),
sl: sl,
rfc: config.RouteFinder,
rgs: make(map[routing.RouteDescriptor]*RouteGroup),
rpcSrv: rpc.NewServer(),
accept: make(chan routing.EdgeRules, acceptSize),
Expand Down
Loading