yanic/output/prometheus-sd/output.go

175 lines
3.9 KiB
Go

package prometheus_sd
import (
"errors"
"fmt"
"net"
"strconv"
"github.com/FreifunkBremen/yanic/output"
"github.com/FreifunkBremen/yanic/runtime"
)
type Output struct {
output.Output
path string
targetType TargetAddressType
labels map[string]interface{}
}
type Config map[string]interface{}
func (c Config) Path() string {
if path, ok := c["path"]; ok {
return path.(string)
}
return ""
}
type TargetAddressType string
const (
TargetAddressNodeID TargetAddressType = "node_id"
TargetAddressIP TargetAddressType = "ip"
TargetAddressIPPublish TargetAddressType = "ip-publish"
)
type TargetAddressFunc func(*runtime.Node) []string
var TargetAddressTypeFuncs = map[TargetAddressType]TargetAddressFunc{
TargetAddressNodeID: func(n *runtime.Node) []string {
if ni := n.Nodeinfo; ni != nil {
return []string{ni.NodeID}
}
return []string{}
},
TargetAddressIP: func(n *runtime.Node) []string {
if addr := n.Address; addr != nil {
return []string{addr.IP.String()}
}
return []string{}
},
TargetAddressIPPublish: func(n *runtime.Node) []string {
addresses := []string{}
if nodeinfo := n.Nodeinfo; nodeinfo != nil {
for _, addr := range nodeinfo.Network.Addresses {
if net.ParseIP(addr).IsGlobalUnicast() {
addresses = append(addresses, addr)
}
}
}
return addresses
},
}
func (c Config) TargetAddress() TargetAddressType {
if v, ok := c["target_address"]; ok {
return TargetAddressType(v.(string))
}
return TargetAddressIP
}
func (c Config) Labels() map[string]interface{} {
if v, ok := c["labels"]; ok {
return v.(map[string]interface{})
}
return nil
}
func init() {
output.RegisterAdapter("prometheus-sd", Register)
}
func Register(configuration map[string]interface{}) (output.Output, error) {
config := Config(configuration)
if path := config.Path(); path != "" {
return &Output{
path: path,
targetType: config.TargetAddress(),
labels: config.Labels(),
}, nil
}
return nil, errors.New("no path given")
}
type Targets struct {
Targets []string `json:"targets"`
Labels map[string]string `json:"labels,omitempty"`
}
func toTargets(n *runtime.Node, defaultLabels map[string]interface{}, targetFunc TargetAddressFunc) *Targets {
target := targetFunc(n)
if len(target) <= 0 {
return nil
}
labels := map[string]string{}
for k, v := range defaultLabels {
vS := v.(string)
labels[k] = vS
}
if ni := n.Nodeinfo; ni != nil {
labels["node_id"] = ni.NodeID
labels["hostname"] = ni.Hostname
// model
if model := ni.Hardware.Model; model != "" {
labels["model"] = model
}
// system
if siteCode := ni.System.SiteCode; siteCode != "" {
labels["site_code"] = siteCode
}
if domainCode := ni.System.DomainCode; domainCode != "" {
labels["domain_code"] = domainCode
}
if primaryDomainCode := ni.System.PrimaryDomainCode; primaryDomainCode != "" {
labels["primary_domain_code"] = primaryDomainCode
}
// owner
if owner := ni.Owner; owner != nil {
labels["owner"] = owner.Contact
}
// location
if location := ni.Location; location != nil {
labels["latitude"] = fmt.Sprintf("%v", location.Latitude)
labels["longitude"] = fmt.Sprintf("%v", location.Longitude)
}
// wireless - airtime
if wifi := ni.Wireless; wifi != nil {
labels["wifi_txpower24"] = strconv.Itoa(int(wifi.TxPower24))
labels["wifi_channel24"] = strconv.Itoa(int(wifi.Channel24))
labels["wifi_txpower5"] = strconv.Itoa(int(wifi.TxPower5))
labels["wifi_channel5"] = strconv.Itoa(int(wifi.Channel5))
}
}
return &Targets{
Targets: target,
Labels: labels,
}
}
func (o *Output) Save(nodes *runtime.Nodes) {
nodes.RLock()
defer nodes.RUnlock()
targetFunc, ok := TargetAddressTypeFuncs[o.targetType]
if !ok {
return
}
targets := []*Targets{}
for _, n := range nodes.List {
if t := toTargets(n, o.labels, targetFunc); t != nil {
targets = append(targets, t)
}
}
runtime.SaveJSON(targets, o.path)
}