mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 18:20:27 +00:00
118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/weaveworks/procspy"
|
|
"github.com/weaveworks/scope/report"
|
|
)
|
|
|
|
// spy invokes procspy.Connections to generate a report.Report that contains
|
|
// every discovered (spied) connection on the host machine, at the granularity
|
|
// of host and port. It optionally enriches that topology with process (PID)
|
|
// information.
|
|
func spy(
|
|
nodeID, nodeName string,
|
|
includeProcesses bool,
|
|
pms []processMapper,
|
|
) report.Report {
|
|
defer func(begin time.Time) {
|
|
spyDuration.WithLabelValues().Observe(float64(time.Since(begin)))
|
|
}(time.Now())
|
|
|
|
r := report.NewReport()
|
|
|
|
conns, err := procspy.Connections(includeProcesses)
|
|
if err != nil {
|
|
log.Printf("spy connections: %v", err)
|
|
return r
|
|
}
|
|
|
|
for conn := conns.Next(); conn != nil; conn = conns.Next() {
|
|
addConnection(&r, conn, nodeID, nodeName, pms)
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func addConnection(
|
|
r *report.Report,
|
|
c *procspy.Connection,
|
|
nodeID, nodeName string,
|
|
pms []processMapper,
|
|
) {
|
|
var (
|
|
scopedLocal = scopedIP(nodeID, c.LocalAddress)
|
|
scopedRemote = scopedIP(nodeID, c.RemoteAddress)
|
|
key = nodeID + report.IDDelim + scopedLocal
|
|
edgeKey = scopedLocal + report.IDDelim + scopedRemote
|
|
)
|
|
|
|
r.Network.Adjacency[key] = r.Network.Adjacency[key].Add(scopedRemote)
|
|
|
|
if _, ok := r.Network.NodeMetadatas[scopedLocal]; !ok {
|
|
r.Network.NodeMetadatas[scopedLocal] = report.NodeMetadata{
|
|
"name": nodeName,
|
|
}
|
|
}
|
|
|
|
// Count the TCP connection.
|
|
edgeMeta := r.Network.EdgeMetadatas[edgeKey]
|
|
edgeMeta.WithConnCountTCP = true
|
|
edgeMeta.MaxConnCountTCP++
|
|
r.Network.EdgeMetadatas[edgeKey] = edgeMeta
|
|
|
|
if c.Proc.PID > 0 {
|
|
var (
|
|
scopedLocal = scopedIPPort(nodeID, c.LocalAddress, c.LocalPort)
|
|
scopedRemote = scopedIPPort(nodeID, c.RemoteAddress, c.RemotePort)
|
|
key = nodeID + report.IDDelim + scopedLocal
|
|
edgeKey = scopedLocal + report.IDDelim + scopedRemote
|
|
)
|
|
|
|
r.Process.Adjacency[key] = r.Process.Adjacency[key].Add(scopedRemote)
|
|
|
|
if _, ok := r.Process.NodeMetadatas[scopedLocal]; !ok {
|
|
// First hit establishes NodeMetadata for scoped local address + port
|
|
md := report.NodeMetadata{
|
|
"pid": fmt.Sprintf("%d", c.Proc.PID),
|
|
"name": c.Proc.Name,
|
|
"domain": nodeID,
|
|
}
|
|
|
|
for _, pm := range pms {
|
|
v, err := pm.Map(c.PID)
|
|
if err != nil {
|
|
log.Printf("spy processes: %s", err)
|
|
continue
|
|
}
|
|
md[pm.Key()] = v
|
|
}
|
|
|
|
r.Process.NodeMetadatas[scopedLocal] = md
|
|
}
|
|
// Count the TCP connection.
|
|
edgeMeta := r.Process.EdgeMetadatas[edgeKey]
|
|
edgeMeta.WithConnCountTCP = true
|
|
edgeMeta.MaxConnCountTCP++
|
|
r.Process.EdgeMetadatas[edgeKey] = edgeMeta
|
|
}
|
|
}
|
|
|
|
// scopedIP makes an IP unique over multiple networks.
|
|
func scopedIP(scope string, ip net.IP) string {
|
|
if ip.IsLoopback() {
|
|
return scope + report.ScopeDelim + ip.String()
|
|
}
|
|
return report.ScopeDelim + ip.String()
|
|
}
|
|
|
|
// scopedIPPort makes an IP+port tuple unique over multiple networks.
|
|
func scopedIPPort(scope string, ip net.IP, port uint16) string {
|
|
return scopedIP(scope, ip) + report.ScopeDelim + strconv.FormatUint(uint64(port), 10)
|
|
}
|