mDNS discovery (HTTP is optional)
This commit is contained in:
parent
9a97bea4b2
commit
b98278d506
6 changed files with 136 additions and 21 deletions
13
collector.go
13
collector.go
|
@ -100,7 +100,7 @@ var (
|
|||
promDescWifiApChannel = prometheus.NewDesc(
|
||||
metricPrefix+"wifi_ap_channel",
|
||||
"channel number",
|
||||
[]string{"ap_id", "ap_band", "ap_name", "state", "channel_type"}, nil)
|
||||
[]string{"ap_id", "ap_band", "ap_name", "channel_type"}, nil)
|
||||
promDescWifiApStations = prometheus.NewDesc(
|
||||
metricPrefix+"wifi_stations",
|
||||
"number of stations connected to the AP",
|
||||
|
@ -294,7 +294,10 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) {
|
|||
|
||||
if capabilities, ok := ap.Capabilities[ap.Config.Band]; ok {
|
||||
labels := prometheus.Labels{}
|
||||
labels["band"] = ap.Config.Band
|
||||
labels["ap_id"] = apID
|
||||
labels["ap_band"] = ap.Config.Band
|
||||
labels["ap_name"] = ap.Name
|
||||
labels["ap_state"] = ap.Status.State
|
||||
|
||||
for k, v := range capabilities {
|
||||
labels[k] = strconv.FormatBool(v)
|
||||
|
@ -312,13 +315,11 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) {
|
|||
apID,
|
||||
ap.Config.Band,
|
||||
ap.Name,
|
||||
ap.Status.State,
|
||||
"primary")
|
||||
c.collectGauge(ch, ap.Status.SecondaryChannel, promDescWifiApChannel,
|
||||
apID,
|
||||
ap.Config.Band,
|
||||
ap.Name,
|
||||
ap.Status.State,
|
||||
"secondary")
|
||||
ch <- prometheus.MustNewConstMetric(promDescWifiApStations, prometheus.GaugeValue, float64(len(ap.Stations)),
|
||||
apID,
|
||||
|
@ -500,7 +501,7 @@ func (c *Collector) toBool(b *bool) bool {
|
|||
return b != nil && *b
|
||||
}
|
||||
|
||||
func NewCollector(filename string, hostDetails, debug bool) *Collector {
|
||||
func NewCollector(filename string, discovery fbx.FreeboxDiscovery, hostDetails, debug bool) *Collector {
|
||||
result := &Collector{
|
||||
hostDetails: hostDetails,
|
||||
}
|
||||
|
@ -515,7 +516,7 @@ func NewCollector(filename string, hostDetails, debug bool) *Collector {
|
|||
} else {
|
||||
log.Info.Println("Could not find the configuration file", filename)
|
||||
newConfig = true
|
||||
result.freebox, err = fbx.NewFreeboxConnection(debug)
|
||||
result.freebox, err = fbx.NewFreeboxConnectionFromServiceDiscovery(debug, discovery)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/mdns"
|
||||
"github.com/trazfr/freebox-exporter/log"
|
||||
)
|
||||
|
||||
|
@ -22,22 +24,25 @@ type FreeboxAPIVersion struct {
|
|||
|
||||
const (
|
||||
apiVersionURL = "http://mafreebox.freebox.fr/api_version"
|
||||
mdnsService = "_fbx-api._tcp"
|
||||
)
|
||||
|
||||
func NewFreeboxAPIVersionHTTP(client *FreeboxHttpClient) (*FreeboxAPIVersion, error) {
|
||||
log.Debug.Println("GET", apiVersionURL)
|
||||
type FreeboxDiscovery int
|
||||
|
||||
// get api version
|
||||
r, err := client.client.Get(apiVersionURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
const (
|
||||
// FreeboxDiscoveryHTTP Freebox discovery by call to http://mafreebox.freebox.fr/api_version
|
||||
FreeboxDiscoveryHTTP FreeboxDiscovery = iota
|
||||
// FreeboxDiscoveryMDNS Freebox discovery by mDNS on service _fbx-api._tcp
|
||||
FreeboxDiscoveryMDNS
|
||||
)
|
||||
|
||||
func NewFreeboxAPIVersion(client *FreeboxHttpClient, discovery FreeboxDiscovery) (*FreeboxAPIVersion, error) {
|
||||
result := &FreeboxAPIVersion{}
|
||||
if err := json.NewDecoder(r.Body).Decode(result); err != nil {
|
||||
|
||||
if err := result.getDiscovery(discovery)(client); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.IsValid() == false {
|
||||
return nil, errors.New("Could not get the API version")
|
||||
}
|
||||
|
@ -77,3 +82,92 @@ func (f *FreeboxAPIVersion) GetURL(path string, miscPath ...interface{}) (string
|
|||
}
|
||||
return fmt.Sprintf("https://%s:%d%sv%s/"+path, args...), nil
|
||||
}
|
||||
|
||||
func (f *FreeboxAPIVersion) getDiscovery(discovery FreeboxDiscovery) func(client *FreeboxHttpClient) error {
|
||||
function := func(*FreeboxHttpClient) error {
|
||||
return errors.New("Wrong discovery argument")
|
||||
}
|
||||
|
||||
switch discovery {
|
||||
case FreeboxDiscoveryHTTP:
|
||||
function = f.newFreeboxAPIVersionHTTP
|
||||
case FreeboxDiscoveryMDNS:
|
||||
function = f.newFreeboxAPIVersionMDNS
|
||||
default:
|
||||
}
|
||||
|
||||
return function
|
||||
}
|
||||
|
||||
func (f *FreeboxAPIVersion) newFreeboxAPIVersionHTTP(client *FreeboxHttpClient) error {
|
||||
log.Info.Println("Freebox discovery: GET", apiVersionURL)
|
||||
|
||||
// HTTP GET api version
|
||||
r, err := client.client.Get(apiVersionURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(f); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FreeboxAPIVersion) newFreeboxAPIVersionMDNS(*FreeboxHttpClient) error {
|
||||
log.Info.Println("Freebox discovery: mDNS")
|
||||
entries := make(chan *mdns.ServiceEntry, 4)
|
||||
|
||||
// mDNS lookup
|
||||
go func() {
|
||||
defer close(entries)
|
||||
if err := mdns.Lookup(mdnsService, entries); err != nil {
|
||||
log.Error.Println("mDNS lookup failed:", err)
|
||||
}
|
||||
log.Debug.Println("End of mDNS lookup")
|
||||
}()
|
||||
|
||||
for entry := range entries {
|
||||
deviceName := entry.Name
|
||||
idx := strings.Index(deviceName, ".")
|
||||
if idx >= 0 {
|
||||
deviceName = deviceName[0:idx]
|
||||
}
|
||||
deviceName = strings.ReplaceAll(deviceName, "\\", "")
|
||||
|
||||
*f = FreeboxAPIVersion{
|
||||
DeviceName: deviceName,
|
||||
}
|
||||
for i := range entry.InfoFields {
|
||||
kv := strings.SplitN(entry.InfoFields[i], "=", 2)
|
||||
if len(kv) != 2 {
|
||||
break
|
||||
}
|
||||
switch kv[0] {
|
||||
case "api_domain":
|
||||
f.APIDomain = kv[1]
|
||||
case "uid":
|
||||
f.UID = kv[1]
|
||||
case "https_available":
|
||||
f.HTTPSAvailable = (kv[1] == "1")
|
||||
case "https_port":
|
||||
port, _ := strconv.ParseUint(kv[1], 10, 16)
|
||||
f.HTTPSPort = uint16(port)
|
||||
case "api_version":
|
||||
f.APIVersion = kv[1]
|
||||
case "api_base_url":
|
||||
f.APIBaseURL = kv[1]
|
||||
case "device_type":
|
||||
f.DeviceType = kv[1]
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
if f.IsValid() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("MDNS timeout")
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ type FreeboxConnection struct {
|
|||
* FreeboxConnection
|
||||
*/
|
||||
|
||||
func NewFreeboxConnection(debug bool) (*FreeboxConnection, error) {
|
||||
func NewFreeboxConnectionFromServiceDiscovery(debug bool, discovery FreeboxDiscovery) (*FreeboxConnection, error) {
|
||||
client := NewFreeboxHttpClient(debug)
|
||||
apiVersion, err := NewFreeboxAPIVersionHTTP(client)
|
||||
apiVersion, err := NewFreeboxAPIVersion(client, discovery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
5
go.mod
5
go.mod
|
@ -2,4 +2,7 @@ module github.com/trazfr/freebox-exporter
|
|||
|
||||
go 1.16
|
||||
|
||||
require github.com/prometheus/client_golang v1.9.0
|
||||
require (
|
||||
github.com/hashicorp/mdns v1.0.3
|
||||
github.com/prometheus/client_golang v1.9.0
|
||||
)
|
||||
|
|
10
go.sum
10
go.sum
|
@ -119,6 +119,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
|||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/mdns v1.0.3 h1:hPneYJlzSjxFBmUlnDGXRykxBZ++dQAJhU57gCO7TzI=
|
||||
github.com/hashicorp/mdns v1.0.3/go.mod h1:P9sIDVQGUBr2GtS4qS2QCBdtgqP7TBt6d8looU5l5r4=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
|
@ -153,6 +155,8 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
|
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
|
||||
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
|
@ -274,6 +278,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -299,6 +304,8 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
|||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -307,6 +314,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -322,6 +330,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -345,6 +354,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
13
main.go
13
main.go
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
|
||||
"github.com/trazfr/freebox-exporter/fbx"
|
||||
"github.com/trazfr/freebox-exporter/log"
|
||||
)
|
||||
|
||||
|
@ -18,7 +19,7 @@ func usage(err error) {
|
|||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Error:", err)
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[options] <configfile>")
|
||||
fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[options] <api_token_file>")
|
||||
fmt.Fprintln(os.Stderr)
|
||||
fmt.Fprintln(os.Stderr, "Options:")
|
||||
flag.PrintDefaults()
|
||||
|
@ -28,12 +29,13 @@ func usage(err error) {
|
|||
func main() {
|
||||
debugPtr := flag.Bool("debug", false, "enable the debug mode")
|
||||
hostDetailsPtr := flag.Bool("hostDetails", false, "get details about the hosts connected to wifi and ethernet. This increases the number of metrics")
|
||||
httpDiscoveryPtr := flag.Bool("httpDiscovery", false, "use http://mafreebox.freebox.fr/api_version to discover the Freebox at the first run (default: mDNS)")
|
||||
listenPtr := flag.String("listen", ":9091", "listen to address")
|
||||
flag.Parse()
|
||||
|
||||
args := flag.Args()
|
||||
if len(args) < 1 {
|
||||
usage(errors.New("configfile not defined"))
|
||||
usage(errors.New("api_token_file not defined"))
|
||||
} else if len(args) > 1 {
|
||||
usage(errors.New("too many arguments"))
|
||||
}
|
||||
|
@ -42,7 +44,12 @@ func main() {
|
|||
} else {
|
||||
log.Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
|
||||
}
|
||||
collector := NewCollector(args[0], *hostDetailsPtr, *debugPtr)
|
||||
discovery := fbx.FreeboxDiscoveryMDNS
|
||||
if *httpDiscoveryPtr {
|
||||
discovery = fbx.FreeboxDiscoveryHTTP
|
||||
}
|
||||
|
||||
collector := NewCollector(args[0], discovery, *hostDetailsPtr, *debugPtr)
|
||||
defer collector.Close()
|
||||
|
||||
prometheus.MustRegister(collector)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue