Use a config file instead of env vars.
This commit is contained in:
parent
74c64be507
commit
bb0e3ccfd8
17
.env.example
17
.env.example
|
|
@ -1,17 +0,0 @@
|
||||||
UNIFI_ADDR="107.170.232.179"
|
|
||||||
UNIFI_PORT="8443"
|
|
||||||
# Go to Settings -> Admins and add (or use) a read-only user for this.
|
|
||||||
UNIFI_USERNAME="username"
|
|
||||||
UNIFI_PASSWORD="password"
|
|
||||||
|
|
||||||
# Can be 1m15s for 1 minute 0 seconds, 15s for 15 seconds, etc.
|
|
||||||
INTERVAL="15s"
|
|
||||||
|
|
||||||
INFLUXDB_ADDR="http://hostname:8086"
|
|
||||||
INFLUXDB_DATABASE="unifi"
|
|
||||||
INFLUXDB_USERNAME="unifi"
|
|
||||||
INFLUXDB_PASSWORD="password"
|
|
||||||
|
|
||||||
export UNIFI_ADDR UNIFI_PORT UNIFI_USERNAME UNIFI_PASSWORD
|
|
||||||
export INTERVAL
|
|
||||||
export INFLUXDB_ADDR INFLUXDB_DATABASE INFLUXDB_USERNAME INFLUXDB_PASSWORD
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
.env
|
/up.conf
|
||||||
/unifi-poller
|
/unifi-poller
|
||||||
/*.1.gz
|
/*.1.gz
|
||||||
/*.1
|
/*.1
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,26 @@
|
||||||
"Comment": "v1.5.0-149-g14dcc5d",
|
"Comment": "v1.5.0-149-g14dcc5d",
|
||||||
"Rev": "14dcc5d6e7a6b15e17aba7b104b8ad0ca6c91ad2"
|
"Rev": "14dcc5d6e7a6b15e17aba7b104b8ad0ca6c91ad2"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/naoina/go-stringutil",
|
||||||
|
"Comment": "v0.1.0",
|
||||||
|
"Rev": "6b638e95a32d0c1131db0e7fe83775cbea4a0d0b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/naoina/toml",
|
||||||
|
"Comment": "v0.1.0",
|
||||||
|
"Rev": "751171607256bb66e64c9f0220c00662420c38e9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/naoina/toml/ast",
|
||||||
|
"Comment": "v0.1.0",
|
||||||
|
"Rev": "751171607256bb66e64c9f0220c00662420c38e9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/ogier/pflag",
|
||||||
|
"Comment": "v0.0.1-7-g45c278a",
|
||||||
|
"Rev": "45c278ab3607870051a2ea9040bb85fcb8557481"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/pkg/errors",
|
"ImportPath": "github.com/pkg/errors",
|
||||||
"Comment": "v0.8.0-6-g2b3a18b",
|
"Comment": "v0.8.0-6-g2b3a18b",
|
||||||
|
|
|
||||||
16
README.md
16
README.md
|
|
@ -1,20 +1,12 @@
|
||||||
# Unifi
|
# Unifi
|
||||||
|
|
||||||
Collect your Unifi Controller Client data and send it to an InfluxDB instance.
|
Collect your Unifi Controller Client data and send it to an InfluxDB instance. Grafana dashboard included.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Deploying
|
## Installation
|
||||||
|
|
||||||
|
[See the Wiki!](https://github.com/davidnewhall/unifi-poller/wiki/Installation)
|
||||||
Clone the repository and using `.env.example` create your own `.env` file with your Unifi GUI and InfluxDB credentials.
|
|
||||||
|
|
||||||
|
|
||||||
Set your environment variables before running:
|
|
||||||
|
|
||||||
```
|
|
||||||
source .env ; ./unifi-poller
|
|
||||||
```
|
|
||||||
|
|
||||||
## Copyright & License
|
## Copyright & License
|
||||||
Copyright © 2016 Garrett Bjerkhoel. See [MIT-LICENSE](http://github.com/dewski/unifi/blob/master/MIT-LICENSE) for details.
|
Copyright © 2016 Garrett Bjerkhoel. See [MIT-LICENSE](MIT-LICENSE) for details.
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Version will be injected at build time.
|
||||||
|
var Version = "v0.1"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// LoginPath is Unifi Controller Login API Path
|
// LoginPath is Unifi Controller Login API Path
|
||||||
LoginPath = "/api/login"
|
LoginPath = "/api/login"
|
||||||
|
|
@ -17,6 +20,7 @@ const (
|
||||||
// UserGroupPath contains usergroup configurations.
|
// UserGroupPath contains usergroup configurations.
|
||||||
UserGroupPath = "/api/s/default/rest/usergroup"
|
UserGroupPath = "/api/s/default/rest/usergroup"
|
||||||
// App defaults in case they're missing from the config.
|
// App defaults in case they're missing from the config.
|
||||||
|
defaultConfFile = "/usr/local/etc/unifi-poller/up.conf"
|
||||||
defaultInterval = 30 * time.Second
|
defaultInterval = 30 * time.Second
|
||||||
defaultInfxDb = "unifi"
|
defaultInfxDb = "unifi"
|
||||||
defaultInfxUser = "unifi"
|
defaultInfxUser = "unifi"
|
||||||
|
|
@ -28,13 +32,28 @@ const (
|
||||||
|
|
||||||
// Config represents the data needed to poll a controller and report to influxdb.
|
// Config represents the data needed to poll a controller and report to influxdb.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Interval time.Duration `json:"interval" toml:"interval" xml:"interval" yaml:"interval"`
|
Interval Dur `json:"interval" toml:"interval" xml:"interval" yaml:"interval"`
|
||||||
InfluxURL string `json:"influx_url" toml:"influx_addr" xml:"influx_addr" yaml:"influx_addr"`
|
InfluxURL string `json:"influx_url" toml:"influx_url" xml:"influx_url" yaml:"influx_url"`
|
||||||
InfluxUser string `json:"influx_user" toml:"influx_user" xml:"influx_user" yaml:"influx_user"`
|
InfluxUser string `json:"influx_user" toml:"influx_user" xml:"influx_user" yaml:"influx_user"`
|
||||||
InfluxPass string `json:"influx_pass" toml:"influx_pass" xml:"influx_pass" yaml:"influx_pass"`
|
InfluxPass string `json:"influx_pass" toml:"influx_pass" xml:"influx_pass" yaml:"influx_pass"`
|
||||||
InfluxDB string `json:"influx_db" toml:"influx_db" xml:"influx_db" yaml:"influx_db"`
|
InfluxDB string `json:"influx_db" toml:"influx_db" xml:"influx_db" yaml:"influx_db"`
|
||||||
UnifiUser string `json:"unifi_user" toml:"unifi_user" xml:"unifi_user" yaml:"unifi_user"`
|
UnifiUser string `json:"unifi_user" toml:"unifi_user" xml:"unifi_user" yaml:"unifi_user"`
|
||||||
UnifiPass string `json:"unifi_pass" toml:"unifi_pass" xml:"unifi_pass" yaml:"unifi_pass"`
|
UnifiPass string `json:"unifi_pass" toml:"unifi_pass" xml:"unifi_pass" yaml:"unifi_pass"`
|
||||||
UnifiBase string `json:"unifi_url" toml:"unifi_url" xml:"unifi_url" yaml:"unifi_url"`
|
UnifiBase string `json:"unifi_url" toml:"unifi_url" xml:"unifi_url" yaml:"unifi_url"`
|
||||||
uniClient *http.Client
|
uniClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dur is used to UnmarshalTOML into a time.Duration value.
|
||||||
|
type Dur struct {
|
||||||
|
value time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalTOML parses a duration type from a config file.
|
||||||
|
func (v *Dur) UnmarshalTOML(data []byte) error {
|
||||||
|
unquoted := string(data[1 : len(data)-1])
|
||||||
|
dur, err := time.ParseDuration(unquoted)
|
||||||
|
if err == nil {
|
||||||
|
v.value = dur
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -12,15 +13,36 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
influx "github.com/influxdata/influxdb/client/v2"
|
influx "github.com/influxdata/influxdb/client/v2"
|
||||||
|
"github.com/naoina/toml"
|
||||||
|
flg "github.com/ogier/pflag"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
config := GetConfig()
|
flg.Usage = func() {
|
||||||
|
fmt.Println("Usage: unifi-poller [--config=filepath] [--debug] [--version]")
|
||||||
|
flg.PrintDefaults()
|
||||||
|
}
|
||||||
|
configFile := flg.StringP("config", "c", defaultConfFile, "Poller Config File (TOML Format)")
|
||||||
|
debug := flg.BoolP("debug", "D", false, "Turn on the Spam (default false)")
|
||||||
|
version := flg.BoolP("version", "v", false, "Print the version and exit.")
|
||||||
|
flg.Parse()
|
||||||
|
if *version {
|
||||||
|
fmt.Println("unifi-poller version:", Version)
|
||||||
|
os.Exit(0) // don't run anything else.
|
||||||
|
}
|
||||||
|
if log.SetFlags(0); *debug {
|
||||||
|
log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate)
|
||||||
|
}
|
||||||
|
config, errc := GetConfig(*configFile)
|
||||||
|
if errc != nil {
|
||||||
|
flg.Usage()
|
||||||
|
log.Fatalln("Config Error:", errc)
|
||||||
|
}
|
||||||
if err := config.AuthController(); err != nil {
|
if err := config.AuthController(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
log.Println("Authenticated to Unifi Controller", config.UnifiBase, "as user", config.UnifiUser)
|
log.Println("Authenticated to Unifi Controller @", config.UnifiBase, "as user", config.UnifiUser)
|
||||||
|
|
||||||
infdb, err := influx.NewHTTPClient(influx.HTTPConfig{
|
infdb, err := influx.NewHTTPClient(influx.HTTPConfig{
|
||||||
Addr: config.InfluxURL,
|
Addr: config.InfluxURL,
|
||||||
|
|
@ -31,28 +53,30 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
log.Println("Logging Unifi Metrics to InfluXDB @", config.InfluxURL, "as user", config.InfluxUser)
|
log.Println("Logging Unifi Metrics to InfluXDB @", config.InfluxURL, "as user", config.InfluxUser)
|
||||||
log.Println("Polling Unifi Controller, interval:", config.Interval)
|
log.Println("Polling Unifi Controller, interval:", config.Interval.value)
|
||||||
config.PollUnifiController(infdb)
|
config.PollUnifiController(infdb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConfig parses and returns our configuration data.
|
// GetConfig parses and returns our configuration data.
|
||||||
func GetConfig() Config {
|
func GetConfig(configFile string) (Config, error) {
|
||||||
// TODO: A real config file.
|
// Preload our defaults.
|
||||||
interval, err := time.ParseDuration(os.Getenv("INTERVAL"))
|
config := Config{
|
||||||
if err != nil {
|
InfluxURL: defaultInfxURL,
|
||||||
log.Println("Invalid Interval, defaulting to", defaultInterval)
|
InfluxUser: defaultInfxUser,
|
||||||
interval = time.Duration(defaultInterval)
|
InfluxPass: defaultInfxPass,
|
||||||
}
|
InfluxDB: defaultInfxDb,
|
||||||
return Config{
|
UnifiUser: defaultUnifUser,
|
||||||
InfluxURL: os.Getenv("INFLUXDB_URL"),
|
|
||||||
InfluxUser: os.Getenv("INFLUXDB_USERNAME"),
|
|
||||||
InfluxPass: os.Getenv("INFLUXDB_PASSWORD"),
|
|
||||||
InfluxDB: os.Getenv("INFLUXDB_DATABASE"),
|
|
||||||
UnifiUser: os.Getenv("UNIFI_USERNAME"),
|
|
||||||
UnifiPass: os.Getenv("UNIFI_PASSWORD"),
|
UnifiPass: os.Getenv("UNIFI_PASSWORD"),
|
||||||
UnifiBase: "https://" + os.Getenv("UNIFI_ADDR") + ":" + os.Getenv("UNIFI_PORT"),
|
UnifiBase: defaultUnifURL,
|
||||||
Interval: interval,
|
Interval: Dur{value: defaultInterval},
|
||||||
}
|
}
|
||||||
|
if buf, err := ioutil.ReadFile(configFile); err != nil {
|
||||||
|
return config, err
|
||||||
|
// This is where the defaults in the config variable are overwritten.
|
||||||
|
} else if err := toml.Unmarshal(buf, &config); err != nil {
|
||||||
|
return config, errors.Wrap(err, "invalid config")
|
||||||
|
}
|
||||||
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthController creates a http.Client with authenticated cookies.
|
// AuthController creates a http.Client with authenticated cookies.
|
||||||
|
|
@ -80,7 +104,7 @@ func (c *Config) AuthController() error {
|
||||||
|
|
||||||
// PollUnifiController runs forever, polling and pushing.
|
// PollUnifiController runs forever, polling and pushing.
|
||||||
func (c *Config) PollUnifiController(infdb influx.Client) {
|
func (c *Config) PollUnifiController(infdb influx.Client) {
|
||||||
ticker := time.NewTicker(c.Interval)
|
ticker := time.NewTicker(c.Interval.value)
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
clients, err := c.GetUnifiClients()
|
clients, err := c.GetUnifiClients()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 909 KiB After Width: | Height: | Size: 246 KiB |
|
|
@ -0,0 +1,15 @@
|
||||||
|
# The Unifi Controller only updates traffic stats about every 30 seconds.
|
||||||
|
# Setting this to something lower may lead to "zeros" in your data. You've been warned.
|
||||||
|
interval = "30s"
|
||||||
|
|
||||||
|
# InfluxDB does not require auth by default, so the user/password are probably unimportant.
|
||||||
|
influx_url = "http://127.0.0.1:8086"
|
||||||
|
influx_user = "unifi"
|
||||||
|
influx_pass = "unifi"
|
||||||
|
# Be sure to create this database.
|
||||||
|
influx_db = "unifi"
|
||||||
|
|
||||||
|
# Make a read-only user in the Unifi Admin Settings.
|
||||||
|
unifi_user = "influxdb"
|
||||||
|
unifi_pass = "4BB9345C-2341-48D7-99F5-E01B583FF77F"
|
||||||
|
unifi_url = "https://127.0.0.1:8443"
|
||||||
Loading…
Reference in New Issue