mirror of
https://github.com/weaveworks/scope.git
synced 2026-05-06 01:08:03 +00:00
Move DNS name mapping from endpoint to report
This commit is contained in:
@@ -219,23 +219,33 @@ func (t *connectionTracker) addConnection(rpt *report.Report, incoming bool, ft
|
||||
)
|
||||
rpt.Endpoint.AddNode(fromNode.WithAdjacent(toNode.ID))
|
||||
rpt.Endpoint.AddNode(toNode)
|
||||
t.addDNS(rpt, ft.fromAddr)
|
||||
t.addDNS(rpt, ft.toAddr)
|
||||
}
|
||||
|
||||
func (t *connectionTracker) makeEndpointNode(namespaceID string, addr string, port uint16, extra map[string]string) report.Node {
|
||||
portStr := strconv.Itoa(int(port))
|
||||
node := report.MakeNodeWith(report.MakeEndpointNodeID(t.conf.HostID, namespaceID, addr, portStr), nil)
|
||||
if names := t.conf.DNSSnooper.CachedNamesForIP(addr); len(names) > 0 {
|
||||
node = node.WithSet(SnoopedDNSNames, report.MakeStringSet(names...))
|
||||
}
|
||||
if names, err := t.reverseResolver.get(addr); err == nil && len(names) > 0 {
|
||||
node = node.WithSet(ReverseDNSNames, report.MakeStringSet(names...))
|
||||
}
|
||||
if extra != nil {
|
||||
node = node.WithLatests(extra)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// Add DNS record for address to report, if not already there
|
||||
func (t *connectionTracker) addDNS(rpt *report.Report, addr string) {
|
||||
if _, found := rpt.DNS[addr]; !found {
|
||||
forward := t.conf.DNSSnooper.CachedNamesForIP(addr)
|
||||
record := report.DNSRecord{
|
||||
Forward: report.MakeStringSet(forward...),
|
||||
}
|
||||
if names, err := t.reverseResolver.get(addr); err == nil && len(names) > 0 {
|
||||
record.Reverse = report.MakeStringSet(names...)
|
||||
}
|
||||
rpt.DNS[addr] = record
|
||||
}
|
||||
}
|
||||
|
||||
func (t *connectionTracker) Stop() error {
|
||||
if t.ebpfTracker != nil {
|
||||
t.ebpfTracker.stop()
|
||||
|
||||
@@ -73,7 +73,7 @@ func newConnectionCounters() *connectionCounters {
|
||||
return &connectionCounters{counted: map[string]struct{}{}, counts: map[connection]int{}}
|
||||
}
|
||||
|
||||
func (c *connectionCounters) add(outgoing bool, localNode, remoteNode, localEndpoint, remoteEndpoint report.Node) {
|
||||
func (c *connectionCounters) add(dns report.DNSRecords, outgoing bool, localNode, remoteNode, localEndpoint, remoteEndpoint report.Node) {
|
||||
// We identify connections by their source endpoint, pre-NAT, to
|
||||
// ensure we only count them once.
|
||||
srcEndpoint, dstEndpoint := remoteEndpoint, localEndpoint
|
||||
@@ -94,10 +94,10 @@ func (c *connectionCounters) add(outgoing bool, localNode, remoteNode, localEndp
|
||||
return
|
||||
}
|
||||
// For internet nodes we break out individual addresses
|
||||
if conn.remoteAddr, ok = internetAddr(remoteNode, remoteEndpoint); !ok {
|
||||
if conn.remoteAddr, ok = internetAddr(dns, remoteNode, remoteEndpoint); !ok {
|
||||
return
|
||||
}
|
||||
if conn.localAddr, ok = internetAddr(localNode, localEndpoint); !ok {
|
||||
if conn.localAddr, ok = internetAddr(dns, localNode, localEndpoint); !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ func (c *connectionCounters) add(outgoing bool, localNode, remoteNode, localEndp
|
||||
c.counts[conn]++
|
||||
}
|
||||
|
||||
func internetAddr(node report.Node, ep report.Node) (string, bool) {
|
||||
func internetAddr(dns report.DNSRecords, node report.Node, ep report.Node) (string, bool) {
|
||||
if !render.IsInternetNode(node) {
|
||||
return "", true
|
||||
}
|
||||
@@ -113,7 +113,7 @@ func internetAddr(node report.Node, ep report.Node) (string, bool) {
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
if name, found := render.DNSFirstMatch(ep, func(string) bool { return true }); found {
|
||||
if name, found := dns.FirstMatch(ep.ID, func(string) bool { return true }); found {
|
||||
// we show the "most important" name only, since we don't have
|
||||
// space for more
|
||||
addr = fmt.Sprintf("%s (%s)", name, addr)
|
||||
@@ -171,7 +171,7 @@ func incomingConnectionsSummary(topologyID string, r report.Report, n report.Nod
|
||||
for _, remoteEndpoint := range endpointChildrenOf(node) {
|
||||
for _, localEndpointID := range remoteEndpoint.Adjacency.Intersection(localEndpointIDs) {
|
||||
localEndpointID = canonicalEndpointID(localEndpointIDCopies, localEndpointID)
|
||||
counts.add(false, n, node, r.Endpoint.Nodes[localEndpointID], remoteEndpoint)
|
||||
counts.add(r.DNS, false, n, node, r.Endpoint.Nodes[localEndpointID], remoteEndpoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,7 +203,7 @@ func outgoingConnectionsSummary(topologyID string, r report.Report, n report.Nod
|
||||
for _, localEndpoint := range localEndpoints {
|
||||
for _, remoteEndpointID := range localEndpoint.Adjacency.Intersection(remoteEndpointIDs) {
|
||||
remoteEndpointID = canonicalEndpointID(remoteEndpointIDCopies, remoteEndpointID)
|
||||
counts.add(true, n, node, localEndpoint, r.Endpoint.Nodes[remoteEndpointID])
|
||||
counts.add(r.DNS, true, n, node, localEndpoint, r.Endpoint.Nodes[remoteEndpointID])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func (e mapEndpoints) Render(rpt report.Report) Nodes {
|
||||
// Nodes without a hostid are mapped to pseudo nodes, if
|
||||
// possible.
|
||||
if _, ok := n.Latest.Lookup(report.HostNodeID); !ok {
|
||||
if id, ok := pseudoNodeID(n, local); ok {
|
||||
if id, ok := pseudoNodeID(rpt, n, local); ok {
|
||||
ret.addChild(n, id, Pseudo)
|
||||
continue
|
||||
}
|
||||
|
||||
31
render/id.go
31
render/id.go
@@ -3,7 +3,6 @@ package render
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/weaveworks/scope/probe/endpoint"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -62,13 +61,13 @@ func NewDerivedPseudoNode(id string, node report.Node) report.Node {
|
||||
return output
|
||||
}
|
||||
|
||||
func pseudoNodeID(n report.Node, local report.Networks) (string, bool) {
|
||||
func pseudoNodeID(rpt report.Report, n report.Node, local report.Networks) (string, bool) {
|
||||
_, addr, _, ok := report.ParseEndpointNodeID(n.ID)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if id, ok := externalNodeID(n, addr, local); ok {
|
||||
if id, ok := externalNodeID(rpt, n, addr, local); ok {
|
||||
return id, ok
|
||||
}
|
||||
|
||||
@@ -78,11 +77,11 @@ func pseudoNodeID(n report.Node, local report.Networks) (string, bool) {
|
||||
}
|
||||
|
||||
// figure out if a node should be considered external and returns an ID which can be used to create a pseudo node
|
||||
func externalNodeID(n report.Node, addr string, local report.Networks) (string, bool) {
|
||||
func externalNodeID(rpt report.Report, n report.Node, addr string, local report.Networks) (string, bool) {
|
||||
// First, check if it's a known service and emit a a specific node if it
|
||||
// is. This needs to be done before checking IPs since known services can
|
||||
// live in the same network, see https://github.com/weaveworks/scope/issues/2163
|
||||
if hostname, found := DNSFirstMatch(n, isKnownService); found {
|
||||
if hostname, found := rpt.DNS.FirstMatch(n.ID, isKnownService); found {
|
||||
return ServiceNodeIDPrefix + hostname, true
|
||||
}
|
||||
|
||||
@@ -101,25 +100,3 @@ func externalNodeID(n report.Node, addr string, local report.Networks) (string,
|
||||
// The node is not external
|
||||
return "", false
|
||||
}
|
||||
|
||||
// DNSFirstMatch returns the first DNS name where match() returns
|
||||
// true, from a prioritized list of snooped and reverse-resolved DNS
|
||||
// names associated with node n.
|
||||
func DNSFirstMatch(n report.Node, match func(name string) bool) (string, bool) {
|
||||
// we rely on Sets being sorted, to make selection for display more
|
||||
// deterministic
|
||||
// prioritize snooped names
|
||||
snoopedNames, _ := n.Sets.Lookup(endpoint.SnoopedDNSNames)
|
||||
for _, hostname := range snoopedNames {
|
||||
if match(hostname) {
|
||||
return hostname, true
|
||||
}
|
||||
}
|
||||
reverseNames, _ := n.Sets.Lookup(endpoint.ReverseDNSNames)
|
||||
for _, hostname := range reverseNames {
|
||||
if match(hostname) {
|
||||
return hostname, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
60
report/dns.go
Normal file
60
report/dns.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package report
|
||||
|
||||
// DNSRecord contains names that an IP address maps to
|
||||
type DNSRecord struct {
|
||||
Forward StringSet `json:"forward,omitempty"`
|
||||
Reverse StringSet `json:"reverse,omitempty"`
|
||||
}
|
||||
|
||||
// DNSRecords contains all address->name mappings for a report
|
||||
type DNSRecords map[string]DNSRecord
|
||||
|
||||
// Copy makes a copy of the DNSRecords
|
||||
func (r DNSRecords) Copy() DNSRecords {
|
||||
cp := make(DNSRecords, len(r))
|
||||
for k, v := range r {
|
||||
cp[k] = v
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
// Merge merges the other object into this one, and returns the result object.
|
||||
// The original is not modified.
|
||||
func (r DNSRecords) Merge(other DNSRecords) DNSRecords {
|
||||
if len(other) > len(r) {
|
||||
r, other = other, r
|
||||
}
|
||||
cp := r.Copy()
|
||||
for k, v := range other {
|
||||
if v2, ok := cp[k]; ok {
|
||||
cp[k] = DNSRecord{
|
||||
Forward: v.Forward.Merge(v2.Forward),
|
||||
Reverse: v.Reverse.Merge(v2.Reverse),
|
||||
}
|
||||
} else {
|
||||
cp[k] = v
|
||||
}
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
// FirstMatch returns the first DNS name where match() returns true
|
||||
func (r DNSRecords) FirstMatch(id string, match func(name string) bool) (string, bool) {
|
||||
_, addr, _, ok := ParseEndpointNodeID(id)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
// we rely on StringSets being sorted, to make selection deterministic
|
||||
// prioritize forward names
|
||||
for _, hostname := range r[addr].Forward {
|
||||
if match(hostname) {
|
||||
return hostname, true
|
||||
}
|
||||
}
|
||||
for _, hostname := range r[addr].Reverse {
|
||||
if match(hostname) {
|
||||
return hostname, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
@@ -151,6 +151,8 @@ type Report struct {
|
||||
// their status endpoints. Edges are present.
|
||||
Overlay Topology
|
||||
|
||||
DNS DNSRecords
|
||||
|
||||
// Sampling data for this report.
|
||||
Sampling Sampling
|
||||
|
||||
@@ -242,6 +244,8 @@ func MakeReport() Report {
|
||||
WithShape(Heptagon).
|
||||
WithLabel("service", "services"),
|
||||
|
||||
DNS: DNSRecords{},
|
||||
|
||||
Sampling: Sampling{},
|
||||
Window: 0,
|
||||
Plugins: xfer.MakePluginSpecs(),
|
||||
@@ -252,6 +256,7 @@ func MakeReport() Report {
|
||||
// Copy returns a value copy of the report.
|
||||
func (r Report) Copy() Report {
|
||||
newReport := Report{
|
||||
DNS: r.DNS.Copy(),
|
||||
Sampling: r.Sampling,
|
||||
Window: r.Window,
|
||||
Plugins: r.Plugins.Copy(),
|
||||
@@ -267,6 +272,7 @@ func (r Report) Copy() Report {
|
||||
// original is not modified.
|
||||
func (r Report) Merge(other Report) Report {
|
||||
newReport := r.Copy()
|
||||
newReport.DNS = newReport.DNS.Merge(other.DNS)
|
||||
newReport.Sampling = newReport.Sampling.Merge(other.Sampling)
|
||||
newReport.Window = newReport.Window + other.Window
|
||||
newReport.Plugins = newReport.Plugins.Merge(other.Plugins)
|
||||
@@ -371,7 +377,7 @@ func (r Report) Validate() error {
|
||||
//
|
||||
// This for now creates node's LatestControls from Controls.
|
||||
func (r Report) Upgrade() Report {
|
||||
return r.upgradeLatestControls().upgradePodNodes().upgradeNamespaces()
|
||||
return r.upgradeLatestControls().upgradePodNodes().upgradeNamespaces().upgradeDNSRecords()
|
||||
}
|
||||
|
||||
func (r Report) upgradeLatestControls() Report {
|
||||
@@ -469,6 +475,33 @@ func (r Report) upgradeNamespaces() Report {
|
||||
return r
|
||||
}
|
||||
|
||||
func (r Report) upgradeDNSRecords() Report {
|
||||
if len(r.DNS) > 0 {
|
||||
return r
|
||||
}
|
||||
dns := make(DNSRecords)
|
||||
for endpointID, endpoint := range r.Endpoint.Nodes {
|
||||
_, addr, _, ok := ParseEndpointNodeID(endpointID)
|
||||
snoopedNames, foundS := endpoint.Sets.Lookup(SnoopedDNSNames)
|
||||
reverseNames, foundR := endpoint.Sets.Lookup(ReverseDNSNames)
|
||||
if ok && (foundS || foundR) {
|
||||
// Add address and names to report-level map
|
||||
if existing, found := dns[addr]; found {
|
||||
// Optimise the expected case that they are equal
|
||||
if existing.Forward.Equal(snoopedNames) && existing.Reverse.Equal(reverseNames) {
|
||||
continue
|
||||
}
|
||||
// Not equal - merge this node's data into existing data,
|
||||
snoopedNames = snoopedNames.Merge(existing.Forward)
|
||||
reverseNames = reverseNames.Merge(existing.Reverse)
|
||||
}
|
||||
dns[addr] = DNSRecord{Forward: snoopedNames, Reverse: reverseNames}
|
||||
}
|
||||
}
|
||||
r.DNS = dns
|
||||
return r
|
||||
}
|
||||
|
||||
// BackwardCompatible returns a new backward-compatible report.
|
||||
//
|
||||
// This for now creates node's Controls from LatestControls.
|
||||
|
||||
@@ -50,6 +50,19 @@ func (s StringSet) Intersection(b StringSet) StringSet {
|
||||
return result
|
||||
}
|
||||
|
||||
// Equal returns true if a and b have the same contents
|
||||
func (s StringSet) Equal(b StringSet) bool {
|
||||
if len(s) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := range s {
|
||||
if s[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Add adds the strings to the StringSet. Add is the only valid way to grow a
|
||||
// StringSet. Add returns the StringSet to enable chaining.
|
||||
func (s StringSet) Add(strs ...string) StringSet {
|
||||
|
||||
Reference in New Issue
Block a user