# name
Monitoring Freifunk Nodes With Prometheus

# nameMap.en
Monitoring Freifunk Nodes With Prometheus

# content
Updated 2020-03-07: We now collect the number of connected clients as well as whether the node is online.

We recently installed a Freifunk node from Freifunk Dreiländereck (FF3L) in our hackerspace. While changing network configuration during the testing phase, the node went offline without us noticing. Since we're using Prometheus for monitoring our space's infrastructure, I went ahead and hacked together a solution which I want to present here:

Idea

Instead of monitoring the node directly, I decided to tap into the status information already collected by the Freifunk community. They are publishing some interesting statistics, however we only really cared about one information: Whether FF3L currently considers the node to be online and reachable.

FF3L publishes these status information at the following endpoint:

https://map.freifunk-3laendereck.net/data/nodes.json

Many (if not all?) Freifunk communities provide such an endpoint, though with some you may have to search for a while to find it.

Implementation

The nodes endpoint yields the information of all nodes at once. Unfortunately, I didn't find a way to reduce the request to specific nodes; if someone knows more about this, don't hesitate to tell me. (As far as I can tell there are multiple implementations of this endpoint, some of which appear to support filters.)

This is how a single node object from the API response looks like:

{
  "nodeinfo": {
    "software": {
      "firmware": {
        "base": "gluon-v2019.1",
        "release": "v2019.1.0+001"
      },
      ...
    },
    "network": {
      ...
    },
    "location": {
      "latitude": ...,
      "longitude": ...
    },
    "system": {
      "role": "node",
      "site_code": "ff3l",
      "domain_code": "3land"
    },
    "node_id": "...",
    "hostname": "...",
    ...
  },
  "flags": {
    "online": true
  },
  "statistics": {
    "uptime": 626614.08,
    "clients": 2,
    ...
  },
  "lastseen": "...",
  "firstseen": "..."
}

We were especially interest in the .flags.online and .statistics.clients fields; our implementation extracts nothing but these two field. The fields .nodeinfo.node_id and .nodeinfo.hostname are suitable for filtering for your own nodes.

Using a bit of "curl|jq magic", we can create a shell script for parsing the data and converting it into a format understood by Prometheus. We added the script as a Textfile Collector to an existing Prometheus Node Exporter instance. The output then looks like this:

# HELP freifunk_node_online 1 if the Freifunk node is online, 0 otherwise
# TYPE freifunk_node_online gauge
# HELP ff3l_node_clients Number of clients connected to the node
# TYPE ff3l_node_clients gauge
freifunk_node_online{node="<node0_id>",hostname="<node0_hostname>"} 1
freifunk_node_clients{node="<node0_id>",hostname="<node0_hostname>"} 2
freifunk_node_online{node="<node1_id>",hostname="<node1_hostname>"} 0
freifunk_node_clients{node="<node1_id>",hostname="<node1_hostname>"} 0

The resulting script can be found on Gitlab.

# contentMap.de
Aktualisiert 2020-03-07: Wir erfassen inzwischen, zusätzlich zur Verfügbarkeit der Node, wieviele aktuell verbunden sind.

Wir haben in unserem Hackerspace neulich einen Freifunk-Knoten von Freifunk Dreiländereck (FF3L) in Betrieb genommen. Dieser ist uns in der Probephase mehrfach bei Änderungen der Netzwerkkonfiguration offline gegangen, ohne das wir es gemerkt hatten. Da wir in unserem Space Prometheus zur Überwachung unserer Infrastruktur einsetzen, habe ich kurzerhand eine entsprechende Lösung gebastelt, die ich hier kurz vorstellen will:

Idee

Anstatt den Knoten direkt zu überwachen, habe ich mich dazu entschieden, die von der Freifunk-Community gesammelten Statusinformationen anzuzapfen. Dort fallen einige interessante Statistiken heraus, aber für uns war ein einziger Wert relevant: Ist der Freifunkknoten laut FF3L momentan online und erreichbar?

Die Statusinformationen lassen sich bei FF3L über den folgenden Endpoint abfragen:

https://map.freifunk-3laendereck.net/data/nodes.json

Viele (vielleicht sogar alle?) Freifunk-Communities haben einen solchen Endpoint, bei manchen muss man eventuell aber etwas suchen, bevor man die API findet.

Umsetzung

Der nodes-Endpoint liefert auf einen Schlag die Informationen zu allen Knoten. Ich habe leider keinen Weg gefunden, die Anfrage direkt auf einzelne Knoten zu reduzieren; wenn hier jemand mehr weiss, würde ich mich über Infos dazu freuen. (Soweit ich das sehen kann, gibt es verschiedene Implementationen, manche scheinen Filter zu unterstützen.)

