package process import ( "encoding/json" "fmt" "net/http" "runtime" "strings" "time" "github.com/gin-gonic/gin" ) type hash map[string]interface{} func (a *Server) instances() []hash { resp := make([]hash, 0) now := time.Now() for _, v := range a.feta.manager.ListInstances() { i := make(hash) // FIXME figure out why a very short lock here deadlocks v.Lock() i["hostname"] = v.Hostname i["nextCheck"] = v.NextFetch.UTC().Format(time.RFC3339) i["nextCheckAfter"] = (-1 * now.Sub(v.NextFetch)).String() i["successCount"] = v.SuccessCount i["errorCount"] = v.ErrorCount i["identified"] = v.Identified i["status"] = v.Status() i["software"] = "unknown" i["version"] = "unknown" if v.Identified { i["software"] = v.ServerImplementationString i["version"] = v.ServerVersionString } v.Unlock() resp = append(resp, i) } return resp } func (a *Server) instanceSummary() map[string]int { resp := make(map[string]int) for _, v := range a.feta.manager.ListInstances() { v.Lock() resp[fmt.Sprintf("STATUS_%s", v.Status())]++ if v.ServerImplementationString != "" { //FIXME(sneak) sanitize this to a-z0-9, it is server-provided resp[fmt.Sprintf("SOFTWARE_%s", strings.ToUpper(v.ServerImplementationString))]++ } v.Unlock() } return resp } func (a *Server) getInstanceListHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { result := &gin.H{ "instances": a.instances(), } json, err := json.Marshal(result) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(json) } } func (a *Server) getIndexHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { index := &gin.H{ "server": &gin.H{ "now": time.Now().UTC().Format(time.RFC3339), "uptime": a.feta.uptime().String(), "goroutines": runtime.NumGoroutine(), "goversion": runtime.Version(), "version": a.feta.version, "buildarch": a.feta.buildarch, }, "instanceSummary": a.instanceSummary(), } json, err := json.Marshal(index) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(json) } } func (a *Server) getHealthCheckHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { resp := &gin.H{ "status": "ok", "now": time.Now().UTC().Format(time.RFC3339), "uptime": a.feta.uptime().String(), } json, err := json.Marshal(resp) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(json) } }