Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bugfix] When multiple host is specified, one port/protocol can't be specified #105

Merged
merged 3 commits into from
Dec 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 54 additions & 28 deletions config/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"context"
"errors"
"fmt"
"log"
"reflect"
Expand Down Expand Up @@ -46,7 +47,7 @@ func getDefaultEnvConfig() *EnvConfig {
}

// Load method loads the configuration by using both flag or environment variables.
func Load() (*EnvConfig, []Config) {
func Load() (*EnvConfig, []Config, error) {
loaders := []backend.Backend{
env.NewBackend(),
flags.NewBackend(),
Expand All @@ -62,7 +63,11 @@ func Load() (*EnvConfig, []Config) {

cfg.show()

return cfg, cfg.Split()
if clientsConfig, err := cfg.Split(); err != nil {
return cfg, nil, err
} else {
return cfg, clientsConfig, nil
}
}

func (c *Config) String() string {
Expand All @@ -87,43 +92,64 @@ func (c Config) Validate() error {
return nil
}

func (c EnvConfig) Split() []Config {
result := make([]Config, 0, len(c.PIHoleHostname))
func (c EnvConfig) Split() ([]Config, error) {
hostsCount := len(c.PIHoleHostname)
result := make([]Config, 0, hostsCount)

for i, hostname := range c.PIHoleHostname {
config := Config{
PIHoleHostname: hostname,
PIHoleProtocol: c.PIHoleProtocol[i],
PIHolePort: c.PIHolePort[i],
PIHoleHostname: strings.TrimSpace(hostname),
}

if len(c.PIHolePort) == 1 {
config.PIHolePort = c.PIHolePort[0]
} else if len(c.PIHolePort) == hostsCount {
config.PIHolePort = c.PIHolePort[i]
} else if len(c.PIHolePort) != 0 {
return nil, errors.New("Wrong number of ports. Port can be empty to use default, one value to use for all hosts, or match the number of hosts")
}

if c.PIHoleApiToken != nil {
if len(c.PIHoleApiToken) == 1 {
if c.PIHoleApiToken[0] != "" {
config.PIHoleApiToken = c.PIHoleApiToken[0]
}
} else if len(c.PIHoleApiToken) > 1 {
if c.PIHoleApiToken[i] != "" {
config.PIHoleApiToken = c.PIHoleApiToken[i]
}
}
if hasData, data, isValid := extractStringConfig(c.PIHoleProtocol, i, hostsCount); hasData {
config.PIHoleProtocol = data
} else if !isValid {
return nil, errors.New("Wrong number of PIHoleProtocol. PIHoleProtocol can be empty to use default, one value to use for all hosts, or match the number of hosts")
}

if c.PIHolePassword != nil {
if len(c.PIHolePassword) == 1 {
if c.PIHolePassword[0] != "" {
config.PIHolePassword = c.PIHolePassword[0]
}
} else if len(c.PIHolePassword) > 1 {
if c.PIHolePassword[i] != "" {
config.PIHolePassword = c.PIHolePassword[i]
}
}
if hasData, data, isValid := extractStringConfig(c.PIHoleApiToken, i, hostsCount); hasData {
config.PIHoleApiToken = data
} else if !isValid {
return nil, errors.New(fmt.Sprintf("Wrong number of PIHoleApiToken %d (Hosts: %d). PIHoleApiToken can be empty to use default, one value to use for all hosts, or match the number of hosts", len(c.PIHoleApiToken), hostsCount))
}

if hasData, data, isValid := extractStringConfig(c.PIHolePassword, i, hostsCount); hasData {
config.PIHolePassword = data
} else if !isValid {
return nil, errors.New("Wrong number of PIHolePassword. PIHolePassword can be empty to use default, one value to use for all hosts, or match the number of hosts")
}

result = append(result, config)
}
return result

return result, nil
}

func extractStringConfig(data []string, idx int, hostsCount int) (bool, string, bool) {
if len(data) == 1 {
v := strings.TrimSpace(data[0])
if v != "" {
return true, v, true
}
} else if len(data) == hostsCount {
v := strings.TrimSpace(data[idx])
if v != "" {
return true, v, true
}
} else if len(data) != 0 { //Host count missmatch
return false, "", false
}

// Empty
return false, "", true
}

func (c Config) hostnameURL() string {
Expand Down
154 changes: 154 additions & 0 deletions config/configuration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package config

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

const (
PIHOLE_HOSTNAME = "PIHOLE_HOSTNAME"
PIHOLE_PORT = "PIHOLE_PORT"
PIHOLE_API_TOKEN = "PIHOLE_API_TOKEN"
PIHOLE_PROTOCOL = "PIHOLE_PROTOCOL"
)

type EnvInitiazlier func(*testing.T)

type TestCase struct {
Name string
Initializer EnvInitiazlier
}

func TestSplitDefault(t *testing.T) {
assert := assert.New(t)

env := getDefaultEnvConfig()

clientConfigs, err := env.Split()
assert.NoError(err)

clientConfig := clientConfigs[0]
assert.Equal("127.0.0.1", clientConfig.PIHoleHostname)
assert.Equal("http", clientConfig.PIHoleProtocol)
assert.Equal(uint16(80), clientConfig.PIHolePort)
assert.Empty(clientConfig.PIHoleApiToken)
assert.Empty(clientConfig.PIHolePassword)
}

func TestSplitMultipleHostWithSameConfig(t *testing.T) {
assert := assert.New(t)

env := getDefaultEnvConfig()
env.PIHoleHostname = []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}
env.PIHoleApiToken = []string{"api-token"}
env.PIHolePort = []uint16{8080}

clientConfigs, err := env.Split()
assert.NoError(err)
assert.Len(clientConfigs, 3)

testCases := []struct {
Host string
Port uint16
Protocol string
}{
{
Host: "127.0.0.1",
Port: 8080,
Protocol: "http",
},
{
Host: "127.0.0.2",
Port: 8080,
Protocol: "http",
},
{
Host: "127.0.0.3",
Port: 8080,
Protocol: "http",
},
}

for i, tc := range testCases {
t.Run(fmt.Sprintf("Test %s", tc.Host), func(t *testing.T) {
clientConfig := clientConfigs[i]

assert.Equal(tc.Host, clientConfig.PIHoleHostname)
assert.Equal(tc.Protocol, clientConfig.PIHoleProtocol)
assert.Equal(tc.Port, clientConfig.PIHolePort)
assert.Equal("api-token", clientConfig.PIHoleApiToken)
assert.Empty(clientConfig.PIHolePassword)
})
}
}

func TestSplitMultipleHostWithMultipleConfigs(t *testing.T) {
assert := assert.New(t)

env := getDefaultEnvConfig()
env.PIHoleHostname = []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}
env.PIHoleApiToken = []string{"api-token1", "", "api-token3"}
env.PIHolePassword = []string{"", "password2", ""}
env.PIHolePort = []uint16{8081, 8082, 8083}

clientConfigs, err := env.Split()
assert.NoError(err)
assert.Len(clientConfigs, 3)

testCases := []struct {
Host string
Port uint16
Protocol string
ApiToken string
Password string
}{
{
Host: "127.0.0.1",
Port: 8081,
Protocol: "http",
ApiToken: "api-token1",
Password: "",
},
{
Host: "127.0.0.2",
Port: 8082,
Protocol: "http",
ApiToken: "",
Password: "password2",
},
{
Host: "127.0.0.3",
Port: 8083,
Protocol: "http",
ApiToken: "api-token3",
Password: "",
},
}

for i, tc := range testCases {
t.Run(fmt.Sprintf("Test %s", tc.Host), func(t *testing.T) {
clientConfig := clientConfigs[i]

assert.Equal(tc.Host, clientConfig.PIHoleHostname)
assert.Equal(tc.Protocol, clientConfig.PIHoleProtocol)
assert.Equal(tc.Port, clientConfig.PIHolePort)
assert.Equal(tc.ApiToken, clientConfig.PIHoleApiToken)
assert.Equal(tc.Password, clientConfig.PIHolePassword)
})
}
}

func TestWrongParams(t *testing.T) {
assert := assert.New(t)

env := getDefaultEnvConfig()
env.PIHoleHostname = []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}
env.PIHoleApiToken = []string{"api-token1", "api-token2"}
env.PIHolePort = []uint16{808}

clientConfigs, err := env.Split()
assert.Errorf(err, "Wrong number of PIHoleApiToken. PIHoleApiToken can be empty to use default, one value to use for all hosts, or match the number of hosts")
assert.Nil(clientConfigs)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.15
require (
github.com/heetch/confita v0.10.0
github.com/prometheus/client_golang v1.11.0
github.com/stretchr/testify v1.7.0
github.com/xonvanetta/shutdown v0.0.3
golang.org/x/net v0.0.0-20200625001655-4c5254603344
)
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
Expand Down Expand Up @@ -195,12 +197,15 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
Expand Down Expand Up @@ -292,6 +297,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
Expand Down
6 changes: 5 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"fmt"
"log"

"github.com/eko/pihole-exporter/config"
"github.com/eko/pihole-exporter/internal/metrics"
Expand All @@ -11,7 +12,10 @@ import (
)

func main() {
envConf, clientConfigs := config.Load()
envConf, clientConfigs, err := config.Load()
if err != nil {
log.Fatal(err.Error())
}

metrics.Init()

Expand Down