From c484eeecdbf3b1deaf5fac0d96ec495a515d13a5 Mon Sep 17 00:00:00 2001
From: Vivek Singh <vivekkmr45@yahoo.in>
Date: Fri, 16 Mar 2018 14:26:25 +0530
Subject: [PATCH] Add `/_/health` endpoint to watchdog

Introduce new endpoint `/_/health` to watchdog for health status of
functions  which check for `/tmp/.lock` file

Fixes first part of #547 issue.

Signed-off-by: Vivek Singh <vivekkmr45@yahoo.in>
---
 watchdog/main.go                | 43 +++++++++++++++++++++
 watchdog/requesthandler_test.go | 66 +++++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/watchdog/main.go b/watchdog/main.go
index a3ac15a5..56ee03b6 100644
--- a/watchdog/main.go
+++ b/watchdog/main.go
@@ -252,6 +252,48 @@ func getAdditionalEnvs(config *WatchdogConfig, r *http.Request, method string) [
 	return envs
 }
 
+func lockFilePresent() bool {
+	path := filepath.Join(os.TempDir(), ".lock")
+	if _, err := os.Stat(path); os.IsNotExist(err) {
+		return false
+	}
+	return true
+}
+
+func createLockFile() error {
+	path := filepath.Join(os.TempDir(), ".lock")
+	log.Printf("Writing lock-file to: %s\n", path)
+	writeErr := ioutil.WriteFile(path, []byte{}, 0660)
+	return writeErr
+}
+
+func removeLockFile() error {
+	path := filepath.Join(os.TempDir(), ".lock")
+	log.Printf("Removing lock-file : %s\n", path)
+	removeErr := os.Remove(path)
+	return removeErr
+}
+
+func makeHealthHandler() func(http.ResponseWriter, *http.Request) {
+	return func(w http.ResponseWriter, r *http.Request) {
+		switch r.Method {
+		case "GET":
+			if lockFilePresent() == false {
+				w.WriteHeader(http.StatusInternalServerError)
+				return
+			}
+
+			w.WriteHeader(http.StatusOK)
+			w.Write([]byte("OK"))
+			break
+		default:
+			w.WriteHeader(http.StatusMethodNotAllowed)
+
+		}
+
+	}
+}
+
 func makeRequestHandler(config *WatchdogConfig) func(http.ResponseWriter, *http.Request) {
 	return func(w http.ResponseWriter, r *http.Request) {
 		switch r.Method {
@@ -290,6 +332,7 @@ func main() {
 		MaxHeaderBytes: 1 << 20, // Max header of 1MB
 	}
 
+	http.HandleFunc("/_/health", makeHealthHandler())
 	http.HandleFunc("/", makeRequestHandler(&config))
 
 	if config.suppressLock == false {
diff --git a/watchdog/requesthandler_test.go b/watchdog/requesthandler_test.go
index d9b1c9cc..3348c3db 100644
--- a/watchdog/requesthandler_test.go
+++ b/watchdog/requesthandler_test.go
@@ -360,3 +360,69 @@ func TestHandler_StatusOKForGETAndNoBody(t *testing.T) {
 			status, required)
 	}
 }
+
+func TestHealthHandler_SatusOK_LockFilePresent(t *testing.T) {
+	rr := httptest.NewRecorder()
+
+	if lockFilePresent() == false {
+		if err := createLockFile(); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	req, err := http.NewRequest("GET", "/_/health", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handler := makeHealthHandler()
+	handler(rr, req)
+
+	required := http.StatusOK
+	if status := rr.Code; status != required {
+		t.Errorf("handler returned wrong status code: got %v, but wanted %v", status, required)
+	}
+
+}
+
+func TestHealthHandler_StatusInternalServerError_LockFileNotPresent(t *testing.T) {
+	rr := httptest.NewRecorder()
+
+	if lockFilePresent() == true {
+		if err := removeLockFile(); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	req, err := http.NewRequest("GET", "/_/health", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handler := makeHealthHandler()
+	handler(rr, req)
+
+	required := http.StatusInternalServerError
+	if status := rr.Code; status != required {
+		t.Errorf("handler retruned wrong status code: got %v, but wanted %v", status, required)
+	}
+}
+
+func TestHealthHandler_SatusMethoNotAllowed_ForWriteableVerbs(t *testing.T) {
+	rr := httptest.NewRecorder()
+
+	verbs := []string{"POST", "PUT", "UPDATE", "DELETE"}
+
+	for _, verb := range verbs {
+		req, err := http.NewRequest(verb, "/_/health", nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		handler := makeHealthHandler()
+		handler(rr, req)
+
+		required := http.StatusMethodNotAllowed
+		if status := rr.Code; status != required {
+			t.Errorf("handler returned wrong status code: got %v, but wanted %v", status, required)
+		}
+	}
+}
-- 
GitLab