Für einen einzelnen Knoten sieht diese API-Response etwa so aus:

{
  "nodeinfo": {
    "software": {
      "firmware": {
        "base": "gluon-v2019.1",
        "release": "v2019.1.0+001"
      },
      ...
    },
    "network": {
      ...
    },
    "location": {
      "latitude": ...,
      "longitude": ...
    },
    "system": {
      "role": "node",
      "site_code": "ff3l",
      "domain_code": "3land"
    },
    "node_id": "...",
    "hostname": "...",
    ...
  },
  "flags": {
    "online": true
  },
  "statistics": {
    "uptime": 626614.08,
    "clients": 2,
    ...
  },
  "lastseen": "...",
  "firstseen": "..."
}

Für uns waren hier vor allem die Felder .flags.online und .statistics.clients interessant; mehr lesen wir in unserer Implementation gar nicht aus. Die Felder .nodeinfo.node_id und .nodeinfo.hostname eignen sich, um nach den eigenen Knoten zu filtern.

Mit ein bisschen "curl|jq-Magie" lässt sich das ganze recht einfach in einem Shellscript parsen und in ein Format bringen, mit dem Prometheus etwas anfangen kann. Wir haben das ganze als Textfile Collector an einen Prometheus Node Exporter angebunden. Der Output sieht dann etwa so aus:

# HELP freifunk_node_online 1 if the Freifunk node is online, 0 otherwise
# TYPE freifunk_node_online gauge
# HELP ff3l_node_clients Number of clients connected to the node
# TYPE ff3l_node_clients gauge
freifunk_node_online{node="<node0_id>",hostname="<node0_hostname>"} 1
freifunk_node_clients{node="<node0_id>",hostname="<node0_hostname>"} 2
freifunk_node_online{node="<node1_id>",hostname="<node1_hostname>"} 0
freifunk_node_clients{node="<node1_id>",hostname="<node1_hostname>"} 0

Das Ergebnis gibt es als fertiges Script auf Gitlab.

# contentMap.en
Updated 2020-03-07: We now collect the number of connected clients as well as whether the node is online.

We recently installed a Freifunk node from Freifunk Dreiländereck (FF3L) in our hackerspace. While changing network configuration during the testing phase, the node went offline without us noticing. Since we're using Prometheus for monitoring our space's infrastructure, I went ahead and hacked together a solution which I want to present here:

Idea

Instead of monitoring the node directly, I decided to tap into the status information already collected by the Freifunk community. They are publishing some interesting statistics, however we only really cared about one information: Whether FF3L currently considers the node to be online and reachable.

FF3L publishes these status information at the following endpoint:

https://map.freifunk-3laendereck.net/data/nodes.json

Many (if not all?) Freifunk communities provide such an endpoint, though with some you may have to search for a while to find it.

Implementation

The nodes endpoint yields the information of all nodes at once. Unfortunately, I didn't find a way to reduce the request to specific nodes; if someone knows more about this, don't hesitate to tell me. (As far as I can tell there are multiple implementations of this endpoint, some of which appear to support filters.)

This is how a single node object from the API response looks like:

{
  "nodeinfo": {
    "software": {
      "firmware": {
        "base": "gluon-v2019.1",
        "release": "v2019.1.0+001"
      },
      ...
    },
    "network": {
      ...
    },
    "location": {
      "latitude": ...,
      "longitude": ...
    },
    "system": {
      "role": "node",
      "site_code": "ff3l",
      "domain_code": "3land"
    },
    "node_id": "...",
    "hostname": "...",
    ...
  },
  "flags": {
    "online": true
  },
  "statistics": {
    "uptime": 626614.08,
    "clients": 2,
    ...
  },
  "lastseen": "...",
  "firstseen": "..."
}

We were especially interest in the .flags.online and .statistics.clients fields; our implementation extracts nothing but these two field. The fields .nodeinfo.node_id and .nodeinfo.hostname are suitable for filtering for your own nodes.

Using a bit of "curl|jq magic", we can create a shell script for parsing the data and converting it into a format understood by Prometheus. We added the script as a Textfile Collector to an existing Prometheus Node Exporter instance. The output then looks like this:

# HELP freifunk_node_online 1 if the Freifunk node is online, 0 otherwise
# TYPE freifunk_node_online gauge
# HELP ff3l_node_clients Number of clients connected to the node
# TYPE ff3l_node_clients gauge
freifunk_node_online{node="<node0_id>",hostname="<node0_hostname>"} 1
freifunk_node_clients{node="<node0_id>",hostname="<node0_hostname>"} 2
freifunk_node_online{node="<node1_id>",hostname="<node1_hostname>"} 0
freifunk_node_clients{node="<node1_id>",hostname="<node1_hostname>"} 0

The resulting script can be found on Gitlab.