From c484eeecdbf3b1deaf5fac0d96ec495a515d13a5 Mon Sep 17 00:00:00 2001 From: Vivek Singh 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 --- 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 a3ac15a5f..56ee03b68 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 d9b1c9cc6..3348c3dbf 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) + } + } +}