From 88c35e30b49a2eaa04dcf59efa87e4e84349428f Mon Sep 17 00:00:00 2001 From: TwinProduction Date: Thu, 12 Sep 2019 16:15:42 -0400 Subject: [PATCH] Add first version of UI --- core/types.go | 43 +++++++++++++++++++++----------- core/types_test.go | 49 +++++++++++++++++++++++++++++++++--- main.go | 7 +----- static/index.html | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 24 deletions(-) create mode 100644 static/index.html diff --git a/core/types.go b/core/types.go index dd25fa5a..3133688e 100644 --- a/core/types.go +++ b/core/types.go @@ -1,6 +1,7 @@ package core import ( + "errors" "fmt" "net" "net/http" @@ -21,13 +22,14 @@ type ServerMessage struct { } type Result struct { - HttpStatus int `json:"status"` - Hostname string `json:"hostname"` - Ip string `json:"ip"` - Duration time.Duration `json:"duration"` - Errors []error `json:"errors"` - ConditionResult []*ConditionResult `json:"condition-results"` - Timestamp time.Time `json:"timestamp"` + HttpStatus int `json:"status"` + Hostname string `json:"hostname"` + Ip string `json:"ip"` + Duration time.Duration `json:"duration"` + Errors []error `json:"errors"` + ConditionResults []*ConditionResult `json:"condition-results"` + Success bool `json:"success"` + Timestamp time.Time `json:"timestamp"` } type Service struct { @@ -68,11 +70,17 @@ func (service *Service) getStatus(result *Result) { } func (service *Service) EvaluateConditions() *Result { - result := &Result{} + result := &Result{Success: true} service.getStatus(result) service.getIp(result) + if len(result.Errors) > 0 { + result.Success = false + } for _, condition := range service.Conditions { - condition.Evaluate(result) + success := condition.Evaluate(result) + if !success { + result.Success = false + } } result.Timestamp = time.Now() return result @@ -86,38 +94,45 @@ type ConditionResult struct { type Condition string -func (c *Condition) Evaluate(result *Result) { +func (c *Condition) Evaluate(result *Result) bool { condition := string(*c) if strings.Contains(condition, "==") { parts := sanitizeAndResolve(strings.Split(condition, "=="), result) if parts[0] == parts[1] { - result.ConditionResult = append(result.ConditionResult, &ConditionResult{ + result.ConditionResults = append(result.ConditionResults, &ConditionResult{ Condition: c, Success: true, Explanation: fmt.Sprintf("%s is equal to %s", parts[0], parts[1]), }) + return true } else { - result.ConditionResult = append(result.ConditionResult, &ConditionResult{ + result.ConditionResults = append(result.ConditionResults, &ConditionResult{ Condition: c, Success: false, Explanation: fmt.Sprintf("%s is not equal to %s", parts[0], parts[1]), }) + return false } } else if strings.Contains(condition, "!=") { parts := sanitizeAndResolve(strings.Split(condition, "!="), result) if parts[0] != parts[1] { - result.ConditionResult = append(result.ConditionResult, &ConditionResult{ + result.ConditionResults = append(result.ConditionResults, &ConditionResult{ Condition: c, Success: true, Explanation: fmt.Sprintf("%s is not equal to %s", parts[0], parts[1]), }) + return true } else { - result.ConditionResult = append(result.ConditionResult, &ConditionResult{ + result.ConditionResults = append(result.ConditionResults, &ConditionResult{ Condition: c, Success: false, Explanation: fmt.Sprintf("%s is equal to %s", parts[0], parts[1]), }) + return false } + } else { + result.Errors = append(result.Errors, errors.New(fmt.Sprintf("invalid condition '%s' has been provided", condition))) + return false } } diff --git a/core/types_test.go b/core/types_test.go index 25d0ddb5..7ba711a3 100644 --- a/core/types_test.go +++ b/core/types_test.go @@ -8,8 +8,8 @@ func TestEvaluateWithIp(t *testing.T) { condition := Condition("$IP == 127.0.0.1") result := &Result{Ip: "127.0.0.1"} condition.Evaluate(result) - if result.ConditionResult[0].Success != true { - t.Error("Condition '$IP == 127.0.0.1' should have been a success") + if !result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have been a success", condition) } } @@ -17,7 +17,48 @@ func TestEvaluateWithStatus(t *testing.T) { condition := Condition("$STATUS == 201") result := &Result{HttpStatus: 201} condition.Evaluate(result) - if result.ConditionResult[0].Success != true { - t.Error("Condition '$STATUS == 201' should have been a success") + if !result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have been a success", condition) + } +} + +func TestEvaluateWithFailure(t *testing.T) { + condition := Condition("$STATUS == 200") + result := &Result{HttpStatus: 500} + condition.Evaluate(result) + if result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have been a failure", condition) + } +} + +func TestIntegrationEvaluateConditions(t *testing.T) { + condition := Condition("$STATUS == 200") + service := Service{ + Name: "GitHub", + Url: "https://api.github.com/healthz", + Conditions: []*Condition{&condition}, + } + result := service.EvaluateConditions() + if !result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have been a success", condition) + } + if !result.Success { + t.Error("Because all conditions passed, this should have been a success") + } +} + +func TestIntegrationEvaluateConditionsWithFailure(t *testing.T) { + condition := Condition("$STATUS == 500") + service := Service{ + Name: "GitHub", + Url: "https://api.github.com/healthz", + Conditions: []*Condition{&condition}, + } + result := service.EvaluateConditions() + if result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have been a failure", condition) + } + if result.Success { + t.Error("Because one of the conditions failed, success should have been false") } } diff --git a/main.go b/main.go index 482ec792..08f832cb 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ func main() { go watchdog.Monitor() http.HandleFunc("/api/v1/results", serviceResultsHandler) http.HandleFunc("/health", healthHandler) - http.HandleFunc("/", indexHandler) + http.Handle("/", http.FileServer(http.Dir("./static"))) log.Println("[main][main] Listening on port 80") log.Fatal(http.ListenAndServe(":80", nil)) } @@ -23,11 +23,6 @@ func serviceResultsHandler(writer http.ResponseWriter, request *http.Request) { _, _ = writer.Write(structToJsonBytes(serviceResults)) } -func indexHandler(writer http.ResponseWriter, request *http.Request) { - writer.WriteHeader(http.StatusNotImplemented) - _, _ = writer.Write(structToJsonBytes(&core.ServerMessage{Error: true, Message: "Not implemented yet"})) -} - func healthHandler(writer http.ResponseWriter, request *http.Request) { writer.WriteHeader(http.StatusOK) _, _ = writer.Write(structToJsonBytes(&core.HealthStatus{Status: "UP"})) diff --git a/static/index.html b/static/index.html new file mode 100644 index 00000000..284f6ac6 --- /dev/null +++ b/static/index.html @@ -0,0 +1,62 @@ + + + + gatus + + + +
+
+
Gatus
+
+ + + + + + + + + + + +
NameStatusHostnameResponse time
+
+ + + + + + + + \ No newline at end of file