Skip to content

Commit

Permalink
[TASK] add output prometheus-sd (service discovery) (#213)
Browse files Browse the repository at this point in the history
  • Loading branch information
genofire authored Apr 14, 2022
1 parent 64b9cfe commit aa9d94f
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 1 deletion.
2 changes: 1 addition & 1 deletion cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestReadConfig(t *testing.T) {
assert.Contains(config.Respondd.Sites["ffhb"].Domains, "city")

// Test output plugins
assert.Len(config.Nodes.Output, 5)
assert.Len(config.Nodes.Output, 6)
outputs := config.Nodes.Output["meshviewer"].([]map[string]interface{})
assert.Len(outputs, 1)
meshviewer := outputs[0]
Expand Down
13 changes: 13 additions & 0 deletions config_example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,19 @@ path = "/var/www/html/meshviewer/data/nodelist.json"
# WARNING: if it is not set, it will publish contact information of other persons
no_owner = true

# definition for prometheus-sd.json
[[nodes.output.prometheus-sd]]
enable = true
path = "/var/www/html/meshviewer/data/prometheus-sd.json"
# ip = lates recieved ip, node_id = node id from host
target_address = "ip"

# Labels of the data (optional)
[nodes.output.prometheus-sd.labels]
#labelname1 = "labelvalue 1"
## some useful e.g.:
#hosts = "ffhb"
#service = "yanic"

# definition for raw.json
[[nodes.output.raw]]
Expand Down
61 changes: 61 additions & 0 deletions docs/docs_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,67 @@ path = "/var/www/html/meshviewer/data/nodelist.json"
```
{% endmethod %}



## [[nodes.output.prometheus-sd]]
{% method %}
The Prometheus Service Discovery (SD) output is a output with the list of addresses of the nodes to use them in later exporter by prometheus.
For usage in Prometheus read there Documentation [Use file-based service discovery to discover scrape targets](https://prometheus.io/docs/guides/file-sd/).
{% sample lang="toml" %}
```toml
[[nodes.output.prometheus-sd]]
enable = false
path = "/var/www/html/meshviewer/data/prometheus-sd.json"
target_address = "ip"

[nodes.output.prometheus-sd.labels]
labelname1 = "labelvalue 1"
# some useful e.g.:
hosts = "ffhb"
service = "yanic"
```
{% endmethod %}


### path
{% method %}
The path, where to store prometheus-sd.json
{% sample lang="toml" %}
```toml
path = "/var/www/html/meshviewer/data/prometheus-sd.json"
```
{% endmethod %}

### target_address
{% method %}
In the prometheus-sd.json the usage of which information of the node as targets (address).

Use the `node_id` as value, to put the Node ID into the target list as address.
Use the `ip` as value to put the last IP address into the target list from where the respondd message is recieved (maybe a link-local address).
Default value is `ip`.

{% sample lang="toml" %}
```toml
path = "/var/www/html/meshviewer/data/prometheus-sd.json"
```
{% endmethod %}


### [nodes.output.prometheus-sd.labels]
{% method %}
You could optional set manuelle labels with inserting into a prometheus-sd.json.
Useful if you want to identify the yanic instance when you use multiple own on the same prometheus database (e.g. multisites).

{% sample lang="toml" %}
```toml
labelname1 = "labelvalue 1"
# some useful e.g.:
hosts = "ffhb"
service = "yanic"
```
{% endmethod %}


## [[nodes.output.raw]]
{% method %}
This output takes the respondd response as sent by the node and includes it in a JSON document.
Expand Down
1 change: 1 addition & 0 deletions output/all/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
_ "yanic/output/meshviewer"
_ "yanic/output/meshviewer-ffrgb"
_ "yanic/output/nodelist"
_ "yanic/output/prometheus-sd"
_ "yanic/output/raw"
_ "yanic/output/raw-jsonl"
)
93 changes: 93 additions & 0 deletions output/prometheus-sd/output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package prometheus_sd

import (
"errors"

"yanic/output"
"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 (
TargetAddressIP TargetAddressType = "ip"
TargetAddressNodeID TargetAddressType = "node_id"
)

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]interface{} `json:"labels,omitempty"`
}

func (o *Output) Save(nodes *runtime.Nodes) {
nodes.RLock()
defer nodes.RUnlock()

targets := &Targets{
Targets: []string{},
Labels: o.labels,
}
if o.targetType == TargetAddressNodeID {
for _, n := range nodes.List {
if ni := n.Nodeinfo; ni != nil {
targets.Targets = append(targets.Targets, ni.NodeID)
}
}
} else {
for _, n := range nodes.List {
if addr := n.Address; addr != nil {
targets.Targets = append(targets.Targets, addr.IP.String())
}
}
}

runtime.SaveJSON([]interface{}{targets}, o.path)
}
90 changes: 90 additions & 0 deletions output/prometheus-sd/output_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package prometheus_sd

import (
"os"
"net"
"testing"

"github.com/stretchr/testify/assert"
"yanic/data"
"yanic/runtime"
)

func TestOutput(t *testing.T) {
assert := assert.New(t)

out, err := Register(map[string]interface{}{})
assert.Error(err)
assert.Nil(out)

nodes := runtime.NewNodes(&runtime.NodesConfig{})
ipAddress, err := net.ResolveUDPAddr("udp6", "[fe80::20de:a:3ac%eth0]:1001")
assert.NoError(err)
nodes.AddNode(&runtime.Node{
Online: true,
Address: ipAddress,
Nodeinfo: &data.Nodeinfo{
NodeID: "node_a",
Network: data.Network{
Mac: "node:a:mac",
Mesh: map[string]*data.NetworkInterface{
"bat0": {
Interfaces: struct {
Wireless []string `json:"wireless,omitempty"`
Other []string `json:"other,omitempty"`
Tunnel []string `json:"tunnel,omitempty"`
}{
Wireless: []string{"node:a:mac:wifi"},
Tunnel: []string{"node:a:mac:vpn"},
Other: []string{"node:a:mac:lan"},
},
},
},
},
},
Neighbours: &data.Neighbours{
NodeID: "node_a",
Batadv: map[string]data.BatadvNeighbours{
"node:a:mac:wifi": {
Neighbours: map[string]data.BatmanLink{
"node:b:mac:wifi": {Tq: 153},
},
},
"node:a:mac:lan": {
Neighbours: map[string]data.BatmanLink{
"node:b:mac:lan": {Tq: 51},
},
},
},
},
})

// IP
out, err = Register(map[string]interface{}{
"path": "/tmp/prometheus_sd.json",
})
os.Remove("/tmp/prometheus_sd.json")
assert.NoError(err)
assert.NotNil(out)

out.Save(nodes)
_, err = os.Stat("/tmp/prometheus_sd.json")
assert.NoError(err)

// NodeID
out, err = Register(map[string]interface{}{
"target_address": "node_id",
"path": "/tmp/prometheus_sd.json",
"labels": map[string]interface{}{
"hosts": "ffhb",
"service": "yanic",
},
})
os.Remove("/tmp/prometheus_sd.json")
assert.NoError(err)
assert.NotNil(out)

out.Save(nodes)
_, err = os.Stat("/tmp/prometheus_sd.json")
assert.NoError(err)
}

0 comments on commit aa9d94f

Please sign in to comment.