Browse Source

Fixes all names to be compliant with the golang standards.

pull/1/head
Christian Fritz 5 years ago
parent
commit
6713abd7d5
No known key found for this signature in database GPG Key ID: AB40486FCA9FA29C
  1. 31
      fritzbox_upnp/service.go
  2. 96
      main.go

31
fritzbox_upnp/service.go

@ -16,17 +16,17 @@ package fritzbox_upnp
// limitations under the License. // limitations under the License.
import ( import (
"bytes"
"crypto/md5"
"crypto/rand"
"crypto/tls"
"encoding/xml" "encoding/xml"
"errors" "errors"
"bytes"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"crypto/tls"
"strconv" "strconv"
"strings" "strings"
"crypto/md5"
"crypto/rand"
) )
// curl http://fritz.box:49000/igddesc.xml // curl http://fritz.box:49000/igddesc.xml
@ -36,7 +36,7 @@ import (
// curl http://fritz.box:49000/igddslSCPD.xml // curl http://fritz.box:49000/igddslSCPD.xml
// curl http://fritz.box:49000/igd2ipv6fwcSCPD.xml // curl http://fritz.box:49000/igd2ipv6fwcSCPD.xml
const text_xml = `text/xml; charset="utf-8"` const textXml = `text/xml; charset="utf-8"`
var ErrInvalidSOAPResponse = errors.New("invalid SOAP response") var ErrInvalidSOAPResponse = errors.New("invalid SOAP response")
@ -126,7 +126,6 @@ type UpnpError struct {
ErrorDescription string `xml:"errorDescription"` ErrorDescription string `xml:"errorDescription"`
} }
// Returns if the action seems to be a query for information. // 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. // This is determined by checking if the action has no input arguments and at least one output argument.
func (a *Action) IsGetOnly() bool { func (a *Action) IsGetOnly() bool {
@ -136,9 +135,6 @@ func (a *Action) IsGetOnly() bool {
} }
} }
return len(a.Arguments) > 0 return len(a.Arguments) > 0
return false
} }
// An Argument to an action // An Argument to an action
@ -287,10 +283,10 @@ func (a *Action) createCallHttpRequest(actionArg *ActionArgument) (*http.Request
action := fmt.Sprintf("%s#%s", a.service.ServiceType, a.Name) action := fmt.Sprintf("%s#%s", a.service.ServiceType, a.Name)
req.Header.Set("Content-Type", text_xml) req.Header.Set("Content-Type", textXml)
req.Header.Set("SOAPAction", action) req.Header.Set("SOAPAction", action)
return req, nil; return req, nil
} }
// store auth header for reuse // store auth header for reuse
@ -363,7 +359,7 @@ func (a *Action) Call(actionArg *ActionArgument) (Result, error) {
soapFault := soapEnv.Body.Fault soapFault := soapEnv.Body.Fault
if soapFault.FaultString == "UPnPError" { if soapFault.FaultString == "UPnPError" {
upe := soapFault.Detail.UpnpError; upe := soapFault.Detail.UpnpError
errMsg = fmt.Sprintf("SAOPFault: %s %d (%s)", soapFault.FaultString, upe.ErrorCode, upe.ErrorDescription) errMsg = fmt.Sprintf("SAOPFault: %s %d (%s)", soapFault.FaultString, upe.ErrorCode, upe.ErrorDescription)
} else { } else {
@ -379,7 +375,7 @@ func (a *Action) Call(actionArg *ActionArgument) (Result, error) {
func (a *Action) getDigestAuthHeader(wwwAuth string, username string, password string) (string, error) { func (a *Action) getDigestAuthHeader(wwwAuth string, username string, password string) (string, error) {
// parse www-auth header // parse www-auth header
if ! strings.HasPrefix(wwwAuth, "Digest ") { if !strings.HasPrefix(wwwAuth, "Digest ") {
return "", errors.New(fmt.Sprintf("WWW-Authentication header is not Digest: '%s'", wwwAuth)) return "", errors.New(fmt.Sprintf("WWW-Authentication header is not Digest: '%s'", wwwAuth))
} }
@ -404,16 +400,16 @@ func (a *Action) getDigestAuthHeader(wwwAuth string, username string, password s
} }
// calc h1 and h2 // calc h1 and h2
ha1 := fmt.Sprintf("%x", md5.Sum([]byte(username + ":" + d["realm"] + ":" + password))) ha1 := fmt.Sprintf("%x", md5.Sum([]byte(username+":"+d["realm"]+":"+password)))
ha2 := fmt.Sprintf("%x", md5.Sum([]byte("POST:" + a.service.ControlUrl))) ha2 := fmt.Sprintf("%x", md5.Sum([]byte("POST:"+a.service.ControlUrl)))
cn := make([]byte, 8) cn := make([]byte, 8)
rand.Read(cn) rand.Read(cn)
cnonce := fmt.Sprintf("%x", cn) cnonce := fmt.Sprintf("%x", cn)
nCounter := 1 nCounter := 1
nc:=fmt.Sprintf("%08x", nCounter) nc := fmt.Sprintf("%08x", nCounter)
ds := strings.Join([]string{ha1, d["nonce"], nc, cnonce, d["qop"], ha2}, ":") ds := strings.Join([]string{ha1, d["nonce"], nc, cnonce, d["qop"], ha2}, ":")
response := fmt.Sprintf("%x", md5.Sum([]byte(ds))) response := fmt.Sprintf("%x", md5.Sum([]byte(ds)))
@ -424,7 +420,6 @@ func (a *Action) getDigestAuthHeader(wwwAuth string, username string, password s
return authHeader, nil return authHeader, nil
} }
func (a *Action) parseSoapResponse(r io.Reader) (Result, error) { func (a *Action) parseSoapResponse(r io.Reader) (Result, error) {
res := make(Result) res := make(Result)
dec := xml.NewDecoder(r) dec := xml.NewDecoder(r)
@ -482,7 +477,7 @@ func convertResult(val string, arg *Argument) (interface{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return uint64(res), nil return res, nil
case "i4": case "i4":
res, err := strconv.ParseInt(val, 10, 64) res, err := strconv.ParseInt(val, 10, 64)
if err != nil { if err != nil {

96
main.go

@ -39,26 +39,26 @@ import (
const serviceLoadRetryTime = 1 * time.Minute const serviceLoadRetryTime = 1 * time.Minute
var ( var (
flag_test = flag.Bool("test", false, "print all available metrics to stdout") flagTest = flag.Bool("test", false, "print all available metrics to stdout")
flag_collect = flag.Bool("collect", false, "print configured metrics to stdout and exit") flagCollect = flag.Bool("collect", false, "print configured metrics to stdout and exit")
flag_jsonout = flag.String("json-out", "", "store metrics also to JSON file when running test") flagJsonOut = flag.String("json-out", "", "store metrics also to JSON file when running test")
flag_addr = flag.String("listen-address", "127.0.0.1:9042", "The address to listen on for HTTP requests.") flagAddr = flag.String("listen-address", "127.0.0.1:9042", "The address to listen on for HTTP requests.")
flag_metrics_file = flag.String("metrics-file", "metrics.json", "The JSON file with the metric definitions.") flagMetricsFile = flag.String("metrics-file", "metrics.json", "The JSON file with the metric definitions.")
flag_gateway_url = flag.String("gateway-url", "http://fritz.box:49000", "The URL of the FRITZ!Box") flagGatewayUrl = flag.String("gateway-url", "http://fritz.box:49000", "The URL of the FRITZ!Box")
flag_gateway_username = flag.String("username", "", "The user for the FRITZ!Box UPnP service") flagGatewayUsername = flag.String("username", "", "The user for the FRITZ!Box UPnP service")
flag_gateway_password = flag.String("password", "", "The password for the FRITZ!Box UPnP service") flagGatewayPassword = flag.String("password", "", "The password for the FRITZ!Box UPnP service")
) )
var ( var (
collect_errors = prometheus.NewCounter(prometheus.CounterOpts{ collectErrors = prometheus.NewCounter(prometheus.CounterOpts{
Name: "fritzbox_exporter_collect_errors", Name: "fritzbox_exporter_collect_errors",
Help: "Number of collection errors.", Help: "Number of collection errors.",
}) })
) )
type JSON_PromDesc struct { type JsonPromDesc struct {
FqName string `json:"fqName"` FqName string `json:"fqName"`
Help string `json:"help"` Help string `json:"help"`
VarLabels []string `json:"varLabels"` VarLabels []string `json:"varLabels"`
@ -78,7 +78,7 @@ type Metric struct {
ActionArgument *ActionArg `json:"actionArgument"` ActionArgument *ActionArg `json:"actionArgument"`
Result string `json:"result"` Result string `json:"result"`
OkValue string `json:"okValue"` OkValue string `json:"okValue"`
PromDesc JSON_PromDesc `json:"promDesc"` PromDesc JsonPromDesc `json:"promDesc"`
PromType string `json:"promType"` PromType string `json:"promType"`
// initialized at startup // initialized at startup
@ -152,7 +152,7 @@ func (fc *FritzboxCollector) ReportMetric(ch chan<- prometheus.Metric, m *Metric
val, ok := result[m.Result] val, ok := result[m.Result]
if !ok { if !ok {
fmt.Printf("%s.%s has no result %s", m.Service, m.Action, m.Result) fmt.Printf("%s.%s has no result %s", m.Service, m.Action, m.Result)
collect_errors.Inc() collectErrors.Inc()
return return
} }
@ -174,7 +174,7 @@ func (fc *FritzboxCollector) ReportMetric(ch chan<- prometheus.Metric, m *Metric
} }
default: default:
fmt.Println("unknown type", val) fmt.Println("unknown type", val)
collect_errors.Inc() collectErrors.Inc()
return return
} }
@ -189,7 +189,7 @@ func (fc *FritzboxCollector) ReportMetric(ch chan<- prometheus.Metric, m *Metric
lval = "" lval = ""
} }
// convert tolower to avoid problems with labels like hostname // convert to lower to avoid problems with labels like hostname
labels[i] = strings.ToLower(fmt.Sprintf("%v", lval)) labels[i] = strings.ToLower(fmt.Sprintf("%v", lval))
} }
} }
@ -201,18 +201,18 @@ func (fc *FritzboxCollector) ReportMetric(ch chan<- prometheus.Metric, m *Metric
labels...) labels...)
} }
func (fc *FritzboxCollector) GetActionResult(result_map map[string]upnp.Result, serviceType string, actionName string, actionArg *upnp.ActionArgument) (upnp.Result, error) { func (fc *FritzboxCollector) GetActionResult(resultMap map[string]upnp.Result, serviceType string, actionName string, actionArg *upnp.ActionArgument) (upnp.Result, error) {
m_key := serviceType + "|" + actionName mKey := serviceType + "|" + actionName
// for calls with argument also add arguement name and value to key // for calls with argument also add arguement name and value to key
if actionArg != nil { if actionArg != nil {
m_key += "|" + actionArg.Name + "|" + fmt.Sprintf("%v", actionArg.Value) mKey += "|" + actionArg.Name + "|" + fmt.Sprintf("%v", actionArg.Value)
} }
last_result := result_map[m_key] lastResult := resultMap[mKey]
if last_result == nil { if lastResult == nil {
service, ok := fc.Root.Services[serviceType] service, ok := fc.Root.Services[serviceType]
if !ok { if !ok {
return nil, errors.New(fmt.Sprintf("service %s not found", serviceType)) return nil, errors.New(fmt.Sprintf("service %s not found", serviceType))
@ -224,16 +224,16 @@ func (fc *FritzboxCollector) GetActionResult(result_map map[string]upnp.Result,
} }
var err error var err error
last_result, err = action.Call(actionArg) lastResult, err = action.Call(actionArg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
result_map[m_key] = last_result resultMap[mKey] = lastResult
} }
return last_result, nil return lastResult, nil
} }
func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) { func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) {
@ -247,7 +247,7 @@ func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) {
} }
// create a map for caching results // create a map for caching results
var result_map = make(map[string]upnp.Result) var resultMap = make(map[string]upnp.Result)
for _, m := range metrics { for _, m := range metrics {
var actArg *upnp.ActionArgument var actArg *upnp.ActionArgument
@ -257,19 +257,19 @@ func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) {
value = aa.Value value = aa.Value
if aa.ProviderAction != "" { if aa.ProviderAction != "" {
provRes, err := fc.GetActionResult(result_map, m.Service, aa.ProviderAction, nil) provRes, err := fc.GetActionResult(resultMap, m.Service, aa.ProviderAction, nil)
if err != nil { if err != nil {
fmt.Printf("Error getting provider action %s result for %s.%s: %s\n", aa.ProviderAction, m.Service, m.Action, err.Error()) fmt.Printf("Error getting provider action %s result for %s.%s: %s\n", aa.ProviderAction, m.Service, m.Action, err.Error())
collect_errors.Inc() collectErrors.Inc()
continue continue
} }
var ok bool var ok bool
value, ok = provRes[aa.Value] // Value contains the result name for provider actions value, ok = provRes[aa.Value] // Value contains the result name for provider actions
if !ok { if !ok {
fmt.Printf("provider action %s for %s.%s has no result %s", m.Service, m.Action, aa.Value) fmt.Printf("provider action %s for %s.%s has no result", m.Service, m.Action, aa.Value)
collect_errors.Inc() collectErrors.Inc()
continue continue
} }
} }
@ -279,17 +279,17 @@ func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) {
count, err := strconv.Atoi(sval) count, err := strconv.Atoi(sval)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
collect_errors.Inc() collectErrors.Inc()
continue continue
} }
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
actArg = &upnp.ActionArgument{Name: aa.Name, Value: i} actArg = &upnp.ActionArgument{Name: aa.Name, Value: i}
result, err := fc.GetActionResult(result_map, m.Service, m.Action, actArg) result, err := fc.GetActionResult(resultMap, m.Service, m.Action, actArg)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
collect_errors.Inc() collectErrors.Inc()
continue continue
} }
@ -302,11 +302,11 @@ func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) {
} }
} }
result, err := fc.GetActionResult(result_map, m.Service, m.Action, actArg) result, err := fc.GetActionResult(resultMap, m.Service, m.Action, actArg)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
collect_errors.Inc() collectErrors.Inc()
continue continue
} }
@ -315,7 +315,7 @@ func (fc *FritzboxCollector) Collect(ch chan<- prometheus.Metric) {
} }
func test() { func test() {
root, err := upnp.LoadServices(*flag_gateway_url, *flag_gateway_username, *flag_gateway_password) root, err := upnp.LoadServices(*flagGatewayUrl, *flagGatewayUsername, *flagGatewayPassword)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -333,7 +333,7 @@ func test() {
s := root.Services[k] s := root.Services[k]
fmt.Printf("Service: %s (Url: %s)\n", k, s.ControlUrl) fmt.Printf("Service: %s (Url: %s)\n", k, s.ControlUrl)
actionKeys := []string{} var actionKeys []string
for l, _ := range s.Actions { for l, _ := range s.Actions {
actionKeys = append(actionKeys, l) actionKeys = append(actionKeys, l)
} }
@ -386,10 +386,10 @@ func test() {
json.WriteString("\n]") json.WriteString("\n]")
if *flag_jsonout != "" { if *flagJsonOut != "" {
err := ioutil.WriteFile(*flag_jsonout, json.Bytes(), 0644) err := ioutil.WriteFile(*flagJsonOut, json.Bytes(), 0644)
if err != nil { if err != nil {
fmt.Printf("Failed writing JSON file '%s': %s\n", *flag_jsonout, err.Error()) fmt.Printf("Failed writing JSON file '%s': %s\n", *flagJsonOut, err.Error())
} }
} }
} }
@ -410,19 +410,19 @@ func getValueType(vt string) prometheus.ValueType {
func main() { func main() {
flag.Parse() flag.Parse()
u, err := url.Parse(*flag_gateway_url) u, err := url.Parse(*flagGatewayUrl)
if err != nil { if err != nil {
fmt.Println("invalid URL:", err) fmt.Println("invalid URL:", err)
return return
} }
if *flag_test { if *flagTest {
test() test()
return return
} }
// read metrics // read metrics
jsonData, err := ioutil.ReadFile(*flag_metrics_file) jsonData, err := ioutil.ReadFile(*flagMetricsFile)
if err != nil { if err != nil {
fmt.Println("error reading metric file:", err) fmt.Println("error reading metric file:", err)
return return
@ -449,17 +449,17 @@ func main() {
} }
collector := &FritzboxCollector{ collector := &FritzboxCollector{
Url: *flag_gateway_url, Url: *flagGatewayUrl,
Gateway: u.Hostname(), Gateway: u.Hostname(),
Username: *flag_gateway_username, Username: *flagGatewayUsername,
Password: *flag_gateway_password, Password: *flagGatewayPassword,
} }
if *flag_collect { if *flagCollect {
collector.LoadServices() collector.LoadServices()
prometheus.MustRegister(collector) prometheus.MustRegister(collector)
prometheus.MustRegister(collect_errors) prometheus.MustRegister(collectErrors)
fmt.Println("collecting metrics via http") fmt.Println("collecting metrics via http")
@ -476,10 +476,10 @@ func main() {
go collector.LoadServices() go collector.LoadServices()
prometheus.MustRegister(collector) prometheus.MustRegister(collector)
prometheus.MustRegister(collect_errors) prometheus.MustRegister(collectErrors)
http.Handle("/metrics", promhttp.Handler()) http.Handle("/metrics", promhttp.Handler())
fmt.Printf("metrics available at http://%s/metrics\n", *flag_addr) fmt.Printf("metrics available at http://%s/metrics\n", *flagAddr)
log.Fatal(http.ListenAndServe(*flag_addr, nil)) log.Fatal(http.ListenAndServe(*flagAddr, nil))
} }

Loading…
Cancel
Save