this is just a start, nothing works yet

This commit is contained in:
davidnewhall2 2019-11-12 00:04:01 -08:00
parent b843f08629
commit 6c19dce90d
9 changed files with 160 additions and 18 deletions

View File

@ -9,6 +9,22 @@
revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005" revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005"
version = "v0.3.1" version = "v0.3.1"
[[projects]]
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
name = "github.com/beorn7/perks"
packages = ["quantile"]
pruneopts = "UT"
revision = "37c8de3658fcb183f997c4e13e8337516ab753e6"
version = "v1.0.1"
[[projects]]
digest = "1:573ca21d3669500ff845bdebee890eb7fc7f0f50c59f2132f2a0c6b03d85086a"
name = "github.com/golang/protobuf"
packages = ["proto"]
pruneopts = "UT"
revision = "6c65a5562fc06764971b7c5d05c76c75e84bdbf7"
version = "v1.3.2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:50708c8fc92aec981df5c446581cf9f90ba9e2a5692118e0ce75d4534aaa14a2" digest = "1:50708c8fc92aec981df5c446581cf9f90ba9e2a5692118e0ce75d4534aaa14a2"
@ -21,6 +37,58 @@
pruneopts = "UT" pruneopts = "UT"
revision = "fc22c7df067eefd070157f157893fbce961d6359" revision = "fc22c7df067eefd070157f157893fbce961d6359"
[[projects]]
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
pruneopts = "UT"
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
version = "v1.0.1"
[[projects]]
digest = "1:eb04f69c8991e52eff33c428bd729e04208bf03235be88e4df0d88497c6861b9"
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
"prometheus/internal",
"prometheus/promhttp",
]
pruneopts = "UT"
revision = "170205fb58decfd011f1550d4cfb737230d7ae4f"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
name = "github.com/prometheus/client_model"
packages = ["go"]
pruneopts = "UT"
revision = "14fe0d1b01d4d5fc031dd4bec1823bd3ebbe8016"
[[projects]]
digest = "1:f119e3205d3a1f0f19dbd7038eb37528e2c6f0933269dc344e305951fb87d632"
name = "github.com/prometheus/common"
packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model",
]
pruneopts = "UT"
revision = "287d3e634a1e550c9e463dd7e5a75a422c614505"
version = "v0.7.0"
[[projects]]
digest = "1:3e363393b80d8f142984a811464eb7e34064700626cc111887373ea76f8ea0bf"
name = "github.com/prometheus/procfs"
packages = [
".",
"internal/fs",
"internal/util",
]
pruneopts = "UT"
revision = "8a055596020d692cf491851e47ba3e302d9f90ce"
version = "v0.0.6"
[[projects]] [[projects]]
digest = "1:524b71991fc7d9246cc7dc2d9e0886ccb97648091c63e30eef619e6862c955dd" digest = "1:524b71991fc7d9246cc7dc2d9e0886ccb97648091c63e30eef619e6862c955dd"
name = "github.com/spf13/pflag" name = "github.com/spf13/pflag"
@ -29,6 +97,14 @@
revision = "2e9d26c8c37aae03e3f9d4e90b7116f5accb7cab" revision = "2e9d26c8c37aae03e3f9d4e90b7116f5accb7cab"
version = "v1.0.5" version = "v1.0.5"
[[projects]]
branch = "master"
digest = "1:71b15a23c3c47b97dd98f97c6afde8da4de9f21dec38c34e2ac2e04dc7b09167"
name = "golang.org/x/sys"
packages = ["windows"]
pruneopts = "UT"
revision = "d32e6e3b99c40f2bfaea45ea9596ed539eed1c0d"
[[projects]] [[projects]]
digest = "1:e74d5f03545d51228b9539aaffc5eb8a692fcb22f38fa60253437b1fc063a73b" digest = "1:e74d5f03545d51228b9539aaffc5eb8a692fcb22f38fa60253437b1fc063a73b"
name = "golift.io/unifi" name = "golift.io/unifi"
@ -51,6 +127,7 @@
input-imports = [ input-imports = [
"github.com/BurntSushi/toml", "github.com/BurntSushi/toml",
"github.com/influxdata/influxdb1-client/v2", "github.com/influxdata/influxdb1-client/v2",
"github.com/prometheus/client_golang/prometheus/promhttp",
"github.com/spf13/pflag", "github.com/spf13/pflag",
"golift.io/unifi", "golift.io/unifi",
"gopkg.in/yaml.v2", "gopkg.in/yaml.v2",

View File

@ -89,10 +89,10 @@ is provided so the application can be easily adapted to any environment.
mode default: "influx" mode default: "influx"
* Value: influx * Value: influx
This default mode runs this application as a daemon. It will poll This default mode runs this application as a daemon. It will poll
the controller at the configured interval. Providing an invalid value the controller at the configured interval and report measurements to
will run in this default mode. InfluxDB. Providing an invalid value will run in this default mode.
* Value: influxlambda - (the only other available option right now) * Value: influxlambda
Setting this value will invoke a run-once mode where the application Setting this value will invoke a run-once mode where the application
immediately polls the controller and reports the metrics to InfluxDB. immediately polls the controller and reports the metrics to InfluxDB.
Then it exits. This mode is useful in an AWS Lambda or a crontab where Then it exits. This mode is useful in an AWS Lambda or a crontab where
@ -101,6 +101,16 @@ is provided so the application can be easily adapted to any environment.
This mode can also be combined with a "test database" in InfluxDB to This mode can also be combined with a "test database" in InfluxDB to
give yourself a "test config file" you may run ad-hoc to test changes. give yourself a "test config file" you may run ad-hoc to test changes.
* Value: prometheus
In this mode the application opens an http interface and exports the
measurements at /metrics for collection by prometheus. Enabling this
mode disables InfluxDB usage entirely.
http_listen default: 0.0.0.0:61317
This option controls the IP and port the http listener uses when the
mode is set to prometheus. This setting has no effect when other modes
are in use.
influx_url default: http://127.0.0.1:8086 influx_url default: http://127.0.0.1:8086
This is the URL where the Influx web server is available. This is the URL where the Influx web server is available.

View File

@ -24,13 +24,21 @@ quiet = false
# an invalid mode will also result in "influx". In this default mode the application # an invalid mode will also result in "influx". In this default mode the application
# runs as a daemon and polls the controller at the configured interval. # runs as a daemon and polls the controller at the configured interval.
# #
# There is only one other option at this time: "influxlambda" # There are two other options at this time: "influxlambda" and "prometheus"
# #
# Lambda mode makes the application exit after collecting and reporting metrics # Lambda mode makes the application exit after collecting and reporting metrics
# to InfluxDB one time. This mode requires an external process like an AWS Lambda # to InfluxDB one time. This mode requires an external process like an AWS Lambda
# or a simple crontab to keep the timings accurate on UniFi Poller run intervals. # or a simple crontab to keep the timings accurate on UniFi Poller run intervals.
#
# Prometheus mode opens an HTTP server on port 61317 and exports the metrics at
# /metrics for polling collection by a prometheus server. This disables influxdb.
mode = "influx" mode = "influx"
# This controls on which ip and port /metrics is exported when mode is "prometheus".
# This has no effect in other modes. Must contain a colon and port.
http_listen = "0.0.0.0:61317"
# InfluxDB does not require auth by default, so the user/password are probably unimportant. # InfluxDB does not require auth by default, so the user/password are probably unimportant.
influx_url = "http://127.0.0.1:8086" influx_url = "http://127.0.0.1:8086"
influx_user = "unifi" influx_user = "unifi"

View File

@ -4,6 +4,7 @@
"debug": false, "debug": false,
"quiet": false, "quiet": false,
"mode": "influx", "mode": "influx",
"http_listen": "0.0.0.0:61317",
"influx_url": "http://127.0.0.1:8086", "influx_url": "http://127.0.0.1:8086",
"influx_user": "unifi", "influx_user": "unifi",
"influx_pass": "unifi", "influx_pass": "unifi",

View File

@ -40,14 +40,23 @@
# an invalid mode will also result in "influx". In this default mode the application # an invalid mode will also result in "influx". In this default mode the application
# runs as a daemon and polls the controller at the configured interval. # runs as a daemon and polls the controller at the configured interval.
# #
# There is only one other option at this time: "influxlambda" # There are two other options at this time: "influxlambda" and "prometheus"
# #
# Lambda mode makes the application exit after collecting and reporting metrics # Lambda mode makes the application exit after collecting and reporting metrics
# to InfluxDB one time. This mode requires an external process like an AWS Lambda # to InfluxDB one time. This mode requires an external process like an AWS Lambda
# or a simple crontab to keep the timings accurate on UniFi Poller run intervals. # or a simple crontab to keep the timings accurate on UniFi Poller run intervals.
#
# Prometheus mode opens an HTTP server on port 61317 and exports the metrics at
# /metrics for polling collection by a prometheus server. This disables influxdb.
--> -->
<mode>influx</mode> <mode>influx</mode>
<!--
# This controls on which ip and port /metrics is exported when mode is "prometheus".
# This has no effect in other modes. Must contain a colon and port.
-->
<http_listen>0.0.0.0:61317</http_listen>
<!-- <!--
# InfluxDB does not require auth by default, so the user/password are probably unimportant. # InfluxDB does not require auth by default, so the user/password are probably unimportant.
--> -->

View File

@ -25,13 +25,20 @@ quiet: false
# an invalid mode will also result in "influx". In this default mode the application # an invalid mode will also result in "influx". In this default mode the application
# runs as a daemon and polls the controller at the configured interval. # runs as a daemon and polls the controller at the configured interval.
# #
# There is only one other option at this time: "influxlambda" # There are two other options at this time: "influxlambda" and "prometheus"
# #
# Lambda mode makes the application exit after collecting and reporting metrics # Lambda mode makes the application exit after collecting and reporting metrics
# to InfluxDB one time. This mode requires an external process like an AWS Lambda # to InfluxDB one time. This mode requires an external process like an AWS Lambda
# or a simple crontab to keep the timings accurate on UniFi Poller run intervals. # or a simple crontab to keep the timings accurate on UniFi Poller run intervals.
#
# Prometheus mode opens an HTTP server on port 61317 and exports the metrics at
# /metrics for polling collection by a prometheus server. This disables influxdb.
mode: "influx" mode: "influx"
# This controls on which ip and port /metrics is exported when mode is "prometheus".
# This has no effect in other modes. Must contain a colon and port.
http_listen: "0.0.0.0:61317"
# InfluxDB does not require auth by default, so the user/password are probably unimportant. # InfluxDB does not require auth by default, so the user/password are probably unimportant.
influx_url: "http://127.0.0.1:8086" influx_url: "http://127.0.0.1:8086"
influx_user: "unifi" influx_user: "unifi"

View File

@ -31,6 +31,7 @@ const (
defaultInfluxURL = "http://127.0.0.1:8086" defaultInfluxURL = "http://127.0.0.1:8086"
defaultUnifiUser = "influx" defaultUnifiUser = "influx"
defaultUnifiURL = "https://127.0.0.1:8443" defaultUnifiURL = "https://127.0.0.1:8443"
defaultHTTPListen = ":61317"
) )
// ENVConfigPrefix is the prefix appended to an env variable tag // ENVConfigPrefix is the prefix appended to an env variable tag
@ -77,6 +78,7 @@ type Config struct {
ReAuth bool `json:"reauthenticate" toml:"reauthenticate" xml:"reauthenticate" yaml:"reauthenticate" env:"REAUTHENTICATE"` ReAuth bool `json:"reauthenticate" toml:"reauthenticate" xml:"reauthenticate" yaml:"reauthenticate" env:"REAUTHENTICATE"`
InfxBadSSL bool `json:"influx_insecure_ssl" toml:"influx_insecure_ssl" xml:"influx_insecure_ssl" yaml:"influx_insecure_ssl" env:"INFLUX_INSECURE_SSL"` InfxBadSSL bool `json:"influx_insecure_ssl" toml:"influx_insecure_ssl" xml:"influx_insecure_ssl" yaml:"influx_insecure_ssl" env:"INFLUX_INSECURE_SSL"`
Mode string `json:"mode" toml:"mode" xml:"mode" yaml:"mode" env:"POLLING_MODE"` Mode string `json:"mode" toml:"mode" xml:"mode" yaml:"mode" env:"POLLING_MODE"`
HTTPListen string `json:"http_listen" toml:"http_listen" xml:"http_listen" yaml:"http_listen" env:"HTTP_LISTEN"`
InfluxURL string `json:"influx_url,omitempty" toml:"influx_url,omitempty" xml:"influx_url" yaml:"influx_url" env:"INFLUX_URL"` InfluxURL string `json:"influx_url,omitempty" toml:"influx_url,omitempty" xml:"influx_url" yaml:"influx_url" env:"INFLUX_URL"`
InfluxUser string `json:"influx_user,omitempty" toml:"influx_user,omitempty" xml:"influx_user" yaml:"influx_user" env:"INFLUX_USER"` InfluxUser string `json:"influx_user,omitempty" toml:"influx_user,omitempty" xml:"influx_user" yaml:"influx_user" env:"INFLUX_USER"`
InfluxPass string `json:"influx_pass,omitempty" toml:"influx_pass,omitempty" xml:"influx_pass" yaml:"influx_pass" env:"INFLUX_PASS"` InfluxPass string `json:"influx_pass,omitempty" toml:"influx_pass,omitempty" xml:"influx_pass" yaml:"influx_pass" env:"INFLUX_PASS"`

View File

@ -4,11 +4,13 @@ import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"log" "log"
"net/http"
"os" "os"
"strings" "strings"
"time" "time"
influx "github.com/influxdata/influxdb1-client/v2" influx "github.com/influxdata/influxdb1-client/v2"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"golift.io/unifi" "golift.io/unifi"
) )
@ -30,6 +32,7 @@ func Start() error {
UnifiBase: defaultUnifiURL, UnifiBase: defaultUnifiURL,
Interval: Duration{defaultInterval}, Interval: Duration{defaultInterval},
Sites: []string{"all"}, Sites: []string{"all"},
HTTPListen: defaultHTTPListen,
}} }}
up.Flag.Parse(os.Args[1:]) up.Flag.Parse(os.Args[1:])
if up.Flag.ShowVer { if up.Flag.ShowVer {
@ -83,14 +86,28 @@ func (u *UnifiPoller) Run() (err error) {
if err = u.GetInfluxDB(); err != nil { if err = u.GetInfluxDB(); err != nil {
return err return err
} }
u.Logf("Logging Measurements to InfluxDB at %s as user %s", u.Config.InfluxURL, u.Config.InfluxUser)
switch strings.ToLower(u.Config.Mode) { switch strings.ToLower(u.Config.Mode) {
case "influxlambda", "lambdainflux", "lambda_influx", "influx_lambda": case "influxlambda", "lambdainflux", "lambda_influx", "influx_lambda":
u.LogDebugf("Lambda Mode Enabled") u.Logf("Logging Measurements to InfluxDB at %s as user %s one time (lambda mode)",
u.Config.InfluxURL, u.Config.InfluxUser)
u.LastCheck = time.Now() u.LastCheck = time.Now()
return u.CollectAndReport() return u.CollectAndProcess(u.ReportMetrics)
case "prometheus", "exporter":
u.Logf("Exporting Measurements at https://%s/metrics for Prometheus", u.Config.HTTPListen)
u.Config.Mode = "http exporter"
http.Handle("/metrics", promhttp.Handler())
go func() {
err = http.ListenAndServe(u.Config.HTTPListen, nil)
if err != http.ErrServerClosed {
log.Fatalf("[ERROR] http server: %v", err)
}
}()
return u.PollController(u.ExportMetrics)
default: default:
return u.PollController() u.Logf("Logging Measurements to InfluxDB at %s as user %s", u.Config.InfluxURL, u.Config.InfluxUser)
u.Config.Mode = "influx poller"
return u.PollController(u.ReportMetrics)
} }
} }

View File

@ -43,11 +43,12 @@ FIRST:
return nil return nil
} }
// PollController runs forever, polling UniFi, and pushing to influx. // PollController runs forever, polling UniFi
// and pushing to influx OR exporting for prometheus.
// This is started by Run() after everything checks out. // This is started by Run() after everything checks out.
func (u *UnifiPoller) PollController() error { func (u *UnifiPoller) PollController(process func(*Metrics) error) error {
interval := u.Config.Interval.Round(time.Second) interval := u.Config.Interval.Round(time.Second)
log.Println("[INFO] Everything checks out! Poller started, interval:", interval) log.Printf("[INFO] Everything checks out! Poller started in %v mode, interval: %v", u.Config.Mode, interval)
ticker := time.NewTicker(interval) ticker := time.NewTicker(interval)
for u.LastCheck = range ticker.C { for u.LastCheck = range ticker.C {
var err error var err error
@ -60,7 +61,7 @@ func (u *UnifiPoller) PollController() error {
} }
if err == nil { if err == nil {
// Only run this if the authentication procedure didn't return error. // Only run this if the authentication procedure didn't return error.
_ = u.CollectAndReport() _ = u.CollectAndProcess(process)
} }
if u.errorCount > 0 { if u.errorCount > 0 {
return fmt.Errorf("controller or influxdb errors, stopping poller") return fmt.Errorf("controller or influxdb errors, stopping poller")
@ -69,12 +70,13 @@ func (u *UnifiPoller) PollController() error {
return nil return nil
} }
// CollectAndReport collects measurements and reports them to influxdb. // CollectAndProcess collects measurements and then passese them into the
// provided method. The method is either an http exporter or an influxdb update.
// Can be called once or in a ticker loop. This function and all the ones below // Can be called once or in a ticker loop. This function and all the ones below
// handle their own logging. An error is returned so the calling function may // handle their own logging. An error is returned so the calling function may
// determine if there was a read or write error and act on it. This is currently // determine if there was a read or write error and act on it. This is currently
// called in two places in this library. One returns an error, one does not. // called in two places in this library. One returns an error, one does not.
func (u *UnifiPoller) CollectAndReport() error { func (u *UnifiPoller) CollectAndProcess(process func(*Metrics) error) error {
metrics, err := u.CollectMetrics() metrics, err := u.CollectMetrics()
if err != nil { if err != nil {
return err return err
@ -82,8 +84,8 @@ func (u *UnifiPoller) CollectAndReport() error {
if err := u.AugmentMetrics(metrics); err != nil { if err := u.AugmentMetrics(metrics); err != nil {
return err return err
} }
err = u.ReportMetrics(metrics) err = process(metrics)
u.LogError(err, "reporting metrics") u.LogError(err, "processing metrics")
return err return err
} }
@ -145,6 +147,15 @@ func (u *UnifiPoller) AugmentMetrics(metrics *Metrics) error {
return nil return nil
} }
// ExportMetrics updates the internal metrics provided via
// HTTP at /metrics for prometheus collection.
func (u *UnifiPoller) ExportMetrics(metrics *Metrics) error {
/*
This is where it gets complicated, and probably deserves its own package.
*/
return nil
}
// ReportMetrics batches all the metrics and writes them to InfluxDB. // ReportMetrics batches all the metrics and writes them to InfluxDB.
// Returns an error if the write to influx fails. // Returns an error if the write to influx fails.
func (u *UnifiPoller) ReportMetrics(metrics *Metrics) error { func (u *UnifiPoller) ReportMetrics(metrics *Metrics) error {