diff --git a/watchdog/.gitignore b/watchdog/.gitignore index 512d37b04582b990766066a959c8d4fd44113f51..cd8ffeccf947deef8070278f8caa3cf2c0f63381 100644 --- a/watchdog/.gitignore +++ b/watchdog/.gitignore @@ -1 +1,2 @@ fwatchdog +watchdog diff --git a/watchdog/config_test.go b/watchdog/config_test.go new file mode 100644 index 0000000000000000000000000000000000000000..74f2b025c58828becbb45a3f127fd436166081d2 --- /dev/null +++ b/watchdog/config_test.go @@ -0,0 +1,91 @@ +package main + +import "testing" + +type EnvBucket struct { + Items map[string]string +} + +func NewEnvBucket() EnvBucket { + return EnvBucket{ + Items: make(map[string]string), + } +} + +func (e EnvBucket) Getenv(key string) string { + return e.Items[key] +} + +func (e EnvBucket) Setenv(key string, value string) { + e.Items[key] = value +} +func TestRead_WriteDebug_DefaultIsTrueConfig(t *testing.T) { + defaults := NewEnvBucket() + readConfig := ReadConfig{} + + config := readConfig.Read(defaults) + + if config.writeDebug != true { + t.Logf("writeDebug should have been true") + t.Fail() + } +} +func TestRead_WriteDebug_FalseConfig(t *testing.T) { + defaults := NewEnvBucket() + readConfig := ReadConfig{} + defaults.Setenv("writeDebug", "true") + + config := readConfig.Read(defaults) + + if config.writeDebug != true { + t.Logf("writeDebug should have been true") + t.Fail() + } +} + +func TestRead_FprocessConfig(t *testing.T) { + defaults := NewEnvBucket() + readConfig := ReadConfig{} + defaults.Setenv("fprocess", "cat") + + config := readConfig.Read(defaults) + + if config.faasProcess != "cat" { + t.Logf("fprocess envVariable incorrect, got: %s.\n", config.faasProcess) + t.Fail() + } +} + +func TestRead_EmptyTimeoutConfig(t *testing.T) { + defaults := NewEnvBucket() + readConfig := ReadConfig{} + + config := readConfig.Read(defaults) + + if (config.readTimeout) != 5 { + t.Log("readTimeout incorrect") + t.Fail() + } + if (config.writeTimeout) != 5 { + t.Log("writeTimeout incorrect") + t.Fail() + } +} + +func TestRead_ReadAndWriteTimeoutConfig(t *testing.T) { + defaults := NewEnvBucket() + defaults.Setenv("read_timeout", "10") + defaults.Setenv("write_timeout", "60") + + readConfig := ReadConfig{} + config := readConfig.Read(defaults) + + if (config.readTimeout) != 10 { + t.Logf("readTimeout incorrect, got: %d\n", config.readTimeout) + t.Fail() + } + if (config.writeTimeout) != 60 { + t.Logf("writeTimeout incorrect, got: %d\n", config.writeTimeout) + t.Fail() + } +} diff --git a/watchdog/main.go b/watchdog/main.go index 9ecf1fec6d642ccd27db9f223799d3cab327facd..d608a04806ade3ba23e53719729532436899a9ff 100644 --- a/watchdog/main.go +++ b/watchdog/main.go @@ -7,54 +7,23 @@ import ( "net/http" "os" "os/exec" - "strconv" "strings" "time" ) -func main() { - readTimeoutStr := os.Getenv("read_timeout") - writeTimeoutStr := os.Getenv("write_timeout") - writeDebugStr := os.Getenv("write_debug") - process := os.Getenv("fprocess") - - readTimeout := 5 * time.Second - writeTimeout := 5 * time.Second - writeDebug := true - - if len(process) == 0 { - log.Panicln("Provide a valid process via fprocess environmental variable.") - return - } - - if len(writeDebugStr) > 0 && writeDebugStr == "false" { - writeDebug = false - } - - if len(readTimeoutStr) > 0 { - parsedVal, parseErr := strconv.Atoi(readTimeoutStr) - if parseErr == nil && parsedVal > 0 { - readTimeout = time.Duration(parsedVal) * time.Second - } - } - - if len(writeTimeoutStr) > 0 { - parsedVal, parseErr := strconv.Atoi(writeTimeoutStr) - if parseErr == nil && parsedVal > 0 { - writeTimeout = time.Duration(parsedVal) * time.Second - } - } +// OsEnv implements interface to wrap os.Getenv +type OsEnv struct { +} - s := &http.Server{ - Addr: ":8080", - ReadTimeout: readTimeout, - WriteTimeout: writeTimeout, - MaxHeaderBytes: 1 << 20, - } +// Getenv wraps os.Getenv +func (OsEnv) Getenv(key string) string { + return os.Getenv(key) +} - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { +func makeRequestHandler(config *WatchdogConfig) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { - parts := strings.Split(process, " ") + parts := strings.Split(config.faasProcess, " ") targetCmd := exec.Command(parts[0], parts[1:]...) writer, _ := targetCmd.StdinPipe() @@ -67,7 +36,7 @@ func main() { out, err := targetCmd.CombinedOutput() if err != nil { - if writeDebug == true { + if config.writeDebug == true { log.Println(targetCmd, err) } @@ -78,13 +47,35 @@ func main() { } w.WriteHeader(200) - if writeDebug == true { + if config.writeDebug == true { os.Stdout.Write(out) } - w.Write(out) } - }) + } +} + +func main() { + osEnv := OsEnv{} + readConfig := ReadConfig{} + config := readConfig.Read(osEnv) + + if len(config.faasProcess) == 0 { + log.Panicln("Provide a valid process via fprocess environmental variable.") + return + } + + readTimeout := time.Duration(config.readTimeout) * time.Second + writeTimeout := time.Duration(config.writeTimeout) * time.Second + + s := &http.Server{ + Addr: ":8080", + ReadTimeout: readTimeout, + WriteTimeout: writeTimeout, + MaxHeaderBytes: 1 << 20, + } + + http.HandleFunc("/", makeRequestHandler(&config)) log.Fatal(s.ListenAndServe()) } diff --git a/watchdog/readconfig.go b/watchdog/readconfig.go new file mode 100644 index 0000000000000000000000000000000000000000..56e83bd737a209ddde43994d8fd19a853f73cd83 --- /dev/null +++ b/watchdog/readconfig.go @@ -0,0 +1,69 @@ +package main + +import "strconv" + +// HasEnv provides interface for os.Getenv +type HasEnv interface { + Getenv(key string) string +} + +// ReadConfig constitutes config from env variables +type ReadConfig struct { +} + +func parseBoolValue(val string) bool { + if val == "true" { + return true + } + return true +} + +func parseIntValue(val string) int { + if len(val) > 0 { + parsedVal, parseErr := strconv.Atoi(val) + + if parseErr == nil && parsedVal >= 0 { + + return parsedVal + } + } + return 0 +} + +// Read fetches config from environmental variables. +func (ReadConfig) Read(hasEnv HasEnv) WatchdogConfig { + cfg := WatchdogConfig{ + writeDebug: true, + } + + cfg.faasProcess = hasEnv.Getenv("fprocess") + + readTimeout := parseIntValue(hasEnv.Getenv("read_timeout")) + writeTimeout := parseIntValue(hasEnv.Getenv("write_timeout")) + + if readTimeout == 0 { + cfg.readTimeout = 5 + } else { + cfg.readTimeout = readTimeout + } + if writeTimeout == 0 { + cfg.writeTimeout = 5 + } else { + cfg.writeTimeout = writeTimeout + } + + cfg.writeDebug = parseBoolValue(hasEnv.Getenv("write_debug")) + + return cfg +} + +// WatchdogConfig for the process. +type WatchdogConfig struct { + readTimeout int + writeTimeout int + // faasProcess is the process to exec + faasProcess string + + // writeDebug write console stdout statements to the container + writeDebug bool +}