package process import ( "fmt" "net/http" "runtime" "strings" "time" u "git.eeqj.de/sneak/goutil" "github.com/flosch/pongo2" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/labstack/echo" ) 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) // TODO move this locking onto a method on Instance that just // returns a new hash // FIXME figure out why a very short lock here deadlocks v.Lock() i["hostname"] = v.Hostname i["uuid"] = v.UUID.String() 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 //this only locks the FSM, not the whole instance struct 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) } for _, item := range resp { count, err := a.feta.dbm.TootCountForHostname(item["hostname"].(string)) item["tootCount"] = 0 if err != nil { item["tootCount"] = count } } 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 != "" { impl := strings.ToUpper(u.FilterToAlnum(v.ServerImplementationString)) resp[fmt.Sprintf("SOFTWARE_%s", impl)]++ } 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) notFoundHandler(c echo.Context) error { return c.String(http.StatusNotFound, "404 not found") } func (a *Server) instanceHandler(c echo.Context) error { tu := c.Param("uuid") u, err := uuid.Parse(tu) if err != nil { return a.notFoundHandler(c) } tc := pongo2.Context{} instances := a.feta.manager.ListInstances() found := false for _, item := range instances { if item.UUID == u { tc["instance"] = item found = true } } if !found { return a.notFoundHandler(c) } return c.Render(http.StatusOK, "instance.html", tc) } func (a *Server) indexHandler(c echo.Context) error { tc := pongo2.Context{ "time": time.Now().UTC().Format(time.RFC3339Nano), "gitrev": a.feta.version, "instances": a.instances(), } return c.Render(http.StatusOK, "index.html", tc) } func (a *Server) statsHandler(c echo.Context) error { 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(), } return c.JSONPretty(http.StatusOK, index, " ") } func (a *Server) healthCheckHandler(c echo.Context) error { resp := &gin.H{ "status": "ok", "now": time.Now().UTC().Format(time.RFC3339), "uptime": a.feta.uptime().String(), } return c.JSONPretty(http.StatusOK, resp, " ") }