func TestMerge(t *testing.T) { log.SetOutput(ioutil.Discard) var ( p1Addr = "localhost:7888" p2Addr = "localhost:7889" ) p1, err := xfer.NewTCPPublisher(p1Addr) if err != nil { t.Fatal(err) } defer p1.Close() p2, err := xfer.NewTCPPublisher(p2Addr) if err != nil { t.Fatal(err) } defer p2.Close() batchTime := 100 * time.Millisecond c := xfer.NewCollector(batchTime, "id") c.Add(p1Addr) c.Add(p2Addr) defer c.Stop() time.Sleep(batchTime / 10) // connect k1, k2 := report.MakeHostNodeID("p1"), report.MakeHostNodeID("p2") { r := report.MakeReport() r.Host.NodeMetadatas[k1] = report.NodeMetadata{"host_name": "test1"} p1.Publish(r) } { r := report.MakeReport() r.Host.NodeMetadatas[k2] = report.NodeMetadata{"host_name": "test2"} p2.Publish(r) } success := make(chan struct{}) go func() { defer close(success) for r := range c.Reports() { if r.Host.NodeMetadatas[k1]["host_name"] != "test1" { continue } if r.Host.NodeMetadatas[k2]["host_name"] != "test2" { continue } return } }() select { case <-success: case <-time.After(2 * batchTime): t.Errorf("collector didn't capture both reports") } }
// Report implements Reporter. func (r *Reporter) Report() (report.Report, error) { var ( rep = report.MakeReport() localCIDRs []string ) for _, localNet := range r.localNets { localCIDRs = append(localCIDRs, localNet.String()) } uptime, err := GetUptime() if err != nil { return rep, err } kernel, err := GetKernelVersion() if err != nil { return rep, err } rep.Host.AddNode(report.MakeHostNodeID(r.hostID), report.MakeNodeWith(map[string]string{ Timestamp: Now(), HostName: r.hostName, OS: runtime.GOOS, Load: GetLoad(), KernelVersion: kernel, Uptime: uptime.String(), }).WithSets(report.Sets{ LocalNetworks: report.MakeStringSet(localCIDRs...), })) return rep, nil }
// Report implements Reporter. func (r *Reporter) Report() (report.Report, error) { var ( rep = report.MakeReport() localCIDRs []string ) for _, localNet := range r.localNets { localCIDRs = append(localCIDRs, localNet.String()) } uptime, err := GetUptime() if err != nil { return rep, err } kernel, err := GetKernelVersion() if err != nil { return rep, err } rep.Host.NodeMetadatas[report.MakeHostNodeID(r.hostID)] = report.MakeNodeMetadataWith(map[string]string{ Timestamp: Now(), HostName: r.hostName, LocalNetworks: strings.Join(localCIDRs, " "), OS: runtime.GOOS, Load: GetLoad(), KernelVersion: kernel, Uptime: uptime.String(), }) return rep, nil }
func TestEdgeID(t *testing.T) { for _, bad := range []string{ client54001EndpointNodeID, client54002EndpointNodeID, unknown1EndpointNodeID, unknown2EndpointNodeID, unknown3EndpointNodeID, clientAddressNodeID, serverAddressNodeID, unknownAddressNodeID, clientHostNodeID, serverHostNodeID, ">1.2.3.4", ">", ";", "", } { if srcNodeID, dstNodeID, ok := report.ParseEdgeID(bad); ok { t.Errorf("%q: expected failure, but got (%q, %q)", bad, srcNodeID, dstNodeID) } } for input, want := range map[string]struct{ srcNodeID, dstNodeID string }{ report.MakeEdgeID("a", report.MakeEndpointNodeID("a", "b", "c")): {"a", report.MakeEndpointNodeID("a", "b", "c")}, report.MakeEdgeID("a", report.MakeAddressNodeID("a", "b")): {"a", report.MakeAddressNodeID("a", "b")}, report.MakeEdgeID("a", report.MakeProcessNodeID("a", "b")): {"a", report.MakeProcessNodeID("a", "b")}, report.MakeEdgeID("a", report.MakeHostNodeID("a")): {"a", report.MakeHostNodeID("a")}, "host.com|1.2.3.4": {"host.com", "1.2.3.4"}, "a|b;c": {"a", "b;c"}, "a|b": {"a", "b"}, "a|": {"a", ""}, "|b": {"", "b"}, "|": {"", ""}, } { srcNodeID, dstNodeID, ok := report.ParseEdgeID(input) if !ok { t.Errorf("%q: not OK", input) continue } if want, have := want.srcNodeID, srcNodeID; want != have { t.Errorf("%q: want %q, have %q", input, want, have) } if want, have := want.dstNodeID, dstNodeID; want != have { t.Errorf("%q: want %q, have %q", input, want, have) } } }
func TestReporter(t *testing.T) { var ( release = "release" version = "version" network = "192.168.0.0/16" hostID = "hostid" hostname = "hostname" timestamp = time.Now() load = report.Metrics{ host.Load1: report.MakeMetric().Add(timestamp, 1.0), host.Load5: report.MakeMetric().Add(timestamp, 5.0), host.Load15: report.MakeMetric().Add(timestamp, 15.0), host.CPUUsage: report.MakeMetric().Add(timestamp, 30.0).WithMax(100.0), host.MemUsage: report.MakeMetric().Add(timestamp, 60.0).WithMax(100.0), } uptime = "278h55m43s" kernel = "release version" _, ipnet, _ = net.ParseCIDR(network) localNets = report.Networks([]*net.IPNet{ipnet}) ) mtime.NowForce(timestamp) defer mtime.NowReset() var ( oldGetKernelVersion = host.GetKernelVersion oldGetLoad = host.GetLoad oldGetUptime = host.GetUptime oldGetCPUUsagePercent = host.GetCPUUsagePercent oldGetMemoryUsageBytes = host.GetMemoryUsageBytes ) defer func() { host.GetKernelVersion = oldGetKernelVersion host.GetLoad = oldGetLoad host.GetUptime = oldGetUptime host.GetCPUUsagePercent = oldGetCPUUsagePercent host.GetMemoryUsageBytes = oldGetMemoryUsageBytes }() host.GetKernelVersion = func() (string, error) { return release + " " + version, nil } host.GetLoad = func(time.Time) report.Metrics { return load } host.GetUptime = func() (time.Duration, error) { return time.ParseDuration(uptime) } host.GetCPUUsagePercent = func() (float64, float64) { return 30.0, 100.0 } host.GetMemoryUsageBytes = func() (float64, float64) { return 60.0, 100.0 } want := report.MakeReport() want.Host.AddNode(report.MakeHostNodeID(hostID), report.MakeNodeWith(map[string]string{ host.Timestamp: timestamp.UTC().Format(time.RFC3339Nano), host.HostName: hostname, host.OS: runtime.GOOS, host.Uptime: uptime, host.KernelVersion: kernel, }).WithSets(report.Sets{ host.LocalNetworks: report.MakeStringSet(network), }).WithMetrics(load)) have, _ := host.NewReporter(hostID, hostname, localNets).Report() if !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } }
// FIXME: Hideous hack to remove persistent-connection edges to virtual service // IPs attributed to the internet. We add each service IP as a /32 network // (the global service-cluster-ip-range is not exposed by the API // server so we treat each IP as a /32 network see // https://github.com/kubernetes/kubernetes/issues/25533). // The right way of fixing this is performing DNAT mapping on persistent // connections for which we don't have a robust solution // (see https://github.com/weaveworks/scope/issues/1491) func (r *Reporter) hostTopology(services []Service) report.Topology { localNetworks := report.EmptyStringSet for _, service := range services { localNetworks = localNetworks.Add(service.ClusterIP() + "/32") } node := report.MakeNode(report.MakeHostNodeID(r.hostID)) node = node.WithSets(report.EmptySets. Add(host.LocalNetworks, localNetworks)) return report.MakeTopology().AddNode(node) }
// Report implements Reporter. func (r *Reporter) Report() (report.Report, error) { defer func(begin time.Time) { SpyDuration.WithLabelValues().Observe(float64(time.Since(begin))) }(time.Now()) hostNodeID := report.MakeHostNodeID(r.hostID) rpt := report.MakeReport() { conns, err := procspy.Connections(r.includeProcesses) if err != nil { return rpt, err } commonNodeInfo := report.MakeNode().WithMetadata(report.Metadata{ Procspied: "true", }) for conn := conns.Next(); conn != nil; conn = conns.Next() { var ( localPort = conn.LocalPort remotePort = conn.RemotePort localAddr = conn.LocalAddress.String() remoteAddr = conn.RemoteAddress.String() ) extraNodeInfo := commonNodeInfo.Copy() if conn.Proc.PID > 0 { extraNodeInfo = extraNodeInfo.WithMetadata(report.Metadata{ process.PID: strconv.FormatUint(uint64(conn.Proc.PID), 10), report.HostNodeID: hostNodeID, }) } r.addConnection(&rpt, localAddr, remoteAddr, localPort, remotePort, &extraNodeInfo, &commonNodeInfo) } } if r.conntracker != nil { extraNodeInfo := report.MakeNode().WithMetadata(report.Metadata{ Conntracked: "true", }) r.conntracker.WalkFlows(func(f Flow) { var ( localPort = uint16(f.Original.Layer4.SrcPort) remotePort = uint16(f.Original.Layer4.DstPort) localAddr = f.Original.Layer3.SrcIP remoteAddr = f.Original.Layer3.DstIP ) r.addConnection(&rpt, localAddr, remoteAddr, localPort, remotePort, &extraNodeInfo, &extraNodeInfo) }) } if r.natmapper != nil { r.natmapper.ApplyNAT(rpt, r.hostID) } return rpt, nil }
func TestMapEndpointIdentity(t *testing.T) { for _, input := range []testcase{ {report.MakeNodeMetadata(), false}, {report.MakeNodeMetadataWith(map[string]string{endpoint.Addr: "1.2.3.4"}), false}, {report.MakeNodeMetadataWith(map[string]string{endpoint.Port: "1234"}), false}, {report.MakeNodeMetadataWith(map[string]string{endpoint.Addr: "1.2.3.4", endpoint.Port: "1234"}), true}, {report.MakeNodeMetadataWith(map[string]string{report.HostNodeID: report.MakeHostNodeID("foo"), endpoint.Addr: "10.0.0.1", endpoint.Port: "20001"}), true}, } { testMap(t, render.MapEndpointIdentity, input) } }
func TestMapEndpointIdentity(t *testing.T) { for _, input := range []testcase{ {nrn(report.MakeNode()), false}, {nrn(report.MakeNodeWith(map[string]string{endpoint.Addr: "1.2.3.4", endpoint.Procspied: "true"})), false}, {nrn(report.MakeNodeWith(map[string]string{endpoint.Port: "1234", endpoint.Procspied: "true"})), false}, {nrn(report.MakeNodeWith(map[string]string{endpoint.Addr: "1.2.3.4", endpoint.Port: "1234", endpoint.Procspied: "true"})), true}, {nrn(report.MakeNodeWith(map[string]string{endpoint.Addr: "1.2.3.4", endpoint.Port: "40000", endpoint.Procspied: "true"})), true}, {nrn(report.MakeNodeWith(map[string]string{report.HostNodeID: report.MakeHostNodeID("foo"), endpoint.Addr: "10.0.0.1", endpoint.Port: "20001", endpoint.Procspied: "true"})), true}, } { testMap(t, render.MapEndpointIdentity, input) } }
func TestReporter(t *testing.T) { var ( release = "release" version = "version" network = "192.168.0.0/16" hostID = "hostid" now = "now" hostname = "hostname" timestamp = time.Now() load = report.Metrics{ host.Load1: report.MakeMetric().Add(timestamp, 1.0), host.Load5: report.MakeMetric().Add(timestamp, 5.0), host.Load15: report.MakeMetric().Add(timestamp, 15.0), } uptime = "278h55m43s" kernel = "release version" _, ipnet, _ = net.ParseCIDR(network) localNets = report.Networks([]*net.IPNet{ipnet}) ) var ( oldGetKernelVersion = host.GetKernelVersion oldGetLoad = host.GetLoad oldGetUptime = host.GetUptime oldNow = host.Now ) defer func() { host.GetKernelVersion = oldGetKernelVersion host.GetLoad = oldGetLoad host.GetUptime = oldGetUptime host.Now = oldNow }() host.GetKernelVersion = func() (string, error) { return release + " " + version, nil } host.GetLoad = func() report.Metrics { return load } host.GetUptime = func() (time.Duration, error) { return time.ParseDuration(uptime) } host.Now = func() string { return now } want := report.MakeReport() want.Host.AddNode(report.MakeHostNodeID(hostID), report.MakeNodeWith(map[string]string{ host.Timestamp: now, host.HostName: hostname, host.OS: runtime.GOOS, host.Uptime: uptime, host.KernelVersion: kernel, }).WithSets(report.Sets{ host.LocalNetworks: report.MakeStringSet(network), }).WithMetrics(load)) have, _ := host.NewReporter(hostID, hostname, localNets).Report() if !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } }
func TestTagger(t *testing.T) { var ( hostID = "foo" probeID = "a1b2c3d4" endpointNodeID = report.MakeEndpointNodeID(hostID, "1.2.3.4", "56789") // hostID ignored nodeMetadata = report.MakeNodeWith(map[string]string{"foo": "bar"}) ) r := report.MakeReport() r.Process.AddNode(endpointNodeID, nodeMetadata) want := nodeMetadata.Merge(report.MakeNodeWith(map[string]string{ report.HostNodeID: report.MakeHostNodeID(hostID), report.ProbeID: probeID, }).WithParents(report.Sets{ report.Host: report.MakeStringSet(report.MakeHostNodeID(hostID)), })) rpt, _ := host.NewTagger(hostID, probeID).Tag(r) have := rpt.Process.Nodes[endpointNodeID].Copy() if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
func TestTagger(t *testing.T) { var ( hostID = "foo" probeID = "a1b2c3d4" endpointNodeID = report.MakeEndpointNodeID(hostID, "1.2.3.4", "56789") // hostID ignored node = report.MakeNodeWith(map[string]string{"foo": "bar"}) ) r := report.MakeReport() r.Process.AddNode(endpointNodeID, node) rpt, _ := host.NewTagger(hostID, probeID).Tag(r) have := rpt.Process.Nodes[endpointNodeID].Copy() // It should now have the host ID wantHostID := report.MakeHostNodeID(hostID) if hostID, ok := have.Latest.Lookup(report.HostNodeID); !ok || hostID != wantHostID { t.Errorf("Expected %q got %q", wantHostID, report.MakeHostNodeID(hostID)) } // It should now have the probe ID if haveProbeID, ok := have.Latest.Lookup(report.ProbeID); !ok || haveProbeID != probeID { t.Errorf("Expected %q got %q", probeID, haveProbeID) } // It should still have the other keys want := "bar" if have, ok := have.Latest.Lookup("foo"); !ok || have != want { t.Errorf("Expected %q got %q", want, have) } // It should have the host as a parent wantParent := report.MakeHostNodeID(hostID) if have, ok := have.Parents.Lookup(report.Host); !ok || len(have) != 1 || have[0] != wantParent { t.Errorf("Expected %q got %q", report.MakeStringSet(wantParent), have) } }
func TestOriginHostTagger(t *testing.T) { var ( hostID = "foo" endpointNodeID = report.MakeEndpointNodeID(hostID, "1.2.3.4", "56789") // hostID ignored nodeMetadata = report.NodeMetadata{"foo": "bar"} ) r := report.MakeReport() r.Endpoint.NodeMetadatas[endpointNodeID] = nodeMetadata want := nodeMetadata.Merge(report.NodeMetadata{report.HostNodeID: report.MakeHostNodeID(hostID)}) rpt, _ := tag.NewOriginHostTagger(hostID).Tag(r) have := rpt.Endpoint.NodeMetadatas[endpointNodeID].Copy() if !reflect.DeepEqual(want, have) { t.Errorf("\nwant %+v\nhave %+v", want, have) } }
func TestReporter(t *testing.T) { oldInterfaceAddrs, oldNow, oldReadFile, oldUname := host.InterfaceAddrs, host.Now, host.ReadFile, host.Uname defer func() { host.InterfaceAddrs, host.Now, host.ReadFile, host.Uname = oldInterfaceAddrs, oldNow, oldReadFile, oldUname }() host.InterfaceAddrs = func() ([]net.Addr, error) { _, ipnet, _ := net.ParseCIDR(network) return []net.Addr{ipnet}, nil } host.Now = func() string { return now } host.ReadFile = func(filename string) ([]byte, error) { switch filename { case host.ProcUptime: return []byte(procUptime), nil case host.ProcLoad: return []byte(procLoad), nil default: panic(filename) } } host.Uname = func(uts *syscall.Utsname) error { uts.Release = string2c(release) uts.Version = string2c(version) return nil } r := host.NewReporter(hostid, hostname) have, _ := r.Report() want := report.MakeReport() want.Host.NodeMetadatas[report.MakeHostNodeID(hostid)] = report.NodeMetadata{ host.Timestamp: now, host.HostName: hostname, host.LocalNetworks: network, host.OS: runtime.GOOS, host.Load: load, host.Uptime: uptime, host.KernelVersion: kernel, } if !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } }
func TestReporter(t *testing.T) { var ( release = "release" version = "version" network = "192.168.0.0/16" hostID = "hostid" now = "now" hostname = "hostname" load = "0.59 0.36 0.29" uptime = "278h55m43s" kernel = "release version" _, ipnet, _ = net.ParseCIDR(network) localNets = report.Networks([]*net.IPNet{ipnet}) ) var ( oldGetKernelVersion = host.GetKernelVersion oldGetLoad = host.GetLoad oldGetUptime = host.GetUptime oldNow = host.Now ) defer func() { host.GetKernelVersion = oldGetKernelVersion host.GetLoad = oldGetLoad host.GetUptime = oldGetUptime host.Now = oldNow }() host.GetKernelVersion = func() (string, error) { return release + " " + version, nil } host.GetLoad = func() string { return load } host.GetUptime = func() (time.Duration, error) { return time.ParseDuration(uptime) } host.Now = func() string { return now } want := report.MakeReport() want.Host.NodeMetadatas[report.MakeHostNodeID(hostID)] = report.MakeNodeMetadataWith(map[string]string{ host.Timestamp: now, host.HostName: hostname, host.LocalNetworks: network, host.OS: runtime.GOOS, host.Load: load, host.Uptime: uptime, host.KernelVersion: kernel, }) have, _ := host.NewReporter(hostID, hostname, localNets).Report() if !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } }
func TestTagger(t *testing.T) { var ( hostID = "foo" endpointNodeID = report.MakeEndpointNodeID(hostID, "1.2.3.4", "56789") // hostID ignored nodeMetadata = report.NewNodeMetadata(map[string]string{"foo": "bar"}) ) r := report.MakeReport() r.Endpoint.NodeMetadatas[endpointNodeID] = nodeMetadata want := nodeMetadata.Merge(report.NewNodeMetadata(map[string]string{ report.HostNodeID: report.MakeHostNodeID(hostID), })) rpt, _ := host.NewTagger(hostID).Tag(r) have := rpt.Endpoint.NodeMetadatas[endpointNodeID].Copy() if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
// Report implements Reporter. func (r *Reporter) Report() (report.Report, error) { var ( rep = report.MakeReport() localCIDRs []string ) localNets, err := GetLocalNetworks() if err != nil { return rep, nil } for _, localNet := range localNets { localCIDRs = append(localCIDRs, localNet.String()) } uptime, err := GetUptime() if err != nil { return rep, err } kernel, err := GetKernelVersion() if err != nil { return rep, err } now := mtime.Now() metrics := GetLoad(now) cpuUsage, max := GetCPUUsagePercent() metrics[CPUUsage] = report.MakeMetric().Add(now, cpuUsage).WithMax(max) memoryUsage, max := GetMemoryUsageBytes() metrics[MemoryUsage] = report.MakeMetric().Add(now, memoryUsage).WithMax(max) rep.Host.AddNode(report.MakeHostNodeID(r.hostID), report.MakeNodeWith(map[string]string{ Timestamp: mtime.Now().UTC().Format(time.RFC3339Nano), HostName: r.hostName, OS: runtime.GOOS, KernelVersion: kernel, Uptime: uptime.String(), }).WithSets(report.EmptySets. Add(LocalNetworks, report.MakeStringSet(localCIDRs...)), ).WithMetrics(metrics)) return rep, nil }
func (r *reporter) Report() (report.Report, error) { var ( rep = report.MakeReport() localCIDRs []string ) localNets, err := InterfaceAddrs() if err != nil { return rep, err } for _, localNet := range localNets { // Not all networks are IP networks. if ipNet, ok := localNet.(*net.IPNet); ok { localCIDRs = append(localCIDRs, ipNet.String()) } } uptime, err := getUptime() if err != nil { return rep, err } kernel, err := getKernelVersion() if err != nil { return rep, err } rep.Host.NodeMetadatas[report.MakeHostNodeID(r.hostID)] = report.NodeMetadata{ Timestamp: Now(), HostName: r.hostName, LocalNetworks: strings.Join(localCIDRs, " "), OS: runtime.GOOS, Load: getLoad(), KernelVersion: kernel, Uptime: uptime.String(), } return rep, nil }
func TestReporter(t *testing.T) { var ( oldGetKernelVersion = host.GetKernelVersion oldGetLoad = host.GetLoad oldGetUptime = host.GetUptime oldInterfaceAddrs = host.InterfaceAddrs oldNow = host.Now ) defer func() { host.GetKernelVersion = oldGetKernelVersion host.GetLoad = oldGetLoad host.GetUptime = oldGetUptime host.InterfaceAddrs = oldInterfaceAddrs host.Now = oldNow }() host.GetKernelVersion = func() (string, error) { return release + " " + version, nil } host.GetLoad = func() string { return load } host.GetUptime = func() (time.Duration, error) { return time.ParseDuration(uptime) } host.Now = func() string { return now } host.InterfaceAddrs = func() ([]net.Addr, error) { _, ipnet, _ := net.ParseCIDR(network); return []net.Addr{ipnet}, nil } want := report.MakeReport() want.Host.NodeMetadatas[report.MakeHostNodeID(hostID)] = report.NewNodeMetadata(map[string]string{ host.Timestamp: now, host.HostName: hostname, host.LocalNetworks: network, host.OS: runtime.GOOS, host.Load: load, host.Uptime: uptime, host.KernelVersion: kernel, }) r := host.NewReporter(hostID, hostname) have, _ := r.Report() if !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } }
import ( "fmt" "reflect" "testing" "github.com/weaveworks/scope/probe/docker" "github.com/weaveworks/scope/probe/endpoint" "github.com/weaveworks/scope/probe/host" "github.com/weaveworks/scope/render" "github.com/weaveworks/scope/report" "github.com/weaveworks/scope/test" ) var ( serverHostID = "host1" serverHostNodeID = report.MakeHostNodeID(serverHostID) randomIP = "3.4.5.6" randomPort = "56789" randomEndpointNodeID = report.MakeEndpointNodeID(serverHostID, randomIP, randomPort) serverIP = "192.168.1.1" serverPort = "80" serverEndpointNodeID = report.MakeEndpointNodeID(serverHostID, serverIP, serverPort) containerID = "a1b2c3d4e5" containerIP = "192.168.0.1" containerName = "foo" containerNodeID = report.MakeContainerNodeID(containerID) rpt = report.Report{
func TestReporter(t *testing.T) { var ( release = "release" version = "version" network = "192.168.0.0/16" hostID = "hostid" hostname = "hostname" timestamp = time.Now() metrics = report.Metrics{ host.Load1: report.MakeMetric().Add(timestamp, 1.0), host.Load5: report.MakeMetric().Add(timestamp, 5.0), host.Load15: report.MakeMetric().Add(timestamp, 15.0), host.CPUUsage: report.MakeMetric().Add(timestamp, 30.0).WithMax(100.0), host.MemoryUsage: report.MakeMetric().Add(timestamp, 60.0).WithMax(100.0), } uptime = "278h55m43s" kernel = "release version" _, ipnet, _ = net.ParseCIDR(network) ) mtime.NowForce(timestamp) defer mtime.NowReset() var ( oldGetKernelVersion = host.GetKernelVersion oldGetLoad = host.GetLoad oldGetUptime = host.GetUptime oldGetCPUUsagePercent = host.GetCPUUsagePercent oldGetMemoryUsageBytes = host.GetMemoryUsageBytes oldGetLocalNetworks = host.GetLocalNetworks ) defer func() { host.GetKernelVersion = oldGetKernelVersion host.GetLoad = oldGetLoad host.GetUptime = oldGetUptime host.GetCPUUsagePercent = oldGetCPUUsagePercent host.GetMemoryUsageBytes = oldGetMemoryUsageBytes host.GetLocalNetworks = oldGetLocalNetworks }() host.GetKernelVersion = func() (string, error) { return release + " " + version, nil } host.GetLoad = func(time.Time) report.Metrics { return metrics } host.GetUptime = func() (time.Duration, error) { return time.ParseDuration(uptime) } host.GetCPUUsagePercent = func() (float64, float64) { return 30.0, 100.0 } host.GetMemoryUsageBytes = func() (float64, float64) { return 60.0, 100.0 } host.GetLocalNetworks = func() ([]*net.IPNet, error) { return []*net.IPNet{ipnet}, nil } rpt, err := host.NewReporter(hostID, hostname).Report() if err != nil { t.Fatal(err) } nodeID := report.MakeHostNodeID(hostID) node, ok := rpt.Host.Nodes[nodeID] if !ok { t.Errorf("Expected host node %q, but not found", nodeID) } // Should have a bunch of expected latest keys for _, tuple := range []struct { key, want string }{ {host.Timestamp, timestamp.UTC().Format(time.RFC3339Nano)}, {host.HostName, hostname}, {host.OS, runtime.GOOS}, {host.Uptime, uptime}, {host.KernelVersion, kernel}, } { if have, ok := node.Latest.Lookup(tuple.key); !ok || have != tuple.want { t.Errorf("Expected %s %q, got %q", tuple.key, tuple.want, have) } } // Should have the local network if have, ok := node.Sets.Lookup(host.LocalNetworks); !ok || !have.Contains(network) { t.Errorf("Expected host.LocalNetworks to include %q, got %q", network, have) } // Should have metrics for key, want := range metrics { wantSample := want.LastSample() if metric, ok := node.Metrics[key]; !ok { t.Errorf("Expected %s metric, but not found", key) } else if sample := metric.LastSample(); sample == nil { t.Errorf("Expected %s metric to have a sample, but there were none", key) } else if sample.Value != wantSample.Value { t.Errorf("Expected %s metric sample %f, got %f", key, wantSample, sample.Value) } } }
package report_test import ( "net" "reflect" "testing" "github.com/weaveworks/scope/report" ) var ( clientHostID = "client.host.com" clientHostName = clientHostID clientHostNodeID = report.MakeHostNodeID(clientHostID) clientAddress = "10.10.10.20" serverHostID = "server.host.com" serverHostName = serverHostID serverHostNodeID = report.MakeHostNodeID(serverHostID) serverAddress = "10.10.10.1" unknownHostID = "" // by definition, we don't know it unknownAddress = "172.16.93.112" // will be a pseudonode, no corresponding host client54001EndpointNodeID = report.MakeEndpointNodeID(clientHostID, clientAddress, "54001") // i.e. curl client54002EndpointNodeID = report.MakeEndpointNodeID(clientHostID, clientAddress, "54002") // also curl server80EndpointNodeID = report.MakeEndpointNodeID(serverHostID, serverAddress, "80") // i.e. apache unknown1EndpointNodeID = report.MakeEndpointNodeID(unknownHostID, unknownAddress, "10001") unknown2EndpointNodeID = report.MakeEndpointNodeID(unknownHostID, unknownAddress, "10002") unknown3EndpointNodeID = report.MakeEndpointNodeID(unknownHostID, unknownAddress, "10003") clientAddressNodeID = report.MakeAddressNodeID(clientHostID, clientAddress) serverAddressNodeID = report.MakeAddressNodeID(serverHostID, serverAddress)
// Report implements Reporter. func (r *Reporter) Report() (report.Report, error) { defer func(begin time.Time) { SpyDuration.WithLabelValues().Observe(float64(time.Since(begin))) }(time.Now()) hostNodeID := report.MakeHostNodeID(r.hostID) rpt := report.MakeReport() seenTuples := map[string]fourTuple{} // Consult the flowWalker for short-lived connections { extraNodeInfo := map[string]string{ Conntracked: "true", } r.flowWalker.walkFlows(func(f flow) { tuple := fourTuple{ f.Original.Layer3.SrcIP, f.Original.Layer3.DstIP, uint16(f.Original.Layer4.SrcPort), uint16(f.Original.Layer4.DstPort), } // Handle DNAT-ed short-lived connections. // The NAT mapper won't help since it only runs periodically, // missing the short-lived connections. if f.Original.Layer3.DstIP != f.Reply.Layer3.SrcIP { tuple = fourTuple{ f.Reply.Layer3.DstIP, f.Reply.Layer3.SrcIP, uint16(f.Reply.Layer4.DstPort), uint16(f.Reply.Layer4.SrcPort), } } seenTuples[tuple.key()] = tuple r.addConnection(&rpt, tuple, extraNodeInfo, extraNodeInfo) }) } if r.walkProc { conns, err := r.scanner.Connections(r.spyProcs) if err != nil { return rpt, err } for conn := conns.Next(); conn != nil; conn = conns.Next() { var ( tuple = fourTuple{ conn.LocalAddress.String(), conn.RemoteAddress.String(), conn.LocalPort, conn.RemotePort, } toNodeInfo = map[string]string{Procspied: "true"} fromNodeInfo = map[string]string{Procspied: "true"} ) if conn.Proc.PID > 0 { fromNodeInfo[process.PID] = strconv.FormatUint(uint64(conn.Proc.PID), 10) fromNodeInfo[report.HostNodeID] = hostNodeID } // If we've already seen this connection, we should know the direction // (or have already figured it out), so we normalize and use the // canonical direction. Otherwise, we can use a port-heuristic to guess // the direction. canonical, ok := seenTuples[tuple.key()] if (ok && canonical != tuple) || (!ok && tuple.fromPort < tuple.toPort) { tuple.reverse() toNodeInfo, fromNodeInfo = fromNodeInfo, toNodeInfo } r.addConnection(&rpt, tuple, fromNodeInfo, toNodeInfo) } } r.natMapper.applyNAT(rpt, r.hostID) return rpt, nil }
NonContainerClientPort = "46789" ClientHostName = ClientHostID ServerHostName = ServerHostID Client1PID = "10001" Client2PID = "30020" ServerPID = "215" NonContainerPID = "1234" Client1Comm = "curl" Client2Comm = "curl" ServerComm = "apache" NonContainerComm = "bash" ClientHostNodeID = report.MakeHostNodeID(ClientHostID) ServerHostNodeID = report.MakeHostNodeID(ServerHostID) Client54001NodeID = report.MakeEndpointNodeID(ClientHostID, ClientIP, ClientPort54001) // curl (1) Client54002NodeID = report.MakeEndpointNodeID(ClientHostID, ClientIP, ClientPort54002) // curl (2) Server80NodeID = report.MakeEndpointNodeID(ServerHostID, ServerIP, ServerPort) // apache UnknownClient1NodeID = report.MakeEndpointNodeID(ServerHostID, UnknownClient1IP, UnknownClient1Port) // we want to ensure two unknown clients, connnected UnknownClient2NodeID = report.MakeEndpointNodeID(ServerHostID, UnknownClient2IP, UnknownClient2Port) // to the same server, are deduped. UnknownClient3NodeID = report.MakeEndpointNodeID(ServerHostID, UnknownClient3IP, UnknownClient3Port) // Check this one isn't deduped RandomClientNodeID = report.MakeEndpointNodeID(ServerHostID, RandomClientIP, RandomClientPort) // this should become an internet node NonContainerNodeID = report.MakeEndpointNodeID(ServerHostID, ServerIP, NonContainerClientPort) GoogleEndpointNodeID = report.MakeEndpointNodeID(ServerHostID, GoogleIP, GooglePort) ClientProcess1NodeID = report.MakeProcessNodeID(ClientHostID, Client1PID) ClientProcess2NodeID = report.MakeProcessNodeID(ClientHostID, Client2PID) ServerProcessNodeID = report.MakeProcessNodeID(ServerHostID, ServerPID)
// NewOriginHostTagger tags each node with a foreign key linking it to its // origin host in the host topology. func NewOriginHostTagger(hostID string) Tagger { return &originHostTagger{hostNodeID: report.MakeHostNodeID(hostID)} }
// NewTagger tags each node with a foreign key linking it to its origin host // in the host topology. func NewTagger(hostID, probeID string) Tagger { return Tagger{ hostNodeID: report.MakeHostNodeID(hostID), probeID: probeID, } }
func (r *Reporter) addConnection(rpt *report.Report, localAddr, remoteAddr string, localPort, remotePort uint16, proc *procspy.Proc) { var ( localIsClient = int(localPort) > int(remotePort) hostNodeID = report.MakeHostNodeID(r.hostID) ) // Update address topology { var ( localAddressNodeID = report.MakeAddressNodeID(r.hostID, localAddr) remoteAddressNodeID = report.MakeAddressNodeID(r.hostID, remoteAddr) localNode = report.MakeNodeWith(map[string]string{ "name": r.hostName, Addr: localAddr, report.HostNodeID: hostNodeID, }) remoteNode = report.MakeNodeWith(map[string]string{ Addr: remoteAddr, }) ) if localIsClient { // New nodes are merged into the report so we don't need to do any counting here; the merge does it for us. localNode = localNode.WithEdge(remoteAddressNodeID, report.EdgeMetadata{ MaxConnCountTCP: newu64(1), }) } else { remoteNode = localNode.WithEdge(localAddressNodeID, report.EdgeMetadata{ MaxConnCountTCP: newu64(1), }) } rpt.Address = rpt.Address.WithNode(localAddressNodeID, localNode) rpt.Address = rpt.Address.WithNode(remoteAddressNodeID, remoteNode) } // Update endpoint topology if r.includeProcesses { var ( localEndpointNodeID = report.MakeEndpointNodeID(r.hostID, localAddr, strconv.Itoa(int(localPort))) remoteEndpointNodeID = report.MakeEndpointNodeID(r.hostID, remoteAddr, strconv.Itoa(int(remotePort))) localNode = report.MakeNodeWith(map[string]string{ Addr: localAddr, Port: strconv.Itoa(int(localPort)), report.HostNodeID: hostNodeID, }) remoteNode = report.MakeNodeWith(map[string]string{ Addr: remoteAddr, Port: strconv.Itoa(int(remotePort)), }) ) if localIsClient { // New nodes are merged into the report so we don't need to do any counting here; the merge does it for us. localNode = localNode.WithEdge(remoteEndpointNodeID, report.EdgeMetadata{ MaxConnCountTCP: newu64(1), }) } else { remoteNode = remoteNode.WithEdge(localEndpointNodeID, report.EdgeMetadata{ MaxConnCountTCP: newu64(1), }) } if proc != nil && proc.PID > 0 { localNode.Metadata[process.PID] = strconv.FormatUint(uint64(proc.PID), 10) } rpt.Endpoint = rpt.Endpoint.WithNode(localEndpointNodeID, localNode) rpt.Endpoint = rpt.Endpoint.WithNode(remoteEndpointNodeID, remoteNode) } }