lobby2/api/main.go
Adam Štrauch 5dd38b7f18
All checks were successful
Tests / test (push) Successful in 20s
Prometheus service discovery
2024-12-19 21:10:34 +01:00

149 lines
3.8 KiB
Go

package api
import (
"log"
"net/http"
"strings"
_ "gitea.ceperka.net/rosti/lobby2/docs" // This line is necessary for swag to find your docs!
"gitea.ceperka.net/rosti/lobby2/nodes"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
echoSwagger "github.com/swaggo/echo-swagger"
)
// @title Lobby2 API
// @version 2.0
// @description API of Lobby 2 project that helps to discover and connect to other nodes and their services.
// @BasePath /
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
type API struct {
listen string
token string
np *nodes.NodesProcessor
e *echo.Echo
}
func NewAPI(np *nodes.NodesProcessor, listen string, token string) *API {
return &API{
listen: listen,
token: token,
np: np,
}
}
func (a *API) Run() error {
if a.token == "" {
log.Fatalln("TOKEN is required")
}
a.e = echo.New()
a.e.Use(middleware.Logger())
a.e.Use(tokenMiddlware(a.token))
a.e.GET("/", func(c echo.Context) error {
return c.Redirect(http.StatusTemporaryRedirect, "/swagger/index.html")
})
a.e.GET("/swagger/*", echoSwagger.WrapHandler)
a.e.GET("/nodes", a.listHandler)
a.e.GET("/nodes/:hostname", a.getHandler)
a.e.POST("/nodes/:hostname", a.refreshHandler)
a.e.GET("/prometheus/:service", a.prometheusHandler)
// Start the server in a goroutine so that it doesn't block the signal listening
return a.e.Start(a.listen)
}
// @Summary List of nodes
// @Description List of all discovered nodes and their labels.
// @Produce application/json
// @Success 200 {object} nodes.Nodes "List of nodes"
// @Failure 401 {object} Message "Forbidden access"
// @Security Bearer
// @Router /nodes [get]
func (a *API) listHandler(c echo.Context) error {
return c.JSON(http.StatusOK, a.np.List())
}
// @Summary Get node
// @Description Return one nodes based on given hostname
// @Produce application/json
// @Param hostname path string true "Node hostname"
// @Success 200 {array} nodes.Node "Node details"
// @Failure 401 {object} Message "Forbidden access"
// @Security Bearer
// @Router /nodes/{hostname} [get]
func (a *API) getHandler(c echo.Context) error {
hostname := c.Param("hostname")
node, ok := a.np.Get(hostname)
if !ok {
return echo.NewHTTPError(http.StatusNotFound, "node not found")
}
return c.JSON(http.StatusOK, node)
}
// @Summary Refresh node
// @Description Send new data or update existing data about a node
// @Produce application/json
// @Param hostname path string true "Node hostname"
// @Param labels body nodes.Labels true "Node labels"
// @Param kv body nodes.KV true "Key-value"
// @Success 200 {array} nodes.Node "Node details"
// @Failure 401 {object} Message "Forbidden access"
// @Security Bearer
// @Router /nodes/{hostname} [post]
func (a *API) refreshHandler(c echo.Context) error {
hostname := c.Param("hostname")
params := params{}
err := c.Bind(&params)
if err != nil {
return c.JSON(http.StatusBadRequest, Message{Message: err.Error()})
}
a.np.Refresh(hostname, params.Labels, params.KV)
return c.NoContent(http.StatusNoContent)
}
// @Summary Prometheus service discovery
// @Description Return one nodes based on given hostname
// @Produce application/json
// @Success 200 {array} []prometheusDiscovery "Node details"
// @Failure 401 {object} Message "Forbidden access"
// @Security Bearer
// @Router /nodes/{hostname} [get]
func (a *API) prometheusHandler(c echo.Context) error {
ss := c.QueryParam("service")
ns := a.np.List()
pds := []prometheusDiscovery{
{
Labels: nodes.Labels{},
Targets: []string{},
},
}
for _, node := range ns {
v, ok := node.KV["prometheus_exporters"]
if ok {
services := strings.Split(v, ",")
for _, service := range services {
if ss == service {
pds[0].Targets = append(pds[0].Targets, node.HostName)
}
}
}
}
return c.JSONPretty(http.StatusOK, pds, " ")
}