add support for pi-hole running behind https

This adds support for a new environment variable `PIHOLE_PROTOCOL`,
which defaults to `http`.
This commit is contained in:
Spike Grobstein 2020-06-05 15:03:29 -07:00
parent 8cd4287e69
commit 36aaa18f45
4 changed files with 33 additions and 8 deletions

View file

@ -61,6 +61,21 @@ $ docker run \
ekofr/pihole-exporter:latest ekofr/pihole-exporter:latest
``` ```
If you are running pi-hole behind https, you must both set the `PIHOLE_PROTOCOL` environment variable
as well as include your ssl certificates to the docker image as it does not have any baked in:
```
$ docker run \
-e 'PIHOLE_PROTOCOL=https' \
-e 'PIHOLE_HOSTNAME=192.168.1.2' \
-e 'PIHOLE_PASSWORD=mypassword' \
-e 'INTERVAL=30s' \
-e 'PORT=9617' \
-v '/etc/ssl/certs:/etc/ssl/certs:ro' \
-p 9617:9617 \
ekofr/pihole-exporter:latest
```
### From sources ### From sources
Optionally, you can download and build it from the sources. You have to retrieve the project sources by using one of the following way: Optionally, you can download and build it from the sources. You have to retrieve the project sources by using one of the following way:

View file

@ -15,6 +15,7 @@ import (
// Config is the exporter CLI configuration. // Config is the exporter CLI configuration.
type Config struct { type Config struct {
PIHoleProtocol string `config:"pihole_protocol"`
PIHoleHostname string `config:"pihole_hostname"` PIHoleHostname string `config:"pihole_hostname"`
PIHolePassword string `config:"pihole_password"` PIHolePassword string `config:"pihole_password"`
PIHoleApiToken string `config:"pihole_api_token"` PIHoleApiToken string `config:"pihole_api_token"`
@ -24,6 +25,7 @@ type Config struct {
func getDefaultConfig() *Config { func getDefaultConfig() *Config {
return &Config{ return &Config{
PIHoleProtocol: "http",
PIHoleHostname: "127.0.0.1", PIHoleHostname: "127.0.0.1",
PIHolePassword: "", PIHolePassword: "",
PIHoleApiToken: "", PIHoleApiToken: "",

View file

@ -7,6 +7,7 @@ import (
"log" "log"
"net/http" "net/http"
"net/url" "net/url"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -15,14 +16,15 @@ import (
) )
var ( var (
loginURLPattern = "http://%s/admin/index.php?login" loginURLPattern = "%s://%s/admin/index.php?login"
statsURLPattern = "http://%s/admin/api.php?summaryRaw&overTimeData&topItems&recentItems&getQueryTypes&getForwardDestinations&getQuerySources&jsonForceObject" statsURLPattern = "%s://%s/admin/api.php?summaryRaw&overTimeData&topItems&recentItems&getQueryTypes&getForwardDestinations&getQuerySources&jsonForceObject"
) )
// Client struct is a PI-Hole client to request an instance of a PI-Hole ad blocker. // Client struct is a PI-Hole client to request an instance of a PI-Hole ad blocker.
type Client struct { type Client struct {
httpClient http.Client httpClient http.Client
interval time.Duration interval time.Duration
protocol string
hostname string hostname string
password string password string
sessionID string sessionID string
@ -30,8 +32,14 @@ type Client struct {
} }
// NewClient method initializes a new PI-Hole client. // NewClient method initializes a new PI-Hole client.
func NewClient(hostname, password, apiToken string, interval time.Duration) *Client { func NewClient(protocol, hostname, password, apiToken string, interval time.Duration) *Client {
if protocol != "http" && protocol != "https" {
log.Printf("protocol %s is invalid. Must be http or https.", protocol)
os.Exit(1)
}
return &Client{ return &Client{
protocol: protocol,
hostname: hostname, hostname: hostname,
password: password, password: password,
apiToken: apiToken, apiToken: apiToken,
@ -101,7 +109,7 @@ func (c *Client) setMetrics(stats *Stats) {
} }
func (c *Client) getPHPSessionID() (sessionID string) { func (c *Client) getPHPSessionID() (sessionID string) {
loginURL := fmt.Sprintf(loginURLPattern, c.hostname) loginURL := fmt.Sprintf(loginURLPattern, c.protocol, c.hostname)
values := url.Values{"pw": []string{c.password}} values := url.Values{"pw": []string{c.password}}
req, err := http.NewRequest("POST", loginURL, strings.NewReader(values.Encode())) req, err := http.NewRequest("POST", loginURL, strings.NewReader(values.Encode()))
@ -130,7 +138,7 @@ func (c *Client) getPHPSessionID() (sessionID string) {
func (c *Client) getStatistics() *Stats { func (c *Client) getStatistics() *Stats {
var stats Stats var stats Stats
statsURL := fmt.Sprintf(statsURLPattern, c.hostname) statsURL := fmt.Sprintf(statsURLPattern, c.protocol, c.hostname)
if c.isUsingApiToken() { if c.isUsingApiToken() {
statsURL = fmt.Sprintf("%s&auth=%s", statsURL, c.apiToken) statsURL = fmt.Sprintf("%s&auth=%s", statsURL, c.apiToken)

View file

@ -26,14 +26,14 @@ func main() {
metrics.Init() metrics.Init()
initPiHoleClient(conf.PIHoleHostname, conf.PIHolePassword, conf.PIHoleApiToken, conf.Interval) initPiHoleClient(conf.PIHoleProtocol, conf.PIHoleHostname, conf.PIHolePassword, conf.PIHoleApiToken, conf.Interval)
initHttpServer(conf.Port) initHttpServer(conf.Port)
handleExitSignal() handleExitSignal()
} }
func initPiHoleClient(hostname, password, apiToken string, interval time.Duration) { func initPiHoleClient(protocol, hostname, password, apiToken string, interval time.Duration) {
client := pihole.NewClient(hostname, password, apiToken, interval) client := pihole.NewClient(protocol, hostname, password, apiToken, interval)
go client.Scrape() go client.Scrape()
} }