Use a config file instead of env vars.
This commit is contained in:
		
							parent
							
								
									f710b5cb6a
								
							
						
					
					
						commit
						5303a86b25
					
				| 
						 | 
					@ -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",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,8 +32,8 @@ 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"`
 | 
				
			||||||
| 
						 | 
					@ -38,3 +42,18 @@ type Config struct {
 | 
				
			||||||
	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