chore(updater): create resolver in provider updater

- Pass min servers to resolve call
- Set settings when constructing resolver
- Construct resolver in each provider updater
- No more common resolver for all providers
This commit is contained in:
Quentin McGaw
2022-06-09 02:54:39 +00:00
parent e37f557cd5
commit 415cb7a945
53 changed files with 155 additions and 483 deletions

View File

@@ -10,7 +10,6 @@ import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
resolver "github.com/qdm12/gluetun/internal/updater/resolver"
)
// MockParallel is a mock of Parallel interface.
@@ -37,7 +36,7 @@ func (m *MockParallel) EXPECT() *MockParallelMockRecorder {
}
// Resolve mocks base method.
func (m *MockParallel) Resolve(arg0 context.Context, arg1 []string, arg2 resolver.ParallelSettings) (map[string][]net.IP, []string, error) {
func (m *MockParallel) Resolve(arg0 context.Context, arg1 []string, arg2 int) (map[string][]net.IP, []string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Resolve", arg0, arg1, arg2)
ret0, _ := ret[0].(map[string][]net.IP)

View File

@@ -10,17 +10,19 @@ import (
//go:generate mockgen -destination=mock_$GOPACKAGE/$GOFILE . Parallel
type Parallel interface {
Resolve(ctx context.Context, hosts []string, settings ParallelSettings) (
Resolve(ctx context.Context, hosts []string, minToFind int) (
hostToIPs map[string][]net.IP, warnings []string, err error)
}
type parallel struct {
repeatResolver Repeat
settings ParallelSettings
}
func NewParallelResolver(address string) Parallel {
func NewParallelResolver(settings ParallelSettings) Parallel {
return &parallel{
repeatResolver: NewRepeat(address),
repeatResolver: NewRepeat(settings.Repeat),
settings: settings,
}
}
@@ -32,10 +34,6 @@ type ParallelSettings struct {
// This value is between 0 and 1. Note this is only
// applicable if FailEarly is not set to true.
MaxFailRatio float64
// MinFound is the minimum number of hosts to be found.
// If it is bigger than the number of hosts given, it
// is set to the number of hosts given.
MinFound int
}
type parallelResult struct {
@@ -48,13 +46,8 @@ var (
ErrMaxFailRatio = errors.New("maximum failure ratio reached")
)
func (pr *parallel) Resolve(ctx context.Context, hosts []string,
settings ParallelSettings) (hostToIPs map[string][]net.IP, warnings []string, err error) {
minFound := settings.MinFound
if minFound > len(hosts) {
minFound = len(hosts)
}
func (pr *parallel) Resolve(ctx context.Context, hosts []string, minToFind int) (
hostToIPs map[string][]net.IP, warnings []string, err error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
@@ -64,16 +57,16 @@ func (pr *parallel) Resolve(ctx context.Context, hosts []string,
defer close(errors)
for _, host := range hosts {
go pr.resolveAsync(ctx, host, settings.Repeat, results, errors)
go pr.resolveAsync(ctx, host, results, errors)
}
hostToIPs = make(map[string][]net.IP, len(hosts))
maxFails := int(settings.MaxFailRatio * float64(len(hosts)))
maxFails := int(pr.settings.MaxFailRatio * float64(len(hosts)))
for range hosts {
select {
case newErr := <-errors:
if settings.FailEarly {
if pr.settings.FailEarly {
if err == nil {
// only set the error to the first error encountered
// and not the context canceled errors coming after.
@@ -100,14 +93,14 @@ func (pr *parallel) Resolve(ctx context.Context, hosts []string,
return nil, warnings, err
}
if len(hostToIPs) < minFound {
if len(hostToIPs) < minToFind {
return nil, warnings,
fmt.Errorf("%w: found %d hosts but expected at least %d",
ErrMinFound, len(hostToIPs), minFound)
ErrMinFound, len(hostToIPs), minToFind)
}
failureRatio := float64(len(warnings)) / float64(len(hosts))
if failureRatio > settings.MaxFailRatio {
if failureRatio > pr.settings.MaxFailRatio {
return hostToIPs, warnings,
fmt.Errorf("%w: %.2f failure ratio reached", ErrMaxFailRatio, failureRatio)
}
@@ -116,8 +109,8 @@ func (pr *parallel) Resolve(ctx context.Context, hosts []string,
}
func (pr *parallel) resolveAsync(ctx context.Context, host string,
settings RepeatSettings, results chan<- parallelResult, errors chan<- error) {
IPs, err := pr.repeatResolver.Resolve(ctx, host, settings)
results chan<- parallelResult, errors chan<- error) {
IPs, err := pr.repeatResolver.Resolve(ctx, host)
if err != nil {
errors <- err
return

View File

@@ -11,20 +11,23 @@ import (
)
type Repeat interface {
Resolve(ctx context.Context, host string, settings RepeatSettings) (IPs []net.IP, err error)
Resolve(ctx context.Context, host string) (IPs []net.IP, err error)
}
type repeat struct {
resolver *net.Resolver
settings RepeatSettings
}
func NewRepeat(address string) Repeat {
func NewRepeat(settings RepeatSettings) Repeat {
return &repeat{
resolver: newResolver(address),
resolver: newResolver(settings.Address),
settings: settings,
}
}
type RepeatSettings struct {
Address string
MaxDuration time.Duration
BetweenDuration time.Duration
MaxNoNew int
@@ -33,8 +36,8 @@ type RepeatSettings struct {
SortIPs bool
}
func (r *repeat) Resolve(ctx context.Context, host string, settings RepeatSettings) (ips []net.IP, err error) {
timedCtx, cancel := context.WithTimeout(ctx, settings.MaxDuration)
func (r *repeat) Resolve(ctx context.Context, host string) (ips []net.IP, err error) {
timedCtx, cancel := context.WithTimeout(ctx, r.settings.MaxDuration)
defer cancel()
noNewCounter := 0
@@ -45,7 +48,7 @@ func (r *repeat) Resolve(ctx context.Context, host string, settings RepeatSettin
// TODO
// - one resolving every 100ms for round robin DNS responses
// - one every second for time based DNS cycling responses
noNewCounter, failCounter, err = r.resolveOnce(ctx, timedCtx, host, settings, uniqueIPs, noNewCounter, failCounter)
noNewCounter, failCounter, err = r.resolveOnce(ctx, timedCtx, host, r.settings, uniqueIPs, noNewCounter, failCounter)
}
if len(uniqueIPs) == 0 {
@@ -54,7 +57,7 @@ func (r *repeat) Resolve(ctx context.Context, host string, settings RepeatSettin
ips = uniqueIPsToSlice(uniqueIPs)
if settings.SortIPs {
if r.settings.SortIPs {
sort.Slice(ips, func(i, j int) bool {
return bytes.Compare(ips[i], ips[j]) < 1
})