125 lines
3.0 KiB
Go
125 lines
3.0 KiB
Go
package prometheus
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/bdlm/log"
|
|
|
|
"github.com/FreifunkBremen/yanic/respond"
|
|
"github.com/FreifunkBremen/yanic/runtime"
|
|
)
|
|
|
|
type Exporter struct {
|
|
config Config
|
|
srv *http.Server
|
|
coll *respond.Collector
|
|
nodes *runtime.Nodes
|
|
}
|
|
|
|
func (ex *Exporter) ServeHTTP(res http.ResponseWriter, req *http.Request) {
|
|
var ip net.IP
|
|
nodeID := ""
|
|
|
|
queryValues := req.URL.Query()
|
|
|
|
if nodeIDs := queryValues["node_id"]; len(nodeIDs) > 0 {
|
|
nodeID = nodeIDs[0]
|
|
node, ok := ex.nodes.List[nodeID]
|
|
if !ok || node.Address == nil {
|
|
http.Error(res, "not able to get node by cached nodeid", http.StatusNotFound)
|
|
return
|
|
}
|
|
ip = node.Address.IP
|
|
if ex.writeNode(res, node, true) {
|
|
log.WithFields(map[string]interface{}{
|
|
"ip": ip,
|
|
"node_id": nodeID,
|
|
}).Debug("take node from cache")
|
|
return
|
|
}
|
|
} else if ipstr := queryValues["ip"]; len(ipstr) > 0 {
|
|
ip = net.ParseIP(ipstr[0])
|
|
if ip == nil {
|
|
http.Error(res, "not able to parse ip address", http.StatusBadRequest)
|
|
return
|
|
}
|
|
node_select := ex.nodes.Select(func(n *runtime.Node) bool {
|
|
n_addr := n.Address
|
|
nodeID = n.Nodeinfo.NodeID
|
|
return n_addr != nil && ip.Equal(n_addr.IP)
|
|
})
|
|
if len(node_select) == 1 {
|
|
if ex.writeNode(res, node_select[0], true) {
|
|
log.WithFields(map[string]interface{}{
|
|
"ip": ip,
|
|
"node_id": nodeID,
|
|
}).Debug("take node from cache")
|
|
return
|
|
}
|
|
} else if len(node_select) > 1 {
|
|
log.Error("strange count of nodes")
|
|
}
|
|
} else {
|
|
http.Error(res, "please request with ?ip= or ?node_id=", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// send request
|
|
ex.coll.SendPacket(ip)
|
|
|
|
// wait
|
|
log.WithFields(map[string]interface{}{
|
|
"ip": ip,
|
|
"node_id": nodeID,
|
|
}).Debug("waited for")
|
|
time.Sleep(ex.config.Wait.Duration)
|
|
|
|
// result
|
|
node, ok := ex.nodes.List[nodeID]
|
|
if !ok {
|
|
http.Error(res, "not able to fetch this node", http.StatusGatewayTimeout)
|
|
return
|
|
}
|
|
ex.writeNode(res, node, false)
|
|
}
|
|
|
|
func (ex *Exporter) writeNode(res http.ResponseWriter, node *runtime.Node, dry bool) bool {
|
|
logger := log.WithField("database", "prometheus")
|
|
if nodeinfo := node.Nodeinfo; nodeinfo != nil {
|
|
logger = logger.WithField("node_id", nodeinfo.NodeID)
|
|
}
|
|
|
|
if !time.Now().Before(node.Lastseen.GetTime().Add(ex.config.Outdated.Duration)) {
|
|
if dry {
|
|
return false
|
|
}
|
|
m := Metric{Labels: MetricLabelsFromNode(node), Name: "yanic_node_up", Value: 0}
|
|
str, err := m.String()
|
|
if err == nil {
|
|
_, err = io.WriteString(res, str+"\n")
|
|
}
|
|
if err != nil {
|
|
logger.Warnf("not able to get metrics from node: %s", err)
|
|
http.Error(res, "not able to generate metric from node", http.StatusInternalServerError)
|
|
}
|
|
return false
|
|
}
|
|
|
|
metrics := MetricsFromNode(ex.nodes, node)
|
|
for _, m := range metrics {
|
|
str, err := m.String()
|
|
if err == nil {
|
|
_, err = io.WriteString(res, str+"\n")
|
|
}
|
|
if err != nil {
|
|
logger.Warnf("not able to get metrics from node: %s", err)
|
|
http.Error(res, "not able to generate metric from node", http.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|