fix(configuration): address parsing failure (#3653)
This fixes an issue with parsing address types from strings.pull/3663/head
parent
664d65d7fb
commit
290a38e424
|
@ -114,7 +114,7 @@ telemetry:
|
|||
enabled: false
|
||||
|
||||
## The address to listen on for metrics. This should be on a different port to the main server.port value.
|
||||
address: '0.0.0.0:9959'
|
||||
address: tcp://0.0.0.0:9959
|
||||
|
||||
##
|
||||
## TOTP Configuration
|
||||
|
|
|
@ -57,6 +57,32 @@ While you can use multiple of these blocks in combination, ee suggest keeping it
|
|||
| 1 day | `1d` or `24h` or `86400` or `86400s` |
|
||||
| 10 hours | `10h` or `600m` or `9h60m` or `36000` |
|
||||
|
||||
## Address
|
||||
|
||||
The address type is a string that takes the following format:
|
||||
|
||||
```text
|
||||
[<scheme>://]<ip>[:<port>]
|
||||
```
|
||||
|
||||
The square brackets indicate optional sections, and the angled brackets indicate required sections. The following
|
||||
sections elaborate on this. Sections may only be optional for the purposes of parsing, there may be a configuration
|
||||
requirement that one of these is provided.
|
||||
|
||||
### scheme
|
||||
|
||||
The entire scheme is optional, but if the scheme host delimiter `://` is in the string, the scheme must be present. The
|
||||
scheme must be one of `tcp://`, or `udp://`. The default scheme is `tcp://`.
|
||||
|
||||
### ip
|
||||
|
||||
The IP is required. If specifying an IPv6 it should be wrapped in square brackets. For example for the IPv6 address
|
||||
`::1` with the `tcp://` scheme and port `80`: `tcp://[::1]:80`.
|
||||
|
||||
### port
|
||||
|
||||
The entire port is optional, but if the host port delimiter `:` exists it must also include a numeric port.
|
||||
|
||||
## Regular Expressions
|
||||
|
||||
We have several sections of configuration that utilize regular expressions. It's recommended to validate your regex
|
||||
|
|
|
@ -20,7 +20,7 @@ toc: true
|
|||
telemetry:
|
||||
metrics:
|
||||
enabled: false
|
||||
address: "0.0.0.0:9959"
|
||||
address: "tcp://0.0.0.0:9959"
|
||||
```
|
||||
|
||||
## Options
|
||||
|
@ -33,10 +33,10 @@ Determines if the [Prometheus] HTTP Metrics Exporter is enabled.
|
|||
|
||||
### address
|
||||
|
||||
{{< confkey type="address" default="0.0.0.0:9959" required="no" >}}
|
||||
{{< confkey type="address" default="tcp://0.0.0.0:9959" required="no" >}}
|
||||
|
||||
Configures the listener address for the [Prometheus] HTTP Metrics Exporter. The address must be a IPv4 or IPv6 address
|
||||
followed by the port in the `<address>:<port>` format.
|
||||
Configures the listener address for the [Prometheus] HTTP Metrics Exporter. This configuration key uses the
|
||||
[Address](../prologue/common.md#address) format. The scheme must be `tcp://` or empty.
|
||||
|
||||
## See More
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ telemetry:
|
|||
enabled: false
|
||||
|
||||
## The address to listen on for metrics. This should be on a different port to the main server.port value.
|
||||
address: '0.0.0.0:9959'
|
||||
address: tcp://0.0.0.0:9959
|
||||
|
||||
##
|
||||
## TOTP Configuration
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration"
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
)
|
||||
|
||||
func TestStringToMailAddressHookFunc(t *testing.T) {
|
||||
|
@ -748,6 +749,120 @@ func TestStringToRegexpFuncPointers(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestStringToAddressHookFunc(t *testing.T) {
|
||||
mustParseAddress := func(a string) (addr schema.Address) {
|
||||
addrs, err := schema.NewAddressFromString(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return *addrs
|
||||
}
|
||||
|
||||
mustParseAddressPtr := func(a string) (addr *schema.Address) {
|
||||
addr, err := schema.NewAddressFromString(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
have interface{}
|
||||
expected interface{}
|
||||
err string
|
||||
decode bool
|
||||
wantGrps []string
|
||||
}{
|
||||
{
|
||||
name: "ShouldDecodeNonPtr",
|
||||
have: "tcp://0.0.0.0:2020",
|
||||
expected: mustParseAddress("tcp://0.0.0.0:2020"),
|
||||
decode: true,
|
||||
},
|
||||
{
|
||||
name: "ShouldDecodePtr",
|
||||
have: "tcp://0.0.0.0:2020",
|
||||
expected: mustParseAddressPtr("tcp://0.0.0.0:2020"),
|
||||
decode: true,
|
||||
},
|
||||
{
|
||||
name: "ShouldNotDecodeIntegerToCorrectType",
|
||||
have: 1,
|
||||
expected: schema.Address{},
|
||||
decode: false,
|
||||
},
|
||||
{
|
||||
name: "ShouldNotDecodeIntegerToCorrectTypePtr",
|
||||
have: 1,
|
||||
expected: &schema.Address{},
|
||||
decode: false,
|
||||
},
|
||||
{
|
||||
name: "ShouldNotDecodeIntegerPtrToCorrectType",
|
||||
have: testInt32Ptr(1),
|
||||
expected: schema.Address{},
|
||||
decode: false,
|
||||
},
|
||||
{
|
||||
name: "ShouldNotDecodeIntegerPtrToCorrectTypePtr",
|
||||
have: testInt32Ptr(1),
|
||||
expected: &schema.Address{},
|
||||
decode: false,
|
||||
},
|
||||
{
|
||||
name: "ShouldNotDecodeToString",
|
||||
have: "tcp://0.0.0.0:2020",
|
||||
expected: "",
|
||||
decode: false,
|
||||
},
|
||||
{
|
||||
name: "ShouldNotDecodeToIntPtr",
|
||||
have: "tcp://0.0.0.0:2020",
|
||||
expected: testInt32Ptr(1),
|
||||
decode: false,
|
||||
},
|
||||
{
|
||||
name: "ShouldNotDecodeToIntPtr",
|
||||
have: "tcp://0.0.0.0:2020",
|
||||
expected: testInt32Ptr(1),
|
||||
decode: false,
|
||||
},
|
||||
{
|
||||
name: "ShouldFailDecode",
|
||||
have: "tcp://&!@^#*&!@#&*@!:2020",
|
||||
expected: schema.Address{},
|
||||
err: "could not decode 'tcp://&!@^#*&!@#&*@!:2020' to a Address: could not parse string 'tcp://&!@^#*&!@#&*@!:2020' as address: expected format is [<scheme>://]<ip>[:<port>]: parse \"tcp://&!@^\": invalid character \"^\" in host name",
|
||||
decode: false,
|
||||
},
|
||||
}
|
||||
|
||||
hook := configuration.StringToAddressHookFunc()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actual, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.expected), tc.have)
|
||||
if tc.err != "" {
|
||||
assert.EqualError(t, err, tc.err)
|
||||
|
||||
if !tc.decode {
|
||||
assert.Nil(t, actual)
|
||||
}
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
|
||||
if tc.decode {
|
||||
assert.Equal(t, tc.expected, actual)
|
||||
} else {
|
||||
assert.Equal(t, tc.have, actual)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testInt32Ptr(i int32) *int32 {
|
||||
return &i
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package schema
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -52,3 +53,7 @@ const (
|
|||
// TOTPSecretSizeMinimum is the minimum secret size.
|
||||
TOTPSecretSizeMinimum = 20
|
||||
)
|
||||
|
||||
// regexpHasScheme checks if a string has a scheme. Valid characters for schemes include alphanumeric, hyphen,
|
||||
// period, and plus characters.
|
||||
var regexpHasScheme = regexp.MustCompile(`^[-+.a-zA-Z\d]+://`)
|
||||
|
|
|
@ -11,13 +11,13 @@ type TelemetryConfig struct {
|
|||
|
||||
// TelemetryMetricsConfig represents the telemetry metrics config.
|
||||
type TelemetryMetricsConfig struct {
|
||||
Enabled bool `koanf:"enabled"`
|
||||
Address Address `koanf:"address"`
|
||||
Enabled bool `koanf:"enabled"`
|
||||
Address *Address `koanf:"address"`
|
||||
}
|
||||
|
||||
// DefaultTelemetryConfig is the default telemetry configuration.
|
||||
var DefaultTelemetryConfig = TelemetryConfig{
|
||||
Metrics: TelemetryMetricsConfig{
|
||||
Address: NewAddress("tcp", net.ParseIP("0.0.0.0"), 9959),
|
||||
Address: &Address{true, "tcp", net.ParseIP("0.0.0.0"), 9959},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -3,74 +3,64 @@ package schema
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var regexpAddress = regexp.MustCompile(`^((?P<Scheme>\w+)://)?((?P<IPv4>((((25[0-5]|2[0-4]\d|[01]?\d\d?)(\.)){3})(25[0-5]|2[0-4]\d|[01]?\d\d?)))|(\[(?P<IPv6>([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d)|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d))\]):)?(?P<Port>\d+)$`)
|
||||
|
||||
const tcp = "tcp"
|
||||
|
||||
// NewAddress produces a valid address from input.
|
||||
func NewAddress(scheme string, ip net.IP, port int) Address {
|
||||
return Address{
|
||||
valid: true,
|
||||
Scheme: scheme,
|
||||
IP: ip,
|
||||
Port: port,
|
||||
// NewAddressFromString returns an *Address and error depending on the ability to parse the string as an Address.
|
||||
func NewAddressFromString(a string) (addr *Address, err error) {
|
||||
if len(a) == 0 {
|
||||
return &Address{true, "tcp", net.ParseIP("0.0.0.0"), 0}, nil
|
||||
}
|
||||
|
||||
var u *url.URL
|
||||
|
||||
if regexpHasScheme.MatchString(a) {
|
||||
u, err = url.Parse(a)
|
||||
} else {
|
||||
u, err = url.Parse("tcp://" + a)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse string '%s' as address: expected format is [<scheme>://]<ip>[:<port>]: %w", a, err)
|
||||
}
|
||||
|
||||
return NewAddressFromURL(u)
|
||||
}
|
||||
|
||||
// NewAddressFromString parses a string and returns an *Address or error.
|
||||
func NewAddressFromString(addr string) (address *Address, err error) {
|
||||
if addr == "" {
|
||||
return &Address{}, nil
|
||||
// NewAddressFromURL returns an *Address and error depending on the ability to parse the *url.URL as an Address.
|
||||
func NewAddressFromURL(u *url.URL) (addr *Address, err error) {
|
||||
addr = &Address{
|
||||
Scheme: strings.ToLower(u.Scheme),
|
||||
IP: net.ParseIP(u.Hostname()),
|
||||
}
|
||||
|
||||
if !regexpAddress.MatchString(addr) {
|
||||
return nil, fmt.Errorf("the string '%s' does not appear to be a valid address", addr)
|
||||
if addr.IP == nil {
|
||||
return nil, fmt.Errorf("could not parse ip for address '%s': %s does not appear to be an IP", u.String(), u.Hostname())
|
||||
}
|
||||
|
||||
address = &Address{
|
||||
valid: true,
|
||||
}
|
||||
|
||||
submatches := regexpAddress.FindStringSubmatch(addr)
|
||||
|
||||
var ip, port string
|
||||
|
||||
for i, name := range regexpAddress.SubexpNames() {
|
||||
switch name {
|
||||
case "Scheme":
|
||||
address.Scheme = submatches[i]
|
||||
case "IPv4":
|
||||
ip = submatches[i]
|
||||
|
||||
if address.Scheme == "" || address.Scheme == tcp {
|
||||
address.Scheme = "tcp4"
|
||||
}
|
||||
case "IPv6":
|
||||
ip = submatches[i]
|
||||
|
||||
if address.Scheme == "" || address.Scheme == tcp {
|
||||
address.Scheme = "tcp6"
|
||||
}
|
||||
case "Port":
|
||||
port = submatches[i]
|
||||
port := u.Port()
|
||||
switch port {
|
||||
case "":
|
||||
break
|
||||
default:
|
||||
addr.Port, err = strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse port for address '%s': %w", u.String(), err)
|
||||
}
|
||||
}
|
||||
|
||||
if address.IP = net.ParseIP(ip); address.IP == nil {
|
||||
return nil, fmt.Errorf("failed to parse '%s' as an IP address", ip)
|
||||
switch addr.Scheme {
|
||||
case "tcp", "udp", "http", "https":
|
||||
break
|
||||
default:
|
||||
return nil, fmt.Errorf("could not parse scheme for address '%s': scheme '%s' is not valid, expected to be one of 'tcp://', 'udp://'", u.String(), addr.Scheme)
|
||||
}
|
||||
|
||||
address.Port, _ = strconv.Atoi(port)
|
||||
addr.valid = true
|
||||
|
||||
if address.Port <= 0 || address.Port > 65535 {
|
||||
return nil, fmt.Errorf("failed to parse address port '%d' is invalid: ports must be between 1 and 65535", address.Port)
|
||||
}
|
||||
|
||||
return address, nil
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// Address represents an address.
|
||||
|
@ -78,8 +68,8 @@ type Address struct {
|
|||
valid bool
|
||||
|
||||
Scheme string
|
||||
net.IP
|
||||
Port int
|
||||
IP net.IP
|
||||
Port int
|
||||
}
|
||||
|
||||
// Valid returns true if the Address is valid.
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package schema
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewAddressFromString(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
have string
|
||||
expected *Address
|
||||
expectedHostPort, expectedString, expectedErr string
|
||||
}{
|
||||
{"ShouldParseBasicAddress", "tcp://0.0.0.0:9091", &Address{true, "tcp", net.ParseIP("0.0.0.0"), 9091}, "0.0.0.0:9091", "tcp://0.0.0.0:9091", ""},
|
||||
{"ShouldParseEmptyAddress", "", &Address{true, "tcp", net.ParseIP("0.0.0.0"), 0}, "0.0.0.0:0", "tcp://0.0.0.0:0", ""},
|
||||
{"ShouldParseAddressMissingScheme", "0.0.0.0:9091", &Address{true, "tcp", net.ParseIP("0.0.0.0"), 9091}, "0.0.0.0:9091", "tcp://0.0.0.0:9091", ""},
|
||||
{"ShouldParseAddressMissingPort", "tcp://0.0.0.0", &Address{true, "tcp", net.ParseIP("0.0.0.0"), 0}, "0.0.0.0:0", "tcp://0.0.0.0:0", ""},
|
||||
{"ShouldNotParseUnknownScheme", "a://0.0.0.0", nil, "", "", "could not parse scheme for address 'a://0.0.0.0': scheme 'a' is not valid, expected to be one of 'tcp://', 'udp://'"},
|
||||
{"ShouldNotParseInvalidPort", "tcp://0.0.0.0:abc", nil, "", "", "could not parse string 'tcp://0.0.0.0:abc' as address: expected format is [<scheme>://]<ip>[:<port>]: parse \"tcp://0.0.0.0:abc\": invalid port \":abc\" after host"},
|
||||
{"ShouldNotParseInvalidIP", "tcp://example.com:9091", nil, "", "", "could not parse ip for address 'tcp://example.com:9091': example.com does not appear to be an IP"},
|
||||
{"ShouldNotParseInvalidAddress", "@$@#%@#$@@", nil, "", "", "could not parse string '@$@#%@#$@@' as address: expected format is [<scheme>://]<ip>[:<port>]: parse \"tcp://@$@#%@#$@@\": invalid URL escape \"%@#\""},
|
||||
{"ShouldNotParseInvalidAddressWithScheme", "tcp://@$@#%@#$@@", nil, "", "", "could not parse string 'tcp://@$@#%@#$@@' as address: expected format is [<scheme>://]<ip>[:<port>]: parse \"tcp://@$@#%@#$@@\": invalid URL escape \"%@#\""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actual, actualErr := NewAddressFromString(tc.have)
|
||||
|
||||
if len(tc.expectedErr) != 0 {
|
||||
assert.EqualError(t, actualErr, tc.expectedErr)
|
||||
} else {
|
||||
assert.Nil(t, actualErr)
|
||||
|
||||
assert.Equal(t, actual.HostPort(), tc.expectedHostPort)
|
||||
assert.Equal(t, actual.String(), tc.expectedString)
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.expected, actual)
|
||||
|
||||
if actual != nil {
|
||||
assert.True(t, actual.Valid())
|
||||
assert.NotEmpty(t, actual.String())
|
||||
assert.NotEmpty(t, actual.HostPort())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -123,6 +123,11 @@ const (
|
|||
errFmtStoragePostgreSQLInvalidSSLMode = "storage: postgres: ssl: option 'mode' must be one of '%s' but it is configured as '%s'"
|
||||
)
|
||||
|
||||
// Telemetry Error constants.
|
||||
const (
|
||||
errFmtTelemetryMetricsScheme = "telemetry: metrics: option 'address' must have a scheme 'tcp://' but it is configured as '%s'"
|
||||
)
|
||||
|
||||
// OpenID Error constants.
|
||||
const (
|
||||
errFmtOIDCNoClientsConfigured = "identity_providers: oidc: option 'clients' must have one or " +
|
||||
|
|
|
@ -1,14 +1,25 @@
|
|||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
)
|
||||
|
||||
// ValidateTelemetry validates the telemetry configuration.
|
||||
func ValidateTelemetry(config *schema.Configuration, validator *schema.StructValidator) {
|
||||
if config.Telemetry.Metrics.Enabled {
|
||||
if config.Telemetry.Metrics.Address.String() == "" {
|
||||
config.Telemetry.Metrics.Address = schema.DefaultTelemetryConfig.Metrics.Address
|
||||
}
|
||||
if config.Telemetry.Metrics.Address == nil {
|
||||
config.Telemetry.Metrics.Address = schema.DefaultTelemetryConfig.Metrics.Address
|
||||
}
|
||||
|
||||
switch config.Telemetry.Metrics.Address.Scheme {
|
||||
case "tcp":
|
||||
break
|
||||
default:
|
||||
validator.Push(fmt.Errorf(errFmtTelemetryMetricsScheme, config.Telemetry.Metrics.Address.Scheme))
|
||||
}
|
||||
|
||||
if config.Telemetry.Metrics.Address.Port == 0 {
|
||||
config.Telemetry.Metrics.Address.Port = schema.DefaultTelemetryConfig.Metrics.Address.Port
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package validator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
)
|
||||
|
||||
func TestValidateTelemetry(t *testing.T) {
|
||||
mustParseAddress := func(a string) *schema.Address {
|
||||
addr, err := schema.NewAddressFromString(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
have *schema.Configuration
|
||||
expected *schema.Configuration
|
||||
expectedWrns, expectedErrs []string
|
||||
}{
|
||||
{
|
||||
"ShouldSetDefaults",
|
||||
&schema.Configuration{},
|
||||
&schema.Configuration{Telemetry: schema.DefaultTelemetryConfig},
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"ShouldSetDefaultPort",
|
||||
&schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://0.0.0.0")}}},
|
||||
&schema.Configuration{Telemetry: schema.DefaultTelemetryConfig},
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"ShouldSetDefaultPortAlt",
|
||||
&schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://0.0.0.0:0")}}},
|
||||
&schema.Configuration{Telemetry: schema.DefaultTelemetryConfig},
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"ShouldSetDefaultPortWithCustomIP",
|
||||
&schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://127.0.0.1")}}},
|
||||
&schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://127.0.0.1:9959")}}},
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"ShouldNotValidateUDP",
|
||||
&schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("udp://0.0.0.0")}}},
|
||||
&schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("udp://0.0.0.0:9959")}}},
|
||||
nil,
|
||||
[]string{"telemetry: metrics: option 'address' must have a scheme 'tcp://' but it is configured as 'udp'"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
v := schema.NewStructValidator()
|
||||
|
||||
ValidateTelemetry(tc.have, v)
|
||||
|
||||
assert.Equal(t, tc.expected.Telemetry.Metrics.Enabled, tc.have.Telemetry.Metrics.Enabled)
|
||||
assert.Equal(t, tc.expected.Telemetry.Metrics.Address, tc.have.Telemetry.Metrics.Address)
|
||||
|
||||
lenWrns := len(tc.expectedWrns)
|
||||
wrns := v.Warnings()
|
||||
|
||||
if lenWrns == 0 {
|
||||
assert.Len(t, wrns, 0)
|
||||
} else {
|
||||
require.Len(t, wrns, lenWrns)
|
||||
|
||||
for i, expectedWrn := range tc.expectedWrns {
|
||||
assert.EqualError(t, wrns[i], expectedWrn)
|
||||
}
|
||||
}
|
||||
|
||||
lenErrs := len(tc.expectedErrs)
|
||||
errs := v.Errors()
|
||||
|
||||
if lenErrs == 0 {
|
||||
assert.Len(t, errs, 0)
|
||||
} else {
|
||||
require.Len(t, errs, lenErrs)
|
||||
|
||||
for i, expectedErr := range tc.expectedErrs {
|
||||
assert.EqualError(t, errs[i], expectedErr)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ server:
|
|||
telemetry:
|
||||
metrics:
|
||||
enabled: true
|
||||
address: tcp://0.0.0.0:9959
|
||||
|
||||
log:
|
||||
level: debug
|
||||
|
|
Loading…
Reference in New Issue