From ddc7406a4c77fd1ceea2ea9f1ed11d7f97d22171 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Mon, 21 Feb 2022 11:34:47 +0100 Subject: [PATCH] src/server.go: refactor eosio v1/v2 api code into it's own module that implements a common interface --- go.mod | 2 + src/api/go.mod | 3 ++ src/api/interface.go | 11 ++++ src/api/v1.go | 55 +++++++++++++++++++ src/api/v2.go | 72 +++++++++++++++++++++++++ src/server.go | 123 +++++++++++-------------------------------- 6 files changed, 173 insertions(+), 93 deletions(-) create mode 100644 src/api/go.mod create mode 100644 src/api/interface.go create mode 100644 src/api/v1.go create mode 100644 src/api/v2.go diff --git a/go.mod b/go.mod index ce25421..090026f 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,8 @@ require ( github.com/mattn/go-colorable v0.1.12 // indirect github.com/pborman/getopt/v2 v2.1.0 internal/utils v1.0.0 + internal/api v1.0.0 ) replace internal/utils => ./src/utils +replace internal/api => ./src/api diff --git a/src/api/go.mod b/src/api/go.mod new file mode 100644 index 0000000..297663b --- /dev/null +++ b/src/api/go.mod @@ -0,0 +1,3 @@ +module internal/api + +go 1.14 diff --git a/src/api/interface.go b/src/api/interface.go new file mode 100644 index 0000000..0a2030a --- /dev/null +++ b/src/api/interface.go @@ -0,0 +1,11 @@ + +package api + +import ( + "github.com/eosswedenorg-go/haproxy" +) + +type ApiInterface interface { + Name() string + Call() (haproxy.HealthCheckStatus, string) +} diff --git a/src/api/v1.go b/src/api/v1.go new file mode 100644 index 0000000..2115be3 --- /dev/null +++ b/src/api/v1.go @@ -0,0 +1,55 @@ + +package api + +import ( + "fmt" + "time" + "github.com/eosswedenorg-go/haproxy" + "github.com/eosswedenorg-go/eosapi" +) + +type EosioV1 struct { + params eosapi.ReqParams + block_time float64 +} + +func NewEosioV1(params eosapi.ReqParams, block_time float64) EosioV1 { + return EosioV1{ + params: params, + block_time: block_time, + } +} + +func (e EosioV1) Name() string { + return "v1" +} + +// check_api - Validates head block time. +// --------------------------------------------------------- +func (e EosioV1) Call() (haproxy.HealthCheckStatus, string) { + + info, err := eosapi.GetInfo(e.params) + if err != nil { + msg := fmt.Sprintf("%s", err); + return haproxy.HealthCheckFailed, msg + } + + // Check HTTP Status Code + if info.HTTPStatusCode > 299 { + return haproxy.HealthCheckDown, + fmt.Sprintf("Taking offline because %v was received from backend", info.HTTPStatusCode) + } + + // Validate head block. + now := time.Now().In(time.UTC) + diff := now.Sub(info.HeadBlockTime).Seconds() + + if diff > e.block_time { + return haproxy.HealthCheckDown, + fmt.Sprintf("Taking offline because head block is lagging %.0f seconds", diff) + } else if diff < -e.block_time { + return haproxy.HealthCheckDown, + fmt.Sprintf("Taking offline because head block is %.0f seconds into the future", diff) + } + return haproxy.HealthCheckUp, "OK" +} diff --git a/src/api/v2.go b/src/api/v2.go new file mode 100644 index 0000000..7a83e1b --- /dev/null +++ b/src/api/v2.go @@ -0,0 +1,72 @@ + +package api + +import ( + "fmt" + "internal/utils" + "github.com/eosswedenorg-go/haproxy" + "github.com/eosswedenorg-go/eosapi" +) + +type EosioV2 struct { + params eosapi.ReqParams + offset int64 +} + +func NewEosioV2(params eosapi.ReqParams, offset int64) EosioV2 { + return EosioV2{ + params: params, + offset: offset, + } +} + +func (e EosioV2) Name() string { + return "v2" +} + +// check_api - Validates head block time. +// --------------------------------------------------------- +func (e EosioV2) Call() (haproxy.HealthCheckStatus, string) { + + health, err := eosapi.GetHealth(e.params) + if err != nil { + msg := fmt.Sprintf("%s", err); + return haproxy.HealthCheckFailed, msg + } + + // Check HTTP Status Code + if health.HTTPStatusCode > 299 { + return haproxy.HealthCheckDown, + fmt.Sprintf("Taking offline because %v was received from backend", health.HTTPStatusCode) + } + + // Fetch elasticsearch and nodeos block numbers from json. + var es_block int64 = 0 + var node_block int64 = 0 + + for _, v := range health.Health { + if v.Name == "Elasticsearch" { + es_block = utils.JsonGetInt64(v.Data["last_indexed_block"]) + } else if v.Name == "NodeosRPC" { + node_block = utils.JsonGetInt64(v.Data["head_block_num"]) + } + } + + // Error out if ether or both are zero. + if es_block == 0 || node_block == 0 { + msg := fmt.Sprintf("Failed to get Elasticsearch and/or nodeos " + + "block numbers (es: %d, eos: %d)", es_block, node_block) + return haproxy.HealthCheckFailed, msg + } + + // Check if ES is behind or in the future. + diff := node_block - es_block; + if diff > e.offset { + return haproxy.HealthCheckDown, + fmt.Sprintf("Taking offline because Elastic is %d blocks behind", diff) + } else if diff < -e.offset { + return haproxy.HealthCheckDown, + fmt.Sprintf("Taking offline because Elastic is %d blocks into the future", -1 * diff) + } + return haproxy.HealthCheckUp, "OK" +} diff --git a/src/server.go b/src/server.go index f3fc5e8..c754a69 100644 --- a/src/server.go +++ b/src/server.go @@ -2,141 +2,78 @@ package main import ( "fmt" - "time" "strings" "strconv" - "internal/utils" + "internal/api" "github.com/eosswedenorg-go/eosapi" "github.com/eosswedenorg-go/haproxy" "github.com/eosswedenorg-go/tcp_server" ) -// check_api - Validates head block time. -// --------------------------------------------------------- -func check_api(p eosapi.ReqParams, block_time float64) (haproxy.HealthCheckStatus, string) { - - info, err := eosapi.GetInfo(p) - if err != nil { - msg := fmt.Sprintf("%s", err); - return haproxy.HealthCheckFailed, msg - } - - // Check HTTP Status Code - if info.HTTPStatusCode > 299 { - return haproxy.HealthCheckDown, - fmt.Sprintf("Taking offline because %v was received from backend", info.HTTPStatusCode) - } - - // Validate head block. - now := time.Now().In(time.UTC) - diff := now.Sub(info.HeadBlockTime).Seconds() - - if diff > block_time { - return haproxy.HealthCheckDown, - fmt.Sprintf("Taking offline because head block is lagging %.0f seconds", diff) - } else if diff < -block_time { - return haproxy.HealthCheckDown, - fmt.Sprintf("Taking offline because head block is %.0f seconds into the future", diff) - } - return haproxy.HealthCheckUp, "OK" +type arguments struct { + api string + url string + host string + block_time int } -// check_api_v2 (hyperion) -// Validates block num diff between -// nodeos and elasticsearch -// --------------------------------------------------------- -func check_api_v2(p eosapi.ReqParams, offset int64) (haproxy.HealthCheckStatus, string) { +func createApi(a *arguments) api.ApiInterface { - health, err := eosapi.GetHealth(p) - if err != nil { - msg := fmt.Sprintf("%s", err); - return haproxy.HealthCheckFailed, msg + switch a.api { + case "v2": + return api.NewEosioV2(eosapi.ReqParams{Url: a.url, Host: a.host}, int64(a.block_time / 2)) } - // Check HTTP Status Code - if health.HTTPStatusCode > 299 { - return haproxy.HealthCheckDown, - fmt.Sprintf("Taking offline because %v was received from backend", health.HTTPStatusCode) - } - - // Fetch elasticsearch and nodeos block numbers from json. - var es_block int64 = 0 - var node_block int64 = 0 - - for _, v := range health.Health { - if v.Name == "Elasticsearch" { - es_block = utils.JsonGetInt64(v.Data["last_indexed_block"]) - } else if v.Name == "NodeosRPC" { - node_block = utils.JsonGetInt64(v.Data["head_block_num"]) - } - } - - // Error out if ether or both are zero. - if es_block == 0 || node_block == 0 { - msg := fmt.Sprintf("Failed to get Elasticsearch and/or nodeos " + - "block numbers (es: %d, eos: %d)", es_block, node_block) - return haproxy.HealthCheckFailed, msg - } - - // Check if ES is behind or in the future. - diff := node_block - es_block; - if diff > offset { - return haproxy.HealthCheckDown, - fmt.Sprintf("Taking offline because Elastic is %d blocks behind", diff) - } else if diff < -offset { - return haproxy.HealthCheckDown, - fmt.Sprintf("Taking offline because Elastic is %d blocks into the future", -1 * diff) - } - return haproxy.HealthCheckUp, "OK" + return api.NewEosioV1(eosapi.ReqParams{Url: a.url, Host: a.host}, float64(a.block_time)) } // onTcpMessage callback function // --------------------------------------------------------- func onTcpMessage(c *tcp_server.Client, args string) { - params := eosapi.ReqParams{} - var block_time int = 10 - var version string = "v1" + a := arguments{ + api: "v1", + block_time: 10, + } + + // var url string + // var host string + // var block_time int = 10 + // var version string = "v1" // Parse arguments. // ------------------- split := strings.Split(strings.TrimSpace(args), "|") // 1. url (scheme + ip/domain + port) - params.Url = split[0] + a.url = split[0] // 2. Block time. if len(split) > 1 { - p, err := strconv.ParseInt(split[1], 10, 32) + num, err := strconv.ParseInt(split[1], 10, 32) if err == nil { - block_time = int(p) + a.block_time = int(num) } } - // 3. Version + // 3. Api if len(split) > 2 { - version = split[2] + a.api = split[2] } // 4. Host if len(split) > 3 { - params.Host = split[3] + a.host = split[3] } // Check api. // ------------------- - var status haproxy.HealthCheckStatus - var msg string + healthCheckApi := createApi(&a) - if version == "v2" { - status, msg = check_api_v2(params, int64(block_time / 2)) - } else { - version = "v1" - status, msg = check_api(params, float64(block_time)) - } + status, msg := healthCheckApi.Call() - logger.Info("API Check", "version", version, "url", params.Url, - "block", block_time / 2, "status", status) + logger.Info("API Check", "type", healthCheckApi.Name(), "url", a.url, + "block", a.block_time / 2, "status", status) if status != haproxy.HealthCheckUp && len(msg) > 0 { logger.Warn("API Check Failed", "message", msg)