Skip to content

Commit

Permalink
Move DNS name mapping from endpoint to report
Browse files Browse the repository at this point in the history
  • Loading branch information
bboreham committed Feb 6, 2018
1 parent 20c5713 commit 9a3b603
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 28 deletions.
22 changes: 16 additions & 6 deletions probe/endpoint/connection_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,23 +219,33 @@ func (t *connectionTracker) addConnection(rpt *report.Report, incoming bool, ft
)
rpt.Endpoint = rpt.Endpoint.AddNode(fromNode.WithAdjacent(toNode.ID))
rpt.Endpoint = 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()
Expand Down
14 changes: 7 additions & 7 deletions render/detailed/connections.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(rpt report.Report, 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
Expand All @@ -94,26 +94,26 @@ 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(rpt, remoteNode, remoteEndpoint); !ok {
return
}
if conn.localAddr, ok = internetAddr(localNode, localEndpoint); !ok {
if conn.localAddr, ok = internetAddr(rpt, localNode, localEndpoint); !ok {
return
}

c.counted[connectionID] = struct{}{}
c.counts[conn]++
}

func internetAddr(node report.Node, ep report.Node) (string, bool) {
func internetAddr(rpt report.Report, node report.Node, ep report.Node) (string, bool) {
if !render.IsInternetNode(node) {
return "", true
}
_, addr, _, ok := report.ParseEndpointNodeID(ep.ID)
if !ok {
return "", false
}
if name, found := render.DNSFirstMatch(ep, func(string) bool { return true }); found {
if name, found := render.DNSFirstMatch(rpt, ep, 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)
Expand Down Expand Up @@ -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, false, n, node, r.Endpoint.Nodes[localEndpointID], remoteEndpoint)
}
}
}
Expand Down Expand Up @@ -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, true, n, node, localEndpoint, r.Endpoint.Nodes[remoteEndpointID])
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion render/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
26 changes: 13 additions & 13 deletions render/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package render
import (
"strings"

"github.com/weaveworks/scope/probe/endpoint"
"github.com/weaveworks/scope/report"
)

Expand Down Expand Up @@ -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
}

Expand All @@ -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 := DNSFirstMatch(rpt, n, isKnownService); found {
return ServiceNodeIDPrefix + hostname, true
}

Expand All @@ -103,20 +102,21 @@ func externalNodeID(n report.Node, addr string, local report.Networks) (string,
}

// 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
// true, from snooped and reverse-resolved DNS names.
func DNSFirstMatch(rpt report.Report, n report.Node, match func(name string) bool) (string, bool) {
_, addr, _, ok := report.ParseEndpointNodeID(n.ID)
if !ok {
return "", false
}
// we rely on StringSets being sorted, to make selection for display more
// deterministic
// prioritize snooped names
snoopedNames, _ := n.Sets.Lookup(endpoint.SnoopedDNSNames)
for _, hostname := range snoopedNames {
for _, hostname := range rpt.DNS[addr].Forward {
if match(hostname) {
return hostname, true
}
}
reverseNames, _ := n.Sets.Lookup(endpoint.ReverseDNSNames)
for _, hostname := range reverseNames {
for _, hostname := range rpt.DNS[addr].Reverse {
if match(hostname) {
return hostname, true
}
Expand Down
53 changes: 52 additions & 1 deletion report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ var topologyNames = []string{
SwarmService,
}

type DNSRecord struct {
Forward StringSet `json:"forward,omitempty"`
Reverse StringSet `json:"reverse,omitempty"`
}

type DNSRecords map[string]DNSRecord

func (r DNSRecords) Copy() DNSRecords {
cp := make(DNSRecords, len(r))
for k, v := range r {
cp[k] = v
}
return cp
}

// Report is the core data type. It's produced by probes, and consumed and
// stored by apps. It's composed of multiple topologies, each representing
// a different (related, but not equivalent) view of the network.
Expand Down Expand Up @@ -151,6 +166,8 @@ type Report struct {
// their status endpoints. Edges are present.
Overlay Topology

DNS DNSRecords

// Sampling data for this report.
Sampling Sampling

Expand Down Expand Up @@ -242,6 +259,8 @@ func MakeReport() Report {
WithShape(Heptagon).
WithLabel("service", "services"),

DNS: DNSRecords{},

Sampling: Sampling{},
Window: 0,
Plugins: xfer.MakePluginSpecs(),
Expand All @@ -252,6 +271,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(),
Expand Down Expand Up @@ -371,7 +391,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 {
Expand Down Expand Up @@ -469,6 +489,37 @@ func (r Report) upgradeNamespaces() Report {
return r
}

// Note in-place modification of Endpoint.Nodes
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 data - we assume
// all endpoints with the same address have equally good data
if _, found := dns[addr]; ok && !found {
dns[addr] = DNSRecord{Forward: snoopedNames, Reverse: reverseNames}
}
// Now remove the entries from Sets, to save work during merging
// First, the case where these are the only entries in Sets - just blank it
if (foundS && foundR && endpoint.Sets.Size() == 2) || endpoint.Sets.Size() == 1 {
endpoint.Sets = MakeSets()
} else {
// Do it the hard way
endpoint.Sets = endpoint.Sets.Delete(SnoopedDNSNames).Delete(ReverseDNSNames)
}
r.Endpoint.Nodes[endpointID] = endpoint
}
}
r.DNS = dns
return r
}

// BackwardCompatible returns a new backward-compatible report.
//
// This for now creates node's Controls from LatestControls.
Expand Down

0 comments on commit 9a3b603

Please sign in to comment.