Browse Source

split upnp into seperate package

pull/1/head
Nils Decker 9 years ago
parent
commit
05c803b465
  1. 1
      .gitignore
  2. 50
      fritzbox_upnp/upnp.go
  3. 67
      fritzbox_upnp/values.go
  4. 152
      main.go

1
.gitignore

@ -0,0 +1 @@
fritzbox_exporter

50
upnp.go → fritzbox_upnp/upnp.go

@ -1,4 +1,4 @@
package main package fritzbox_upnp
import ( import (
"bytes" "bytes"
@ -7,10 +7,11 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"strconv"
"strings" "strings"
) )
const TEXT_XML = `text/xml; charset="utf-8"` const text_xml = `text/xml; charset="utf-8"`
var ( var (
ErrResultNotFound = errors.New("result not found") ErrResultNotFound = errors.New("result not found")
@ -27,14 +28,17 @@ var (
// </s:Body> </s:Envelope>" // </s:Body> </s:Envelope>"
type UpnpValue struct { type UpnpValue struct {
path string Path string
service string Service string
method string Method string
ret_tag string RetTag string
ShortName string
Help string
} }
func (v *UpnpValue) Query(device string) (string, error) { func (v *UpnpValue) query(device string, port uint16) (string, error) {
url := fmt.Sprintf("http://%s:49000%s", device, v.path) url := fmt.Sprintf("http://%s:%d%s", device, port, v.Path)
bodystr := fmt.Sprintf(` bodystr := fmt.Sprintf(`
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
@ -43,7 +47,7 @@ func (v *UpnpValue) Query(device string) (string, error) {
<u:%s xmlns:u='urn:schemas-upnp-org:service:%s' /> <u:%s xmlns:u='urn:schemas-upnp-org:service:%s' />
</s:Body> </s:Body>
</s:Envelope> </s:Envelope>
`, v.method, v.service) `, v.Method, v.Service)
body := strings.NewReader(bodystr) body := strings.NewReader(bodystr)
@ -52,9 +56,9 @@ func (v *UpnpValue) Query(device string) (string, error) {
return "", err return "", err
} }
action := fmt.Sprintf("urn:schemas-upnp-org:service:%s#%s", v.service, v.method) action := fmt.Sprintf("urn:schemas-upnp-org:service:%s#%s", v.Service, v.Method)
req.Header["Content-Type"] = []string{TEXT_XML} req.Header["Content-Type"] = []string{text_xml}
req.Header["SoapAction"] = []string{action} req.Header["SoapAction"] = []string{action}
resp, err := http.DefaultClient.Do(req) resp, err := http.DefaultClient.Do(req)
@ -80,7 +84,7 @@ func (v *UpnpValue) Query(device string) (string, error) {
} }
if se, ok := t.(xml.StartElement); ok { if se, ok := t.(xml.StartElement); ok {
if se.Name.Local == v.ret_tag { if se.Name.Local == v.RetTag {
t2, err := dec.Token() t2, err := dec.Token()
if err != nil { if err != nil {
return "", err return "", err
@ -96,3 +100,25 @@ func (v *UpnpValue) Query(device string) (string, error) {
} }
} }
type UpnpValueString struct{ UpnpValue }
func (v *UpnpValueString) Query(device string, port uint16) (string, error) {
return v.query(device, port)
}
type UpnpValueUint struct{ UpnpValue }
func (v *UpnpValueUint) Query(device string, port uint16) (uint64, error) {
strval, err := v.query(device, port)
if err != nil {
return 0, err
}
val, err := strconv.ParseUint(strval, 10, 64)
if err != nil {
return 0, err
}
return val, nil
}

67
fritzbox_upnp/values.go

@ -0,0 +1,67 @@
package fritzbox_upnp
// curl http://fritz.box:49000/igddesc.xml
// curl http://fritz.box:49000/any.xml
// curl http://fritz.box:49000/igdconnSCPD.xml
// curl http://fritz.box:49000/igdicfgSCPD.xml
// curl http://fritz.box:49000/igddslSCPD.xml
// curl http://fritz.box:49000/igd2ipv6fwcSCPD.xml
var (
WAN_IP = UpnpValueString{UpnpValue{
Path: "/igdupnp/control/WANIPConn1",
Service: "WANIPConnection:1",
Method: "GetExternalIPAddress",
RetTag: "NewExternalIPAddress",
ShortName: "wan_ip",
Help: "WAN IP Adress",
}}
WAN_Packets_Received = UpnpValueUint{UpnpValue{
Path: "/igdupnp/control/WANCommonIFC1",
Service: "WANCommonInterfaceConfig:1",
Method: "GetTotalPacketsReceived",
RetTag: "NewTotalPacketsReceived",
ShortName: "packets_received",
Help: "packets received on gateway WAN interface",
}}
WAN_Packets_Sent = UpnpValueUint{UpnpValue{
Path: "/igdupnp/control/WANCommonIFC1",
Service: "WANCommonInterfaceConfig:1",
Method: "GetTotalPacketsSent",
RetTag: "NewTotalPacketsSent",
ShortName: "packets_sent",
Help: "packets sent on gateway WAN interface",
}}
WAN_Bytes_Received = UpnpValueUint{UpnpValue{
Path: "/igdupnp/control/WANCommonIFC1",
Service: "WANCommonInterfaceConfig:1",
Method: "GetAddonInfos",
RetTag: "NewTotalBytesReceived",
ShortName: "bytes_received",
Help: "bytes received on gateway WAN interface",
}}
WAN_Bytes_Sent = UpnpValueUint{UpnpValue{
Path: "/igdupnp/control/WANCommonIFC1",
Service: "WANCommonInterfaceConfig:1",
Method: "GetAddonInfos",
RetTag: "NewTotalBytesSent",
ShortName: "bytes_sent",
Help: "bytes sent on gateway WAN interface",
}}
)
var Values = []UpnpValueUint{
WAN_Packets_Received,
WAN_Packets_Sent,
WAN_Bytes_Received,
WAN_Bytes_Sent,
}

152
main.go

@ -2,74 +2,40 @@ package main
import ( import (
"flag" "flag"
"fmt"
"net/http" "net/http"
"strconv"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
upnp "github.com/ndecker/fritzbox_exporter/fritzbox_upnp"
) )
var ( 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", ":9111", "The address to listen on for HTTP requests.")
flag_dev_address = flag.String("device-address", "fritz.box", "The URL of the upnp service")
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")
) )
var ( var (
WAN_IP = UpnpValue{ collect_errors = prometheus.NewCounter(prometheus.CounterOpts{
path: "/igdupnp/control/WANIPConn1", Name: "fritzbox_exporter_collect_errors",
service: "WANIPConnection:1", Help: "Number of collection errors.",
method: "GetExternalIPAddress", })
ret_tag: "NewExternalIPAddress",
}
WAN_Packets_Received = UpnpValue{
path: "/igdupnp/control/WANCommonIFC1",
service: "WANCommonInterfaceConfig:1",
method: "GetTotalPacketsReceived",
ret_tag: "NewTotalPacketsReceived",
}
WAN_Packets_Sent = UpnpValue{
path: "/igdupnp/control/WANCommonIFC1",
service: "WANCommonInterfaceConfig:1",
method: "GetTotalPacketsSent",
ret_tag: "NewTotalPacketsSent",
}
WAN_Bytes_Received = UpnpValue{
path: "/igdupnp/control/WANCommonIFC1",
service: "WANCommonInterfaceConfig:1",
method: "GetAddonInfos",
ret_tag: "NewTotalBytesReceived",
}
WAN_Bytes_Sent = UpnpValue{
path: "/igdupnp/control/WANCommonIFC1",
service: "WANCommonInterfaceConfig:1",
method: "GetAddonInfos",
ret_tag: "NewTotalBytesSent",
}
) )
type Metric struct { type UpnpMetric struct {
UpnpValue upnp.UpnpValueUint
*prometheus.Desc *prometheus.Desc
} }
func (m Metric) Value() (uint64, error) { func (m UpnpMetric) Describe(ch chan<- *prometheus.Desc) {
strval, err := m.Query(*flag_dev_address)
if err != nil {
return 0, err
}
return strconv.ParseUint(strval, 10, 64)
}
func (m Metric) Describe(ch chan<- *prometheus.Desc) {
ch <- m.Desc ch <- m.Desc
} }
func (m Metric) Collect(ch chan<- prometheus.Metric) error { func (m UpnpMetric) Collect(gateway string, port uint16, ch chan<- prometheus.Metric) error {
val, err := m.Value() val, err := m.Query(gateway, port)
if err != nil { if err != nil {
return err return err
} }
@ -78,72 +44,68 @@ func (m Metric) Collect(ch chan<- prometheus.Metric) error {
m.Desc, m.Desc,
prometheus.CounterValue, prometheus.CounterValue,
float64(val), float64(val),
gateway,
) )
return nil return nil
} }
var ( func NewUpnpMetric(v upnp.UpnpValueUint) UpnpMetric {
packets_sent = Metric{ return UpnpMetric{
WAN_Packets_Sent, v,
prometheus.NewDesc(
prometheus.BuildFQName("gateway", "wan", "packets_sent"),
"packets sent on gateway wan interface",
nil,
prometheus.Labels{"gateway": *flag_dev_address},
),
}
packets_received = Metric{
WAN_Packets_Received,
prometheus.NewDesc(
prometheus.BuildFQName("gateway", "wan", "packets_received"),
"packets received on gateway wan interface",
nil,
prometheus.Labels{"gateway": *flag_dev_address},
),
}
bytes_sent = Metric{
WAN_Bytes_Sent,
prometheus.NewDesc( prometheus.NewDesc(
prometheus.BuildFQName("gateway", "wan", "bytes_sent"), prometheus.BuildFQName("gateway", "wan", v.ShortName),
"bytes sent on gateway wan interface", v.Help,
[]string{"gateway"},
nil, nil,
prometheus.Labels{"gateway": *flag_dev_address},
), ),
} }
bytes_received = Metric{ }
WAN_Bytes_Received,
prometheus.NewDesc(
prometheus.BuildFQName("gateway", "wan", "bytes_received"),
"bytes received on gateway wan interface",
nil,
prometheus.Labels{"gateway": *flag_dev_address},
),
}
)
type FritzboxCollector struct { type FritzboxCollector struct {
gateway string
port uint16
metrics []UpnpMetric
} }
func (fc *FritzboxCollector) Describe(ch chan<- *prometheus.Desc) { func (fc *FritzboxCollector) Describe(ch chan<- *prometheus.Desc) {
packets_sent.Describe(ch) for _, m := range fc.metrics {
packets_received.Describe(ch) m.Describe(ch)
bytes_sent.Describe(ch) }
bytes_received.Describe(ch)
} }
func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) { func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) {
packets_sent.Collect(ch) for _, m := range fc.metrics {
packets_received.Collect(ch) err := m.Collect(fc.gateway, fc.port, ch)
bytes_sent.Collect(ch) if err != nil {
bytes_received.Collect(ch) collect_errors.Inc()
}
}
} }
func main() { func main() {
flag.Parse() flag.Parse()
prometheus.MustRegister(&FritzboxCollector{}) if *flag_test {
for _, v := range upnp.Values {
res, err := v.Query(*flag_gateway_address, uint16(*flag_gateway_port))
if err != nil {
panic(err)
}
fmt.Printf("%s: %d\n", v.ShortName, res)
}
return
}
metrics := make([]UpnpMetric, len(upnp.Values))
for _, v := range upnp.Values {
metrics = append(metrics, NewUpnpMetric(v))
}
prometheus.MustRegister(&FritzboxCollector{
*flag_gateway_address,
uint16(*flag_gateway_port),
metrics,
})
// Since we are dealing with custom Collector implementations, it might // Since we are dealing with custom Collector implementations, it might
// be a good idea to enable the collect checks in the registry. // be a good idea to enable the collect checks in the registry.
prometheus.EnableCollectChecks(true) prometheus.EnableCollectChecks(true)

Loading…
Cancel
Save