walkthroughs/howto-k8s-outlier-detection/feapp/main.go (138 lines of code) (raw):
package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"sync"
)
const defaultPort = "8080"
var colorServiceEndpoint = ""
var hostsStats []hostStatusCounter
var counterMutex = &sync.Mutex{}
type hostStatusCounter struct {
HostUID string
Counter struct {
StatusOk int
StatusError int
Total int
}
}
func getServerPort() string {
port := os.Getenv("SERVER_PORT")
if port != "" {
return port
}
return defaultPort
}
func getColorServiceEndpoint() (string, error) {
endpoint := os.Getenv("COLOR_SERVICE_ENDPOINT")
if endpoint != "" {
return endpoint, nil
}
return "", errors.New("COLOR_SERVICE_ENDPOINT is not set")
}
func updateStats(hostUID string, status int) {
counterMutex.Lock()
defer counterMutex.Unlock()
found := false
for i, h := range hostsStats {
if h.HostUID == hostUID {
hostsStats[i].Counter.Total++
if status == http.StatusOK {
hostsStats[i].Counter.StatusOk++
} else {
hostsStats[i].Counter.StatusError++
}
found = true
}
}
if !found {
var newHost hostStatusCounter
if status == http.StatusOK {
newHost = hostStatusCounter{
HostUID: hostUID,
Counter: struct {
StatusOk int
StatusError int
Total int
}{
StatusOk: 1,
StatusError: 0,
Total: 1,
},
}
} else {
newHost = hostStatusCounter{
HostUID: hostUID,
Counter: struct {
StatusOk int
StatusError int
Total int
}{
StatusOk: 0,
StatusError: 1,
Total: 1,
},
}
}
hostsStats = append(hostsStats, newHost)
}
fmt.Println("stats updated: ", hostsStats)
}
func main() {
log.Printf("starting server on port %s\n", getServerPort())
c, err := getColorServiceEndpoint()
if c == "" {
log.Fatalln(err)
}
colorServiceEndpoint = c
http.HandleFunc("/ping", pingHandler)
http.HandleFunc("/color/get", colorGetHandler)
http.HandleFunc("/color/fault", colorFaultHandler)
http.HandleFunc("/color/recover", colorRecoverHandler)
http.HandleFunc("/stats", statsHandler)
http.HandleFunc("/reset_stats", resetStatsHandler)
log.Fatal(http.ListenAndServe(":"+getServerPort(), nil))
}
func pingHandler(w http.ResponseWriter, r *http.Request) {
log.Println("received ping.")
}
func colorServiceHandler(w http.ResponseWriter, r *http.Request, path string) {
log.Printf("received color/%s request.", path)
resp, err := http.Get(fmt.Sprintf("http://%s/%s", colorServiceEndpoint, path))
if err != nil {
log.Printf("error in getting response: %s\n", err)
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, err.Error())
return
}
if path == "get" {
updateStats(resp.Header.Get("HostUID"), resp.StatusCode)
}
body, err := ioutil.ReadAll(resp.Body)
w.WriteHeader(resp.StatusCode)
fmt.Fprintf(w, "%s\n", string(body))
}
func colorGetHandler(w http.ResponseWriter, r *http.Request) {
colorServiceHandler(w, r, "get")
}
func colorFaultHandler(w http.ResponseWriter, r *http.Request) {
colorServiceHandler(w, r, "fault")
}
func colorRecoverHandler(w http.ResponseWriter, r *http.Request) {
colorServiceHandler(w, r, "recover")
}
func statsHandler(w http.ResponseWriter, r *http.Request) {
json, _ := json.Marshal(hostsStats)
fmt.Fprintf(w, "%s\n", string(json))
}
func resetStatsHandler(w http.ResponseWriter, r *http.Request) {
counterMutex.Lock()
defer counterMutex.Unlock()
hostsStats = nil
fmt.Fprintf(w, "stats cleared.\n")
}