mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 18:20:27 +00:00
85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
package endpoint
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/bluele/gcache"
|
|
)
|
|
|
|
const (
|
|
rAddrCacheLen = 500 // Default cache length
|
|
rAddrBacklog = 1000
|
|
rAddrCacheExpiration = 30 * time.Minute
|
|
)
|
|
|
|
var errNotFound = fmt.Errorf("Not found")
|
|
|
|
type revResFunc func(addr string) (names []string, err error)
|
|
|
|
// ReverseResolver is a caching, reverse resolver.
|
|
type ReverseResolver struct {
|
|
addresses chan string
|
|
cache gcache.Cache
|
|
Throttle <-chan time.Time // Made public for mocking
|
|
Resolver revResFunc
|
|
}
|
|
|
|
// NewReverseResolver starts a new reverse resolver that performs reverse
|
|
// resolutions and caches the result.
|
|
func NewReverseResolver() *ReverseResolver {
|
|
r := ReverseResolver{
|
|
addresses: make(chan string, rAddrBacklog),
|
|
cache: gcache.New(rAddrCacheLen).LRU().Expiration(rAddrCacheExpiration).Build(),
|
|
Throttle: time.Tick(time.Second / 10),
|
|
Resolver: net.LookupAddr,
|
|
}
|
|
go r.loop()
|
|
return &r
|
|
}
|
|
|
|
// Get the reverse resolution for an IP address if already in the cache, a
|
|
// gcache.NotFoundKeyError error otherwise. Note: it returns one of the
|
|
// possible names that can be obtained for that IP.
|
|
func (r *ReverseResolver) Get(address string) (string, error) {
|
|
val, err := r.cache.Get(address)
|
|
if hostname, ok := val.(string); err == nil && ok {
|
|
return hostname, nil
|
|
}
|
|
if _, ok := val.(struct{}); err == nil && ok {
|
|
return "", errNotFound
|
|
}
|
|
if err == gcache.NotFoundKeyError {
|
|
// We trigger a asynchronous reverse resolution when not cached
|
|
select {
|
|
case r.addresses <- address:
|
|
default:
|
|
}
|
|
}
|
|
return "", errNotFound
|
|
}
|
|
|
|
func (r *ReverseResolver) loop() {
|
|
for request := range r.addresses {
|
|
// check if the answer is already in the cache
|
|
if _, err := r.cache.Get(request); err == nil {
|
|
continue
|
|
}
|
|
<-r.Throttle // rate limit our DNS resolutions
|
|
names, err := r.Resolver(request)
|
|
if err == nil && len(names) > 0 {
|
|
name := strings.TrimRight(names[0], ".")
|
|
r.cache.Set(request, name)
|
|
} else {
|
|
r.cache.Set(request, struct{}{})
|
|
}
|
|
}
|
|
}
|
|
|
|
// Stop the async reverse resolver.
|
|
func (r *ReverseResolver) Stop() {
|
|
close(r.addresses)
|
|
}
|