feta/process/handlers.go

153 lines
3.5 KiB
Go

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, " ")
}