func (c *container) ports(localAddrs []net.IP) report.StringSet { if c.container.NetworkSettings == nil { return report.MakeStringSet() } ports := []string{} for port, bindings := range c.container.NetworkSettings.Ports { if len(bindings) == 0 { ports = append(ports, fmt.Sprintf("%s", port)) continue } for _, b := range bindings { if b.HostIP != "0.0.0.0" { ports = append(ports, fmt.Sprintf("%s:%s->%s", b.HostIP, b.HostPort, port)) continue } for _, ip := range localAddrs { if ip.To4() != nil { ports = append(ports, fmt.Sprintf("%s:%s->%s", ip, b.HostPort, port)) } } } } return report.MakeStringSet(ports...) }
func TestWeaveTaggerOverlayTopology(t *testing.T) { oldExecCmd := exec.Command defer func() { exec.Command = oldExecCmd }() exec.Command = func(name string, args ...string) exec.Cmd { return testExec.NewMockCmdString(fmt.Sprintf("%s %s %s/24\n", mockContainerID, mockContainerMAC, mockContainerIP)) } s := httptest.NewServer(http.HandlerFunc(mockWeaveRouter)) defer s.Close() w := overlay.NewWeave(mockHostID, s.URL) defer w.Stop() w.Tick() { have, err := w.Report() if err != nil { t.Fatal(err) } if want, have := report.MakeTopology().AddNode( report.MakeOverlayNodeID(mockWeavePeerName), report.MakeNodeWith(map[string]string{ overlay.WeavePeerName: mockWeavePeerName, overlay.WeavePeerNickName: mockWeavePeerNickName, }), ), have.Overlay; !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } } { nodeID := report.MakeContainerNodeID(mockHostID, mockContainerID) want := report.Report{ Container: report.MakeTopology().AddNode(nodeID, report.MakeNodeWith(map[string]string{ docker.ContainerID: mockContainerID, overlay.WeaveDNSHostname: mockHostname, overlay.WeaveMACAddress: mockContainerMAC, }).WithSets(report.Sets{ docker.ContainerIPs: report.MakeStringSet(mockContainerIP), docker.ContainerIPsWithScopes: report.MakeStringSet(mockContainerIPWithScope), })), } have, err := w.Tag(report.Report{ Container: report.MakeTopology().AddNode(nodeID, report.MakeNodeWith(map[string]string{ docker.ContainerID: mockContainerID, })), }) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } } }
func (t *Tagger) tag(tree process.Tree, topology *report.Topology) { for nodeID, node := range topology.Nodes { pidStr, ok := node.Latest.Lookup(process.PID) if !ok { continue } pid, err := strconv.ParseUint(pidStr, 10, 64) if err != nil { continue } var ( c Container candidate = int(pid) ) t.registry.LockedPIDLookup(func(lookup func(int) Container) { for { c = lookup(candidate) if c != nil { break } candidate, err = tree.GetParent(candidate) if err != nil { break } } }) if c == nil || ContainerIsStopped(c) || c.PID() == 1 { continue } node := report.MakeNodeWith(nodeID, map[string]string{ ContainerID: c.ID(), }).WithParents(report.EmptySets. Add(report.Container, report.MakeStringSet(report.MakeContainerNodeID(c.ID()))), ) // If we can work out the image name, add a parent tag for it image, ok := t.registry.GetContainerImage(c.Image()) if ok && len(image.RepoTags) > 0 { imageName := ImageNameWithoutVersion(image.RepoTags[0]) node = node.WithParents(report.EmptySets. Add(report.ContainerImage, report.MakeStringSet(report.MakeContainerImageNodeID(imageName))), ) } topology.AddNode(node) } }
func (c *container) GetNode(hostID string, localAddrs []net.IP) report.Node { c.RLock() defer c.RUnlock() ips := append(c.container.NetworkSettings.SecondaryIPAddresses, c.container.NetworkSettings.IPAddress) // Treat all Docker IPs as local scoped. ipsWithScopes := []string{} for _, ip := range ips { ipsWithScopes = append(ipsWithScopes, report.MakeScopedAddressNodeID(hostID, ip)) } state := c.State() result := report.MakeNodeWith(map[string]string{ ContainerID: c.ID(), ContainerName: strings.TrimPrefix(c.container.Name, "/"), ContainerCreated: c.container.Created.Format(time.RFC822), ContainerCommand: c.container.Path + " " + strings.Join(c.container.Args, " "), ImageID: c.container.Image, ContainerHostname: c.Hostname(), ContainerState: state, }).WithSets(report.EmptySets. Add(ContainerPorts, c.ports(localAddrs)). Add(ContainerIPs, report.MakeStringSet(ips...)). Add(ContainerIPsWithScopes, report.MakeStringSet(ipsWithScopes...)), ).WithMetrics( c.metrics(), ).WithParents(report.EmptySets. Add(report.ContainerImage, report.MakeStringSet(report.MakeContainerImageNodeID(c.container.Image))), ) if c.container.State.Paused { result = result.WithControls(UnpauseContainer) } else if c.container.State.Running { uptime := (mtime.Now().Sub(c.container.State.StartedAt) / time.Second) * time.Second result = result.WithLatests(map[string]string{ ContainerUptime: uptime.String(), ContainerRestartCount: strconv.Itoa(c.container.RestartCount), }) result = result.WithControls( RestartContainer, StopContainer, PauseContainer, AttachContainer, ExecContainer, ) } else { result = result.WithControls(StartContainer) } result = AddLabels(result, c.container.Config.Labels) result = result.WithMetrics(c.metrics()) return result }
func TestMakeStringSet(t *testing.T) { for _, testcase := range []struct { input []string want report.StringSet }{ {input: []string{}, want: report.MakeStringSet()}, {input: []string{"a"}, want: report.MakeStringSet("a")}, {input: []string{"a", "a"}, want: report.MakeStringSet("a")}, {input: []string{"b", "c", "a"}, want: report.MakeStringSet("a", "b", "c")}, } { if want, have := testcase.want, report.MakeStringSet(testcase.input...); !reflect.DeepEqual(want, have) { t.Errorf("%v: want %v, have %v", testcase.input, want, have) } } }
// Tag implements Tagger. func (w *Weave) Tag(r report.Report) (report.Report, error) { w.mtx.RLock() defer w.mtx.RUnlock() // Put information from weaveDNS on the container nodes for _, entry := range w.statusCache.DNS.Entries { if entry.Tombstone > 0 { continue } nodeID := report.MakeContainerNodeID(entry.ContainerID) node, ok := r.Container.Nodes[nodeID] if !ok { continue } w, _ := node.Latest.Lookup(WeaveDNSHostname) hostnames := report.IDList(strings.Fields(w)) hostnames = hostnames.Add(strings.TrimSuffix(entry.Hostname, ".")) r.Container.Nodes[nodeID] = node.WithLatests(map[string]string{WeaveDNSHostname: strings.Join(hostnames, " ")}) } // Put information from weave ps on the container nodes const maxPrefixSize = 12 for id, node := range r.Container.Nodes { prefix, ok := node.Latest.Lookup(docker.ContainerID) if !ok { continue } if len(prefix) > maxPrefixSize { prefix = prefix[:maxPrefixSize] } entry, ok := w.psCache[prefix] if !ok { continue } ipsWithScope := report.MakeStringSet() for _, ip := range entry.IPs { ipsWithScope = ipsWithScope.Add(report.MakeAddressNodeID("", ip)) } node = node.WithSet(docker.ContainerIPs, report.MakeStringSet(entry.IPs...)) node = node.WithSet(docker.ContainerIPsWithScopes, ipsWithScope) node = node.WithLatests(map[string]string{ WeaveMACAddress: entry.MACAddress, }) r.Container.Nodes[id] = node } return r, nil }
// Render produces a container graph where the the latest metadata contains the // container image name, if found. func (r containerWithImageNameRenderer) Render(rpt report.Report, dct Decorator) report.Nodes { containers := r.Renderer.Render(rpt, dct) images := SelectContainerImage.Render(rpt, dct) outputs := report.Nodes{} for id, c := range containers { outputs[id] = c imageID, ok := c.Latest.Lookup(docker.ImageID) if !ok { continue } image, ok := images[report.MakeContainerImageNodeID(imageID)] if !ok { continue } imageName, ok := image.Latest.Lookup(docker.ImageName) if !ok { continue } imageNameWithoutVersion := docker.ImageNameWithoutVersion(imageName) imageNodeID := report.MakeContainerImageNodeID(imageNameWithoutVersion) output := c.Copy() output = propagateLatest(docker.ImageName, image, output) output = propagateLatest(docker.ImageLabelPrefix+"works.weave.role", image, output) output.Parents = output.Parents. Delete(report.ContainerImage). Add(report.ContainerImage, report.MakeStringSet(imageNodeID)) outputs[id] = output } return outputs }
func (r *Reporter) podTopology(services []Service) (report.Topology, report.Topology, error) { pods, containers := report.MakeTopology(), report.MakeTopology() selectors := map[string]labels.Selector{} for _, service := range services { selectors[service.ID()] = service.Selector() } err := r.client.WalkPods(func(p Pod) error { for serviceID, selector := range selectors { if selector.Matches(p.Labels()) { p.AddServiceID(serviceID) } } nodeID := report.MakePodNodeID(p.Namespace(), p.Name()) pods = pods.AddNode(nodeID, p.GetNode()) container := report.MakeNodeWith(map[string]string{ PodID: p.ID(), Namespace: p.Namespace(), }).WithParents(report.EmptySets.Add(report.Pod, report.MakeStringSet(nodeID))) for _, containerID := range p.ContainerIDs() { containers.AddNode(report.MakeContainerNodeID(containerID), container) } return nil }) return pods, containers, err }
// Report implements Reporter. func (w *Weave) Report() (report.Report, error) { w.mtx.RLock() defer w.mtx.RUnlock() r := report.MakeReport() r.Container = r.Container.WithMetadataTemplates(report.MetadataTemplates{ WeaveMACAddress: {ID: WeaveMACAddress, Label: "Weave MAC", From: report.FromLatest, Priority: 17}, WeaveDNSHostname: {ID: WeaveDNSHostname, Label: "Weave DNS Name", From: report.FromLatest, Priority: 18}, }) for _, peer := range w.statusCache.Router.Peers { r.Overlay.AddNode(report.MakeNodeWith(report.MakeOverlayNodeID(peer.Name), map[string]string{ WeavePeerName: peer.Name, WeavePeerNickName: peer.NickName, })) } if w.statusCache.IPAM.DefaultSubnet != "" { r.Overlay.AddNode( report.MakeNode(report.MakeOverlayNodeID(w.statusCache.Router.Name)).WithSets( report.MakeSets().Add(host.LocalNetworks, report.MakeStringSet(w.statusCache.IPAM.DefaultSubnet)), ), ) } return r, 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.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 }
func (r *Reporter) addConnection(rpt *report.Report, t fourTuple, extraFromNode, extraToNode map[string]string) { var ( fromEndpointNodeID = report.MakeEndpointNodeID(r.hostID, t.fromAddr, strconv.Itoa(int(t.fromPort))) toEndpointNodeID = report.MakeEndpointNodeID(r.hostID, t.toAddr, strconv.Itoa(int(t.toPort))) fromNode = report.MakeNodeWith(fromEndpointNodeID, map[string]string{ Addr: t.fromAddr, Port: strconv.Itoa(int(t.fromPort)), }).WithEdge(toEndpointNodeID, report.EdgeMetadata{}) toNode = report.MakeNodeWith(toEndpointNodeID, map[string]string{ Addr: t.toAddr, Port: strconv.Itoa(int(t.toPort)), }) ) // In case we have a reverse resolution for the IP, we can use it for // the name... if toNames, err := r.reverseResolver.get(t.toAddr); err == nil { toNode = toNode.WithSet(ReverseDNSNames, report.MakeStringSet(toNames...)) } if extraFromNode != nil { fromNode = fromNode.WithLatests(extraFromNode) } if extraToNode != nil { toNode = toNode.WithLatests(extraToNode) } rpt.Endpoint = rpt.Endpoint.AddNode(fromNode) rpt.Endpoint = rpt.Endpoint.AddNode(toNode) }
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)) } }
// Tag implements Tagger. func (w *Weave) Tag(r report.Report) (report.Report, error) { w.mtx.RLock() defer w.mtx.RUnlock() // Put information from weaveDNS on the container nodes for _, entry := range w.status.DNS.Entries { if entry.Tombstone > 0 { continue } nodeID := report.MakeContainerNodeID(w.hostID, entry.ContainerID) node, ok := r.Container.Nodes[nodeID] if !ok { continue } hostnames := report.IDList(strings.Fields(node.Metadata[WeaveDNSHostname])) hostnames = hostnames.Add(strings.TrimSuffix(entry.Hostname, ".")) node.Metadata[WeaveDNSHostname] = strings.Join(hostnames, " ") } // Put information from weave ps on the container nodes psEntries, err := w.ps() if err != nil { return r, nil } psEntriesByPrefix := map[string]psEntry{} for _, entry := range psEntries { psEntriesByPrefix[entry.containerIDPrefix] = entry } for id, node := range r.Container.Nodes { prefix := node.Metadata[docker.ContainerID][:12] entry, ok := psEntriesByPrefix[prefix] if !ok { continue } ipsWithScope := report.MakeStringSet() for _, ip := range entry.ips { ipsWithScope = ipsWithScope.Add(report.MakeAddressNodeID("", ip)) } node = node.WithSet(docker.ContainerIPs, report.MakeStringSet(entry.ips...)) node = node.WithSet(docker.ContainerIPsWithScopes, ipsWithScope) node.Metadata[WeaveMACAddress] = entry.macAddress r.Container.Nodes[id] = node } return r, nil }
func (t *Tagger) tag(tree process.Tree, topology *report.Topology) { for nodeID, node := range topology.Nodes { pidStr, ok := node.Latest.Lookup(process.PID) if !ok { continue } pid, err := strconv.ParseUint(pidStr, 10, 64) if err != nil { continue } var ( c Container candidate = int(pid) ) t.registry.LockedPIDLookup(func(lookup func(int) Container) { for { c = lookup(candidate) if c != nil { break } candidate, err = tree.GetParent(candidate) if err != nil { break } } }) if c == nil || c.State() == StateStopped || c.PID() == 1 { continue } topology.AddNode(nodeID, report.MakeNodeWith(map[string]string{ ContainerID: c.ID(), }).WithParents(report.EmptySets. Add(report.Container, report.MakeStringSet(report.MakeContainerNodeID(c.ID()))). Add(report.ContainerImage, report.MakeStringSet(report.MakeContainerImageNodeID(c.Image()))), )) } }
func TestSetsMerge(t *testing.T) { for _, testcase := range []struct { a, b report.Sets want map[string][]string }{ {report.EmptySets, report.EmptySets, map[string][]string{}}, { report.EmptySets, report.EmptySets.Add("a", report.MakeStringSet("b")), map[string][]string{"a": {"b"}}, }, { report.EmptySets, report.EmptySets.Add("a", report.MakeStringSet("b", "c")), map[string][]string{"a": {"b", "c"}}, }, { report.EmptySets.Add("a", report.MakeStringSet("1")).Add("b", report.MakeStringSet("2")), report.EmptySets.Add("c", report.MakeStringSet("3")).Add("b", report.MakeStringSet("3")), map[string][]string{"a": {"1"}, "b": {"2", "3"}, "c": {"3"}}, }, } { haveSets := testcase.a.Merge(testcase.b) have := map[string][]string{} keys := haveSets.Keys() for _, k := range keys { have[k], _ = haveSets.Lookup(k) } if !reflect.DeepEqual(testcase.want, have) { t.Errorf("%+v.Merge(%+v): want %+v, have %+v", testcase.a, testcase.b, testcase.want, have) } } }
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 TestReporter(t *testing.T) { want := report.MakeReport() pod1ID := report.MakePodNodeID("ping", "pong-a") pod2ID := report.MakePodNodeID("ping", "pong-b") serviceID := report.MakeServiceNodeID("ping", "pongservice") want.Pod = report.MakeTopology().AddNode(pod1ID, report.MakeNodeWith(map[string]string{ kubernetes.PodID: "ping/pong-a", kubernetes.PodName: "pong-a", kubernetes.Namespace: "ping", kubernetes.PodCreated: pod1.Created(), kubernetes.PodContainerIDs: "container1 container2", kubernetes.ServiceIDs: "ping/pongservice", }).WithParents(report.Sets{ report.Service: report.MakeStringSet(serviceID), })).AddNode(pod2ID, report.MakeNodeWith(map[string]string{ kubernetes.PodID: "ping/pong-b", kubernetes.PodName: "pong-b", kubernetes.Namespace: "ping", kubernetes.PodCreated: pod1.Created(), kubernetes.PodContainerIDs: "container3 container4", kubernetes.ServiceIDs: "ping/pongservice", }).WithParents(report.Sets{ report.Service: report.MakeStringSet(serviceID), })) want.Service = report.MakeTopology().AddNode(serviceID, report.MakeNodeWith(map[string]string{ kubernetes.ServiceID: "ping/pongservice", kubernetes.ServiceName: "pongservice", kubernetes.Namespace: "ping", kubernetes.ServiceCreated: pod1.Created(), })) want.Container = report.MakeTopology().AddNode(report.MakeContainerNodeID("container1"), report.MakeNodeWith(map[string]string{ kubernetes.PodID: "ping/pong-a", kubernetes.Namespace: "ping", }).WithParents(report.Sets{ report.Pod: report.MakeStringSet(pod1ID), })).AddNode(report.MakeContainerNodeID("container2"), report.MakeNodeWith(map[string]string{ kubernetes.PodID: "ping/pong-a", kubernetes.Namespace: "ping", }).WithParents(report.Sets{ report.Pod: report.MakeStringSet(pod1ID), })).AddNode(report.MakeContainerNodeID("container3"), report.MakeNodeWith(map[string]string{ kubernetes.PodID: "ping/pong-b", kubernetes.Namespace: "ping", }).WithParents(report.Sets{ report.Pod: report.MakeStringSet(pod2ID), })).AddNode(report.MakeContainerNodeID("container4"), report.MakeNodeWith(map[string]string{ kubernetes.PodID: "ping/pong-b", kubernetes.Namespace: "ping", }).WithParents(report.Sets{ report.Pod: report.MakeStringSet(pod2ID), })) reporter := kubernetes.NewReporter(mockClientInstance) have, _ := reporter.Report() if !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } }
func (c *container) getBaseNode() report.Node { result := report.MakeNodeWith(report.MakeContainerNodeID(c.ID()), map[string]string{ ContainerID: c.ID(), ContainerCreated: c.container.Created.Format(time.RFC822), ContainerCommand: c.container.Path + " " + strings.Join(c.container.Args, " "), ImageID: c.Image(), ContainerHostname: c.Hostname(), }).WithParents(report.EmptySets. Add(report.ContainerImage, report.MakeStringSet(report.MakeContainerImageNodeID(c.Image()))), ) result = result.AddTable(LabelPrefix, c.container.Config.Labels) result = result.AddTable(EnvPrefix, c.env()) return result }
func (c *container) NetworkInfo(localAddrs []net.IP) report.Sets { c.RLock() defer c.RUnlock() ips := c.container.NetworkSettings.SecondaryIPAddresses if c.container.NetworkSettings.IPAddress != "" { ips = append(ips, c.container.NetworkSettings.IPAddress) } // For now, for the proof-of-concept, we just add networks as a set of // names. For the next iteration, we will probably want to create a new // Network topology, populate the network nodes with all of the details // here, and provide foreign key links from nodes to networks. networks := make([]string, 0, len(c.container.NetworkSettings.Networks)) for name, settings := range c.container.NetworkSettings.Networks { networks = append(networks, name) if settings.IPAddress != "" { ips = append(ips, settings.IPAddress) } } // Filter out IPv6 addresses; nothing works with IPv6 yet ipv4s := []string{} for _, ip := range ips { if isIPv4(ip) { ipv4s = append(ipv4s, ip) } } // Treat all Docker IPs as local scoped. ipsWithScopes := addScopeToIPs(c.hostID, ipv4s) return report.EmptySets. Add(ContainerNetworks, report.MakeStringSet(networks...)). Add(ContainerPorts, c.ports(localAddrs)). Add(ContainerIPs, report.MakeStringSet(ipv4s...)). Add(ContainerIPsWithScopes, report.MakeStringSet(ipsWithScopes...)) }
func TestTagger(t *testing.T) { oldProcessTree := docker.NewProcessTreeStub defer func() { docker.NewProcessTreeStub = oldProcessTree }() docker.NewProcessTreeStub = func(_ process.Walker) (process.Tree, error) { return &mockProcessTree{map[int]int{3: 2}}, nil } var ( pid1NodeID = report.MakeProcessNodeID("somehost.com", "2") pid2NodeID = report.MakeProcessNodeID("somehost.com", "3") wantNode = report.MakeNodeWith(map[string]string{ docker.ContainerID: "ping", }).WithParents(report.Sets{ report.Container: report.MakeStringSet(report.MakeContainerNodeID("ping")), report.ContainerImage: report.MakeStringSet(report.MakeContainerImageNodeID("baz")), }) ) input := report.MakeReport() input.Process.AddNode(pid1NodeID, report.MakeNodeWith(map[string]string{process.PID: "2"})) input.Process.AddNode(pid2NodeID, report.MakeNodeWith(map[string]string{process.PID: "3"})) want := report.MakeReport() want.Process.AddNode(pid1NodeID, report.MakeNodeWith(map[string]string{process.PID: "2"}).Merge(wantNode)) want.Process.AddNode(pid2NodeID, report.MakeNodeWith(map[string]string{process.PID: "3"}).Merge(wantNode)) tagger := docker.NewTagger(mockRegistryInstance, nil) have, err := tagger.Tag(input) if err != nil { t.Errorf("%v", err) } if !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } }
// Tag implements Tagger. func (t Tagger) Tag(r report.Report) (report.Report, error) { var ( metadata = map[string]string{report.HostNodeID: t.hostNodeID} parents = report.EmptySets.Add(report.Host, report.MakeStringSet(t.hostNodeID)) ) // Explicitly don't tag Endpoints and Addresses - These topologies include pseudo nodes, // and as such do their own host tagging for _, topology := range []report.Topology{r.Process, r.Container, r.ContainerImage, r.Host, r.Overlay, r.Pod} { for _, node := range topology.Nodes { topology.AddNode(node.WithLatests(metadata).WithParents(parents)) } } return r, nil }
func TestStringSetContains(t *testing.T) { for _, testcase := range []struct { contents []string target string want bool }{ {nil, "foo", false}, {[]string{}, "foo", false}, {[]string{"a"}, "foo", false}, {[]string{"a", "foo"}, "foo", true}, {[]string{"foo", "b"}, "foo", true}, } { have := report.MakeStringSet(testcase.contents...).Contains(testcase.target) if testcase.want != have { t.Errorf("%+v.Contains(%q): want %v, have %v", testcase.contents, testcase.target, testcase.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 TestReportLocalNetworks(t *testing.T) { r := report.MakeReport().Merge(report.Report{ Host: report.Topology{ Nodes: report.Nodes{ "nonets": report.MakeNode(), "foo": report.MakeNode().WithSets(report.Sets{ host.LocalNetworks: report.MakeStringSet( "10.0.0.1/8", "192.168.1.1/24", "10.0.0.1/8", "badnet/33"), }), }, }, }) want := report.Networks([]*net.IPNet{ mustParseCIDR("10.0.0.1/8"), mustParseCIDR("192.168.1.1/24"), }) have := render.LocalNetworks(r) if !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } }
func TestNodeMetadata(t *testing.T) { inputs := []struct { name string node report.Node want []detailed.MetadataRow }{ { name: "container", node: report.MakeNodeWith(map[string]string{ docker.ContainerID: fixture.ClientContainerID, docker.LabelPrefix + "label1": "label1value", }).WithTopology(report.Container).WithSets(report.Sets{ docker.ContainerIPs: report.MakeStringSet("10.10.10.0/24", "10.10.10.1/24"), }).WithLatest(docker.ContainerState, fixture.Now, docker.StateRunning), want: []detailed.MetadataRow{ {ID: docker.ContainerID, Label: "ID", Value: fixture.ClientContainerID}, {ID: docker.ContainerState, Label: "State", Value: "running"}, {ID: docker.ContainerIPs, Label: "IPs", Value: "10.10.10.0/24, 10.10.10.1/24"}, { ID: "label_label1", Label: "Label \"label1\"", Value: "label1value", }, }, }, { name: "unknown topology", node: report.MakeNodeWith(map[string]string{ docker.ContainerID: fixture.ClientContainerID, }).WithTopology("foobar").WithID(fixture.ClientContainerNodeID), want: nil, }, } for _, input := range inputs { have := detailed.NodeMetadata(input.node) if !reflect.DeepEqual(input.want, have) { t.Errorf("%s: %s", input.name, test.Diff(input.want, have)) } } }
func (p *pod) GetNode() report.Node { n := report.MakeNodeWith(map[string]string{ PodID: p.ID(), PodName: p.Name(), Namespace: p.Namespace(), PodCreated: p.Created(), PodContainerIDs: strings.Join(p.ContainerIDs(), " "), }) if len(p.serviceIDs) > 0 { n.Metadata[ServiceIDs] = strings.Join(p.serviceIDs, " ") } for _, serviceID := range p.serviceIDs { segments := strings.SplitN(serviceID, "/", 2) if len(segments) != 2 { continue } n = n.WithParents(report.Sets{ report.Service: report.MakeStringSet(report.MakeServiceNodeID(p.Namespace(), segments[1])), }) } return n }
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 TestNodeMetadata(t *testing.T) { inputs := []struct { name string node report.Node want []report.MetadataRow }{ { name: "container", node: report.MakeNodeWith(fixture.ClientContainerNodeID, map[string]string{ docker.ContainerID: fixture.ClientContainerID, docker.LabelPrefix + "label1": "label1value", docker.ContainerStateHuman: docker.StateRunning, }).WithTopology(report.Container).WithSets(report.EmptySets. Add(docker.ContainerIPs, report.MakeStringSet("10.10.10.0/24", "10.10.10.1/24")), ), want: []report.MetadataRow{ {ID: docker.ContainerID, Label: "ID", Value: fixture.ClientContainerID, Priority: 1}, {ID: docker.ContainerStateHuman, Label: "State", Value: "running", Priority: 2}, {ID: docker.ContainerIPs, Label: "IPs", Value: "10.10.10.0/24, 10.10.10.1/24", Priority: 15}, }, }, { name: "unknown topology", node: report.MakeNodeWith(fixture.ClientContainerNodeID, map[string]string{ docker.ContainerID: fixture.ClientContainerID, }).WithTopology("foobar"), want: nil, }, } for _, input := range inputs { have := detailed.NodeMetadata(fixture.Report, input.node) if !reflect.DeepEqual(input.want, have) { t.Errorf("%s: %s", input.name, test.Diff(input.want, have)) } } }
serverEndpointNodeID: report.MakeNode().WithLatests(map[string]string{ endpoint.Addr: serverIP, endpoint.Port: serverPort, endpoint.Conntracked: "true", }).WithID(serverEndpointNodeID).WithTopology(report.Endpoint), }, }, Container: report.Topology{ Nodes: report.Nodes{ containerNodeID: report.MakeNode().WithLatests(map[string]string{ docker.ContainerID: containerID, docker.ContainerName: containerName, report.HostNodeID: serverHostNodeID, }).WithSets(report.EmptySets. Add(docker.ContainerIPs, report.MakeStringSet(containerIP)). Add(docker.ContainerPorts, report.MakeStringSet(fmt.Sprintf("%s:%s->%s/tcp", serverIP, serverPort, serverPort))), ).WithID(containerNodeID).WithTopology(report.Container), }, }, Host: report.Topology{ Nodes: report.Nodes{ serverHostNodeID: report.MakeNodeWith(map[string]string{ report.HostNodeID: serverHostNodeID, }).WithSets(report.EmptySets. Add(host.LocalNetworks, report.MakeStringSet("192.168.0.0/16")), ).WithID(serverHostNodeID).WithTopology(report.Host), }, }, }