Browse Source

add documentation

pull/1/head
Nils Decker 9 years ago
parent
commit
e12f307451
  1. 157
      README.md
  2. 37
      fritzbox_upnp/service.go
  3. 37
      main.go

157
README.md

@ -0,0 +1,157 @@
# Fritz!Box Upnp statistics exporter for prometheus
This exporter exports some variables from an
[AVM Fritzbox](http://avm.de/produkte/fritzbox/)
to prometheus.
This exporter is tested with a Fritzbox 7490 and software version 06.51.
## Building
go get github.com/ndecker/fritzbox_exporter/
cd $GOROOT/src/github.com/ndecker/fritzbox_exporter
go install
## Running
In the configuration of the Fritzbox the option "Statusinformationen über UPnP übertragen" in the dialog "Heimnetz >
Heimnetzübersicht > Netzwerkeinstellungen" has to be enabled.
Usage:
./fritzbox_exporter -h
Usage of ./fritzbox_exporter:
-gateway-address string
The URL of the upnp service (default "fritz.box")
-gateway-port int
The URL of the upnp service (default 49000)
-listen-address string
The address to listen on for HTTP requests. (default ":9132")
-test
print all available metrics to stdout
## Exported metrics
These metrics are exported:
# HELP fritzbox_exporter_collect_errors Number of collection errors.
# TYPE fritzbox_exporter_collect_errors counter
fritzbox_exporter_collect_errors 0
# HELP gateway_wan_bytes_received bytes received on gateway WAN interface
# TYPE gateway_wan_bytes_received counter
gateway_wan_bytes_received{gateway="fritz.box"} 5.037749914e+09
# HELP gateway_wan_bytes_sent bytes sent on gateway WAN interface
# TYPE gateway_wan_bytes_sent counter
gateway_wan_bytes_sent{gateway="fritz.box"} 2.55707479e+08
# HELP gateway_wan_connection_status WAN connection status (Connected = 1)
# TYPE gateway_wan_connection_status gauge
gateway_wan_connection_status{gateway="fritz.box"} 1
# HELP gateway_wan_connection_uptime_seconds WAN connection uptime
# TYPE gateway_wan_connection_uptime_seconds gauge
gateway_wan_connection_uptime_seconds{gateway="fritz.box"} 65259
# HELP gateway_wan_layer1_downstream_max_bitrate Layer1 downstream max bitrate
# TYPE gateway_wan_layer1_downstream_max_bitrate gauge
gateway_wan_layer1_downstream_max_bitrate{gateway="fritz.box"} 1.286e+07
# HELP gateway_wan_layer1_link_status Status of physical link (Up = 1)
# TYPE gateway_wan_layer1_link_status gauge
gateway_wan_layer1_link_status{gateway="fritz.box"} 1
# HELP gateway_wan_layer1_upstream_max_bitrate Layer1 upstream max bitrate
# TYPE gateway_wan_layer1_upstream_max_bitrate gauge
gateway_wan_layer1_upstream_max_bitrate{gateway="fritz.box"} 1.148e+06
# HELP gateway_wan_packets_received packets received on gateway WAN interface
# TYPE gateway_wan_packets_received counter
gateway_wan_packets_received{gateway="fritz.box"} 1.346625e+06
# HELP gateway_wan_packets_sent packets sent on gateway WAN interface
# TYPE gateway_wan_packets_sent counter
gateway_wan_packets_sent{gateway="fritz.box"} 3.05051e+06
## Output of -test
The exporter prints all available Variables to stdout when called with the -test option.
These values are determined by parsing all services from http://fritz.box:49000/igddesc.xml
Name: urn:schemas-any-com:service:Any:1
WANDevice - FRITZ!Box 7490: urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
GetCommonLinkProperties
WANAccessType: DSL
Layer1UpstreamMaxBitRate: 1148000
Layer1DownstreamMaxBitRate: 12860000
PhysicalLinkStatus: Up
GetTotalBytesSent
TotalBytesSent: 255710914
GetTotalBytesReceived
TotalBytesReceived: 5037753042
GetTotalPacketsSent
TotalPacketsSent: 3050536
GetTotalPacketsReceived
TotalPacketsReceived: 1346651
GetAddonInfos
ByteSendRate: 0
ByteReceiveRate: 0
PacketSendRate: 0
PacketReceiveRate: 0
TotalBytesSent: 255710914
TotalBytesReceived: 5037753042
AutoDisconnectTime: 0
IdleDisconnectTime: 10
DNSServer1: 1.1.1.1
DNSServer2: 2.2.2.2
VoipDNSServer1: 1.1.1.1
VoipDNSServer2: 2.2.2.2
UpnpControlEnabled: false
RoutedBridgedModeBoth: 1
WANConnectionDevice - FRITZ!Box 7490: urn:schemas-upnp-org:service:WANDSLLinkConfig:1
GetDSLLinkInfo
LinkType: PPPoE
LinkStatus: Up
GetModulationType
ModulationType: ADSL G.lite
GetDestinationAddress
DestinationAddress: NONE
GetATMEncapsulation
ATMEncapsulation: LLC
GetFCSPreserved
FCSPreserved: true
GetAutoConfig
AutoConfig: true
WANConnectionDevice - FRITZ!Box 7490: urn:schemas-upnp-org:service:WANIPConnection:1
X_AVM_DE_GetDNSServer
IPv4DNSServer1: 1.1.1.1
IPv4DNSServer2: 2.2.2.2
GetAutoDisconnectTime
AutoDisconnectTime: 0
GetIdleDisconnectTime
IdleDisconnectTime: 0
X_AVM_DE_GetExternalIPv6Address
ExternalIPv6Address:
PrefixLength: 0
ValidLifetime: 0
PreferedLifetime: 0
GetNATRSIPStatus
RSIPAvailable: false
NATEnabled: true
GetExternalIPAddress
ExternalIPAddress: 1.1.1.1
X_AVM_DE_GetIPv6Prefix
IPv6Prefix:
PrefixLength: 0
ValidLifetime: 0
PreferedLifetime: 0
X_AVM_DE_GetIPv6DNSServer
IPv6DNSServer1:
ValidLifetime1: 2002000000
IPv6DNSServer2:
ValidLifetime2: 199800000
GetConnectionTypeInfo
ConnectionType: IP_Routed
PossibleConnectionTypes: IP_Routed
GetStatusInfo
ConnectionStatus: Connected
LastConnectionError: ERROR_NONE
Uptime: 65386
WANConnectionDevice - FRITZ!Box 7490: urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
GetFirewallStatus
FirewallEnabled: true
InboundPinholeAllowed: false

37
fritzbox_upnp/service.go

@ -1,13 +1,14 @@
// Query UPNP variables from Fritz!Box devices.
package fritzbox_upnp
// Copyright 2016 Nils Decker
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -36,12 +37,14 @@ const text_xml = `text/xml; charset="utf-8"`
var ErrInvalidSOAPResponse = errors.New("invalid SOAP response")
// Root of the UPNP tree
type Root struct {
BaseUrl string
Device Device `xml:"device"`
Services map[string]*Service
Services map[string]*Service // Map of all services indexed by .ServiceType
}
// An UPNP Device
type Device struct {
root *Root
@ -55,12 +58,13 @@ type Device struct {
ModelUrl string `xml:"modelURL"`
UDN string `xml:"UDN"`
Services []*Service `xml:"serviceList>service"`
Devices []*Device `xml:"deviceList>device"`
Services []*Service `xml:"serviceList>service"` // Service of the device
Devices []*Device `xml:"deviceList>device"` // Sub-Devices of the device
PresentationUrl string `xml:"presentationURL"`
}
// An UPNP Service
type Service struct {
Device *Device
@ -70,8 +74,8 @@ type Service struct {
EventSubUrl string `xml:"eventSubURL"`
SCPDUrl string `xml:"SCPDURL"`
Actions map[string]*Action
StateVariables []*StateVariable
Actions map[string]*Action // All actions available on the service
StateVariables []*StateVariable // All state variables available on the service
}
type scpdRoot struct {
@ -79,14 +83,17 @@ type scpdRoot struct {
StateVariables []*StateVariable `xml:"serviceStateTable>stateVariable"`
}
// An UPNP Acton on a service
type Action struct {
service *Service
Name string `xml:"name"`
Arguments []*Argument `xml:"argumentList>argument"`
ArgumentMap map[string]*Argument
ArgumentMap map[string]*Argument // Map of arguments indexed by .Name
}
// Returns if the action seems to be a query for information.
// This is determined by checking if the action has no input arguments and at least one output argument.
func (a *Action) IsGetOnly() bool {
for _, a := range a.Arguments {
if a.Direction == "in" {
@ -96,6 +103,7 @@ func (a *Action) IsGetOnly() bool {
return len(a.Arguments) > 0
}
// An Argument to an action
type Argument struct {
Name string `xml:"name"`
Direction string `xml:"direction"`
@ -103,14 +111,19 @@ type Argument struct {
StateVariable *StateVariable
}
// A state variable that can be manipulated through actions
type StateVariable struct {
Name string `xml:"name"`
DataType string `xml:"dataType"`
DefaultValue string `xml:"defaultValue"`
}
// The result of a Call() contains all output arguments of the call.
// The map is indexed by the name of the state variable.
// The type of the value is string, uint64 or bool depending of the DataType of the variable.
type Result map[string]interface{}
// load the whole tree
func (r *Root) load() error {
igddesc, err := http.Get(
fmt.Sprintf("%s/igddesc.xml", r.BaseUrl),
@ -131,6 +144,7 @@ func (r *Root) load() error {
return r.Device.fillServices(r)
}
// load all service descriptions
func (d *Device) fillServices(r *Root) error {
d.root = r
@ -182,6 +196,8 @@ func (d *Device) fillServices(r *Root) error {
return nil
}
// Call an action.
// Currently only actions without input arguments are supported.
func (a *Action) Call() (Result, error) {
bodystr := fmt.Sprintf(`
<?xml version='1.0' encoding='utf-8'?>
@ -270,7 +286,7 @@ func convertResult(val string, arg *Argument) (interface{}, error) {
return bool(val == "1"), nil
case "ui1", "ui2", "ui4":
// type ui4 can contain values greater than 2^32!
// type ui4 can contain values greater than 2^32!
res, err := strconv.ParseUint(val, 10, 64)
if err != nil {
return nil, err
@ -282,6 +298,7 @@ func convertResult(val string, arg *Argument) (interface{}, error) {
}
}
// Load the services tree from an device.
func LoadServices(device string, port uint16) (*Root, error) {
var root = &Root{
BaseUrl: fmt.Sprintf("http://%s:%d", device, port),

37
main.go

@ -1,13 +1,13 @@
package main
// Copyright 2016 Nils Decker
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -26,7 +26,7 @@ import (
var (
flag_test = flag.Bool("test", false, "print all available metrics to stdout")
flag_addr = flag.String("listen-address", ":9111", "The address to listen on for HTTP requests.")
flag_addr = flag.String("listen-address", ":9132", "The address to listen on for HTTP requests.")
flag_gateway_address = flag.String("gateway-address", "fritz.box", "The URL of the upnp service")
flag_gateway_port = flag.Int("gateway-port", 49000, "The URL of the upnp service")
@ -45,8 +45,8 @@ type Metric struct {
Result string
OkValue string
Desc *prometheus.Desc
MetricType prometheus.ValueType
Desc *prometheus.Desc
MetricType prometheus.ValueType
}
var metrics = []*Metric{
@ -60,8 +60,7 @@ var metrics = []*Metric{
[]string{"gateway"},
nil,
),
MetricType: prometheus.CounterValue,
MetricType: prometheus.CounterValue,
},
{
Service: "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
@ -73,7 +72,7 @@ var metrics = []*Metric{
[]string{"gateway"},
nil,
),
MetricType: prometheus.CounterValue,
MetricType: prometheus.CounterValue,
},
{
Service: "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
@ -85,7 +84,7 @@ var metrics = []*Metric{
[]string{"gateway"},
nil,
),
MetricType: prometheus.CounterValue,
MetricType: prometheus.CounterValue,
},
{
Service: "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
@ -97,7 +96,7 @@ var metrics = []*Metric{
[]string{"gateway"},
nil,
),
MetricType: prometheus.CounterValue,
MetricType: prometheus.CounterValue,
},
{
Service: "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
@ -109,7 +108,7 @@ var metrics = []*Metric{
[]string{"gateway"},
nil,
),
MetricType: prometheus.GaugeValue,
MetricType: prometheus.GaugeValue,
},
{
Service: "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
@ -121,7 +120,7 @@ var metrics = []*Metric{
[]string{"gateway"},
nil,
),
MetricType: prometheus.GaugeValue,
MetricType: prometheus.GaugeValue,
},
{
Service: "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
@ -134,7 +133,7 @@ var metrics = []*Metric{
[]string{"gateway"},
nil,
),
MetricType: prometheus.GaugeValue,
MetricType: prometheus.GaugeValue,
},
{
Service: "urn:schemas-upnp-org:service:WANIPConnection:1",
@ -147,7 +146,7 @@ var metrics = []*Metric{
[]string{"gateway"},
nil,
),
MetricType: prometheus.GaugeValue,
MetricType: prometheus.GaugeValue,
},
{
Service: "urn:schemas-upnp-org:service:WANIPConnection:1",
@ -159,7 +158,7 @@ var metrics = []*Metric{
[]string{"gateway"},
nil,
),
MetricType: prometheus.GaugeValue,
MetricType: prometheus.GaugeValue,
},
}
@ -236,7 +235,7 @@ func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(
m.Desc,
m.MetricType,
m.MetricType,
floatval,
fc.Gateway,
)
@ -266,7 +265,7 @@ func main() {
fmt.Printf(" %s\n", a.Name)
for _, arg := range a.Arguments {
fmt.Printf(" %s - %s: %v\n", arg.RelatedStateVariable, arg.StateVariable.DataType, res[arg.StateVariable.Name])
fmt.Printf(" %s: %v\n", arg.RelatedStateVariable, res[arg.StateVariable.Name])
}
}
}
@ -275,7 +274,7 @@ func main() {
}
prometheus.MustRegister(&FritzboxCollector{root, *flag_gateway_address})
prometheus.MustRegister(collect_errors)
prometheus.MustRegister(collect_errors)
// Since we are dealing with custom Collector implementations, it might
// be a good idea to enable the collect checks in the registry.

Loading…
Cancel
Save