A question refers to the comment ! And if not Ooopsy
This commit is contained in:
94
tools/api.go
94
tools/api.go
@@ -3,31 +3,36 @@ package tools
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/dbs/mongo"
|
||||
)
|
||||
|
||||
var UncatchedError = []error{}
|
||||
/*
|
||||
* API is the Health Check API
|
||||
* it defines the health check methods
|
||||
*/
|
||||
var UncatchedError = []error{} // Singleton instance of the api 500 error cache
|
||||
|
||||
type State int
|
||||
|
||||
// State is an enum that defines the state of the API
|
||||
const (
|
||||
ALIVE State = iota
|
||||
REDUCED_SERVICE
|
||||
UNPROCESSABLE_ENTITY
|
||||
DB_FALLOUT
|
||||
TEAPOT
|
||||
DEAD
|
||||
WAITING
|
||||
ALIVE State = iota
|
||||
REDUCED_SERVICE // occurs when some services are down
|
||||
UNPROCESSABLE_ENTITY // occurs when the database is up but the collections are not
|
||||
DB_FALLOUT // occurs when the database is down
|
||||
TEAPOT // well some things boils in here, i'm probably a teapot, occurs when uncatched errors are present (it's fun)
|
||||
DEAD // occurs when the peer is dead
|
||||
)
|
||||
|
||||
// EnumIndex returns the index of the enum
|
||||
func (s State) EnumIndex() int {
|
||||
return int(s)
|
||||
}
|
||||
|
||||
// ToState returns the state from a string
|
||||
func ToState(str string) State {
|
||||
for _, s := range []State{ALIVE, REDUCED_SERVICE, UNPROCESSABLE_ENTITY, DB_FALLOUT, TEAPOT, DEAD, WAITING} {
|
||||
for _, s := range []State{ALIVE, REDUCED_SERVICE, UNPROCESSABLE_ENTITY, DB_FALLOUT, TEAPOT, DEAD} {
|
||||
if s.String() == str {
|
||||
return s
|
||||
}
|
||||
@@ -35,92 +40,105 @@ func ToState(str string) State {
|
||||
return DEAD
|
||||
}
|
||||
|
||||
// String returns the string of the enum
|
||||
func (s State) String() string {
|
||||
return [...]string{"alive", "reduced service", "unprocessable entity", "database fallout",
|
||||
"some things boils in here, i'm probably a teapot", "dead", "waiting"}[s]
|
||||
"some things boils in here, i'm probably a teapot", "dead"}[s]
|
||||
}
|
||||
|
||||
type API struct{}
|
||||
|
||||
// GetState returns the state of the API
|
||||
func (a *API) GetState() (State, int, error) {
|
||||
// Check if the database is up
|
||||
err := mongo.MONGOService.TestDB(GetConfig())
|
||||
if err != nil {
|
||||
return DB_FALLOUT, 200, err
|
||||
return DB_FALLOUT, 200, err // If the database is not up, return database fallout
|
||||
}
|
||||
err = mongo.MONGOService.TestCollections(GetConfig(), []string{})
|
||||
err = mongo.MONGOService.TestCollections(GetConfig(), []string{}) // Check if the collections are up
|
||||
if err != nil {
|
||||
return UNPROCESSABLE_ENTITY, 200, err
|
||||
return UNPROCESSABLE_ENTITY, 200, err // If the collections are not up, return unprocessable entity
|
||||
}
|
||||
if len(UncatchedError) > 0 {
|
||||
if len(UncatchedError) > 0 { // If there are uncatched errors, return teapot
|
||||
errStr := ""
|
||||
for _, e := range UncatchedError {
|
||||
errStr += e.Error() + "\n"
|
||||
}
|
||||
return TEAPOT, 200, errors.New(errStr)
|
||||
}
|
||||
return ALIVE, 200, nil
|
||||
return ALIVE, 200, nil // If everything is up, return alive
|
||||
}
|
||||
|
||||
// CheckRemotePeer checks the state of a remote peer
|
||||
func (a *API) CheckRemotePeer(url string) (State, map[string]int) {
|
||||
// Check if the database is up
|
||||
caller := NewHTTPCaller(map[string]map[METHOD]string{})
|
||||
caller := NewHTTPCaller(map[string]map[METHOD]string{}) // Create a new http caller
|
||||
var resp APIStatusResponse
|
||||
b, err := caller.CallPost(url, "/status", map[string]interface{}{})
|
||||
fmt.Println("CheckRemotePeer", b, url, err)
|
||||
b, err := caller.CallPost(url, "/status", map[string]interface{}{}) // Call the status endpoint of the peer
|
||||
if err != nil {
|
||||
return DEAD, map[string]int{}
|
||||
return DEAD, map[string]int{} // If the peer is not reachable, return dead
|
||||
}
|
||||
json.Unmarshal(b, &resp)
|
||||
fmt.Println("CheckRemotePeer2", b, err)
|
||||
if resp.Data == nil {
|
||||
if resp.Data == nil { // If the response is empty, return dead
|
||||
return DEAD, map[string]int{}
|
||||
}
|
||||
new := map[string]int{}
|
||||
fmt.Println("CheckRemotePeer", resp.Data.Services)
|
||||
for k, v := range resp.Data.Services {
|
||||
for k, v := range resp.Data.Services { // Return the services states of the peer
|
||||
new[k] = ToState(v).EnumIndex()
|
||||
}
|
||||
return ToState(resp.Data.State), new
|
||||
return ToState(resp.Data.State), new // Return the state of the peer & its services states
|
||||
}
|
||||
|
||||
// CheckRemoteAPIs checks the state of remote APIs from your proper OC
|
||||
func (a *API) CheckRemoteAPIs(urls map[string]string) (State, map[string]string, error) {
|
||||
// Check if the database is up
|
||||
new := map[string]string{}
|
||||
caller := NewHTTPCaller(map[string]map[METHOD]string{})
|
||||
caller := NewHTTPCaller(map[string]map[METHOD]string{}) // Create a new http caller
|
||||
code := 0
|
||||
u := ""
|
||||
e := ""
|
||||
for appName, url := range urls {
|
||||
state := ALIVE
|
||||
reachable := false
|
||||
for appName, url := range urls { // Check the state of each remote API in the list
|
||||
var resp APIStatusResponse
|
||||
b, err := caller.CallGet(url, "/version/status")
|
||||
b, err := caller.CallGet(url, "/version/status") // Call the status endpoint of the remote API (standard OC status endpoint)
|
||||
if err != nil {
|
||||
return REDUCED_SERVICE, new, err
|
||||
state = REDUCED_SERVICE // If a remote API is not reachable, return reduced service
|
||||
continue
|
||||
}
|
||||
json.Unmarshal(b, &resp)
|
||||
if resp.Data == nil {
|
||||
return DEAD, new, errors.New(url + " -> is DEAD")
|
||||
if resp.Data == nil { //
|
||||
state = REDUCED_SERVICE // If the response is empty, return reduced service
|
||||
continue
|
||||
}
|
||||
new[appName] = resp.Data.State
|
||||
if resp.Data.Code > code {
|
||||
code = resp.Data.Code
|
||||
u = url
|
||||
e += resp.Error
|
||||
}
|
||||
reachable = true // If the remote API is reachable, set reachable to true cause we are not dead
|
||||
}
|
||||
if !reachable {
|
||||
state = DEAD // If no remote API is reachable, return dead, nobody is alive
|
||||
}
|
||||
if code > 0 {
|
||||
return REDUCED_SERVICE, new, errors.New(u + " -> " + e)
|
||||
state = REDUCED_SERVICE
|
||||
}
|
||||
return ALIVE, new, nil
|
||||
return state, new, nil
|
||||
}
|
||||
|
||||
/* APIStatusResponse is the response of the API status */
|
||||
type APIStatusResponse struct {
|
||||
Data *APIStatus `json:"data"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
/*
|
||||
* APIStatus is the status of the API
|
||||
* it defines the state of the API
|
||||
* Code is the status code, where 0 is ALIVE, 1 is REDUCED_SERVICE, 2 is UNPROCESSABLE_ENTITY, 3 is DB_FALLOUT, 4 is TEAPOT, 5 is DEAD
|
||||
*/
|
||||
type APIStatus struct {
|
||||
Code int `json:"code"`
|
||||
State string `json:"state"`
|
||||
Services map[string]string `json:"services"`
|
||||
Code int `json:"code"` // Code is the status code, where 0 is ALIVE, 1 is REDUCED_SERVICE, 2 is UNPROCESSABLE_ENTITY, 3 is DB_FALLOUT, 4 is TEAPOT, 5 is DEAD
|
||||
State string `json:"state"` // State is the state of the API (status shows as a string) (alive, reduced service, unprocessable entity, database fallout, some things boils in here, i'm probably a teapot, dead)
|
||||
Services map[string]string `json:"services"` // Services is the state of the services of the API (status shows as a string) (alive, reduced service, unprocessable entity, database fallout, some things boils in here, i'm probably a teapot, dead)
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
// NATS Method Enum defines the different methods that can be used to interact with the NATS server
|
||||
type NATSMethod int
|
||||
|
||||
const (
|
||||
@@ -14,6 +15,7 @@ const (
|
||||
CREATE
|
||||
)
|
||||
|
||||
// NameToMethod returns the NATSMethod enum value from a string
|
||||
func NameToMethod(name string) NATSMethod {
|
||||
for _, v := range [...]NATSMethod{REMOVE, CREATE} {
|
||||
if strings.Contains(strings.ToLower(v.String()), strings.ToLower(name)) {
|
||||
@@ -23,20 +25,24 @@ func NameToMethod(name string) NATSMethod {
|
||||
return -1
|
||||
}
|
||||
|
||||
// GenerateKey generates a key for the NATSMethod usefull for standard key based on data name & method
|
||||
func (d NATSMethod) GenerateKey(name string) string {
|
||||
return name + "_" + d.String()
|
||||
}
|
||||
|
||||
// String returns the string of the enum
|
||||
func (d NATSMethod) String() string {
|
||||
return [...]string{"remove", "create", "discovery"}[d]
|
||||
}
|
||||
|
||||
type natsCaller struct{}
|
||||
|
||||
// NewNATSCaller creates a new instance of the NATS Caller
|
||||
func NewNATSCaller() *natsCaller {
|
||||
return &natsCaller{}
|
||||
}
|
||||
|
||||
// SetNATSPub sets a message to the NATS server
|
||||
func (o *natsCaller) SetNATSPub(dataName string, method NATSMethod, data interface{}) string {
|
||||
if GetConfig().NATSUrl == "" {
|
||||
return " -> NATS_SERVER is not set"
|
||||
@@ -50,9 +56,9 @@ func (o *natsCaller) SetNATSPub(dataName string, method NATSMethod, data interfa
|
||||
if err != nil {
|
||||
return " -> " + err.Error()
|
||||
}
|
||||
err = nc.Publish(method.GenerateKey(dataName), js)
|
||||
err = nc.Publish(method.GenerateKey(dataName), js) // Publish the message on the NATS server with a channel name based on the data name (or whatever start) and the method
|
||||
if err != nil {
|
||||
return " -> " + err.Error()
|
||||
return " -> " + err.Error() // Return an error if the message could not be published
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HTTP Method Enum defines the different methods that can be used to interact with the HTTP server
|
||||
type METHOD int
|
||||
|
||||
const (
|
||||
@@ -16,14 +17,17 @@ const (
|
||||
DELETE
|
||||
)
|
||||
|
||||
// String returns the string of the enum
|
||||
func (m METHOD) String() string {
|
||||
return [...]string{"GET", "PUT", "POST", "DELETE"}[m]
|
||||
}
|
||||
|
||||
// EnumIndex returns the index of the enum
|
||||
func (m METHOD) EnumIndex() int {
|
||||
return int(m)
|
||||
}
|
||||
|
||||
// ToMethod returns the method from a string
|
||||
func ToMethod(str string) METHOD {
|
||||
for _, s := range []METHOD{GET, PUT, POST, DELETE} {
|
||||
if s.String() == str {
|
||||
@@ -33,18 +37,20 @@ func ToMethod(str string) METHOD {
|
||||
return GET
|
||||
}
|
||||
|
||||
var HTTPCallerInstance = &HTTPCaller{}
|
||||
var HTTPCallerInstance = &HTTPCaller{} // Singleton instance of the HTTPCaller
|
||||
|
||||
type HTTPCaller struct {
|
||||
URLS map[string]map[METHOD]string
|
||||
URLS map[string]map[METHOD]string // Map of the different methods and their urls
|
||||
}
|
||||
|
||||
// NewHTTPCaller creates a new instance of the HTTP Caller
|
||||
func NewHTTPCaller(urls map[string]map[METHOD]string) *HTTPCaller {
|
||||
return &HTTPCaller{
|
||||
URLS: urls,
|
||||
URLS: urls, // Set the urls defined in the config & based on the data name type & method
|
||||
}
|
||||
}
|
||||
|
||||
// CallGet calls the GET method on the HTTP server
|
||||
func (caller *HTTPCaller) CallGet(url string, subpath string) ([]byte, error) {
|
||||
resp, err := http.Get(url + subpath)
|
||||
if err != nil {
|
||||
@@ -54,6 +60,7 @@ func (caller *HTTPCaller) CallGet(url string, subpath string) ([]byte, error) {
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
// CallPut calls the DELETE method on the HTTP server
|
||||
func (caller *HTTPCaller) CallDelete(url string, subpath string) ([]byte, error) {
|
||||
resp, err := http.NewRequest("DELETE", url+subpath, nil)
|
||||
if err != nil {
|
||||
@@ -63,6 +70,7 @@ func (caller *HTTPCaller) CallDelete(url string, subpath string) ([]byte, error)
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
// CallPost calls the POST method on the HTTP server
|
||||
func (caller *HTTPCaller) CallPost(url string, subpath string, body map[string]interface{}) ([]byte, error) {
|
||||
postBody, _ := json.Marshal(body)
|
||||
responseBody := bytes.NewBuffer(postBody)
|
||||
@@ -73,3 +81,5 @@ func (caller *HTTPCaller) CallPost(url string, subpath string, body map[string]i
|
||||
defer resp.Body.Close()
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
// NO PUT IN HERE TO DANGEROUS TO USE ON A REMOTE SERVER, MAYBE NEEDED IN THE FUTURE
|
||||
|
Reference in New Issue
Block a user