Created
January 26, 2023 16:39
-
-
Save mfojtik/8fa9a571c3c5835d7f9f6288d09b390e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dnsprobe | |
import ( | |
"context" | |
"errors" | |
"fmt" | |
"net" | |
"reflect" | |
"sort" | |
"sync" | |
"time" | |
) | |
type Controller struct { | |
service string | |
lastDurations []time.Duration | |
lastEntries []string | |
lastError error | |
lastErrorTimestamp time.Time | |
lastSuccess time.Time | |
resolveTimeout time.Duration | |
probeInterval time.Duration | |
resolver net.Resolver | |
} | |
func (c *Controller) startProbe(ctx context.Context) { | |
var wg sync.WaitGroup | |
for { | |
wg.Add(1) | |
go func(ctx context.Context) { | |
defer wg.Done() | |
now := time.Now() | |
var finishedDuration time.Duration | |
var lastEntries []string | |
done := make(chan error) | |
go func() { | |
defer func() { | |
finishedDuration = -time.Until(now) | |
}() | |
entries, err := c.resolver.LookupHost(ctx, c.service) | |
if err != nil { | |
done <- err | |
} | |
sort.Strings(entries) | |
lastEntries = entries | |
close(done) | |
}() | |
select { | |
case <-ctx.Done(): | |
return | |
case err := <-done: | |
if err != nil { | |
fmt.Printf("ERROR: DNS resolving failed for %q: %v\n", c.service, err) | |
c.lastError = err | |
c.lastErrorTimestamp = time.Now() | |
return | |
} | |
case <-time.After(c.resolveTimeout): | |
fmt.Printf("ERROR: DNS resolving timed out for %q after %s\n", c.service, c.resolveTimeout) | |
c.lastError = errors.New("resolving timeout") | |
} | |
c.lastDurations = append(c.lastDurations, finishedDuration) | |
if len(c.lastDurations) > 60 { | |
c.lastDurations = append(c.lastDurations[:0], c.lastDurations[1:]...) | |
} | |
if !reflect.DeepEqual(c.lastEntries, lastEntries) && len(c.lastEntries) > 0 { | |
fmt.Printf("WARNING: DNS change detected for %q: was %#v now it is %#v\n", c.service, c.lastEntries, lastEntries) | |
} | |
c.lastSuccess = time.Now() | |
c.lastEntries = lastEntries | |
}(ctx) | |
select { | |
case <-ctx.Done(): | |
return | |
default: | |
wg.Wait() | |
time.Sleep(c.probeInterval) | |
} | |
} | |
} | |
func New(serviceName string, probeInterval, resolveTimeout time.Duration) *Controller { | |
resolver := net.DefaultResolver | |
resolver.StrictErrors = true | |
resolver.PreferGo = true | |
return &Controller{ | |
resolver: *resolver, | |
service: serviceName, | |
probeInterval: probeInterval, | |
resolveTimeout: resolveTimeout, | |
} | |
} | |
func (c *Controller) Run(ctx context.Context) { | |
go c.startProbe(ctx) | |
<-ctx.Done() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment