diff --git a/probe/docker/container.go b/probe/docker/container.go index 8f78d34bb..af721b8cd 100644 --- a/probe/docker/container.go +++ b/probe/docker/container.go @@ -195,9 +195,9 @@ func (c *container) StopGatheringStats() { return } -func (c *container) ports(localAddrs []net.IP) string { +func (c *container) ports(localAddrs []net.IP) report.StringSet { if c.container.NetworkSettings == nil { - return "" + return report.MakeStringSet() } ports := []string{} @@ -217,7 +217,7 @@ func (c *container) ports(localAddrs []net.IP) string { } } - return strings.Join(ports, ", ") + return report.MakeStringSet(ports...) } func (c *container) GetNode(hostID string, localAddrs []net.IP) report.Node { @@ -232,15 +232,16 @@ func (c *container) GetNode(hostID string, localAddrs []net.IP) report.Node { } result := report.MakeNodeWith(map[string]string{ - ContainerID: c.ID(), - ContainerName: strings.TrimPrefix(c.container.Name, "/"), + 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(), + }).WithSets(report.Sets{ ContainerPorts: c.ports(localAddrs), - ContainerCreated: c.container.Created.Format(time.RFC822), - ContainerCommand: c.container.Path + " " + strings.Join(c.container.Args, " "), - ImageID: c.container.Image, - ContainerIPs: strings.Join(ips, " "), - ContainerIPsWithScopes: strings.Join(ipsWithScopes, " "), - ContainerHostname: c.Hostname(), + ContainerIPs: report.MakeStringSet(ips...), + ContainerIPsWithScopes: report.MakeStringSet(ipsWithScopes...), }) AddLabels(result, c.container.Config.Labels) @@ -274,11 +275,11 @@ func (c *container) GetNode(hostID string, localAddrs []net.IP) report.Node { // ExtractContainerIPs returns the list of container IPs given a Node from the Container topology. func ExtractContainerIPs(nmd report.Node) []string { - return strings.Fields(nmd.Metadata[ContainerIPs]) + return []string(nmd.Sets[ContainerIPs]) } // ExtractContainerIPsWithScopes returns the list of container IPs, prepended // with scopes, given a Node from the Container topology. func ExtractContainerIPsWithScopes(nmd report.Node) []string { - return strings.Fields(nmd.Metadata[ContainerIPsWithScopes]) + return []string(nmd.Sets[ContainerIPsWithScopes]) } diff --git a/probe/docker/container_linux_test.go b/probe/docker/container_linux_test.go index 39f11b994..5e4e76da8 100644 --- a/probe/docker/container_linux_test.go +++ b/probe/docker/container_linux_test.go @@ -69,14 +69,15 @@ func TestContainer(t *testing.T) { "docker_container_command": " ", "docker_container_created": "01 Jan 01 00:00 UTC", "docker_container_id": "ping", - "docker_container_ips": "1.2.3.4", - "docker_container_ips_with_scopes": "scope;1.2.3.4", "docker_container_name": "pong", - "docker_container_ports": "1.2.3.4:80->80/tcp, 81/tcp", "docker_image_id": "baz", "docker_label_foo1": "bar1", "docker_label_foo2": "bar2", "memory_usage": "12345", + }).WithSets(report.Sets{ + "docker_container_ports": report.MakeStringSet("1.2.3.4:80->80/tcp", "81/tcp"), + "docker_container_ips": report.MakeStringSet("1.2.3.4"), + "docker_container_ips_with_scopes": report.MakeStringSet("scope;1.2.3.4"), }) test.Poll(t, 100*time.Millisecond, want, func() interface{} { node := c.GetNode("scope", []net.IP{}) diff --git a/probe/overlay/weave.go b/probe/overlay/weave.go index 6c4c87ae4..05ff51b92 100644 --- a/probe/overlay/weave.go +++ b/probe/overlay/weave.go @@ -164,28 +164,25 @@ func (w *Weave) Tag(r report.Report) (report.Report, error) { if err != nil { return r, nil } - containersByPrefix := map[string]report.Node{} - for _, node := range r.Container.Nodes { - prefix := node.Metadata[docker.ContainerID][:12] - containersByPrefix[prefix] = node + psEntriesByPrefix := map[string]psEntry{} + for _, entry := range psEntries { + psEntriesByPrefix[entry.containerIDPrefix] = entry } - for _, e := range psEntries { - node, ok := containersByPrefix[e.containerIDPrefix] + for id, node := range r.Container.Nodes { + prefix := node.Metadata[docker.ContainerID][:12] + entry, ok := psEntriesByPrefix[prefix] if !ok { continue } - existingIPs := report.MakeIDList(docker.ExtractContainerIPs(node)...) - existingIPs = existingIPs.Add(e.ips...) - node.Metadata[docker.ContainerIPs] = strings.Join(existingIPs, " ") - - existingIPsWithScopes := report.MakeIDList(docker.ExtractContainerIPsWithScopes(node)...) - for _, ip := range e.ips { - existingIPsWithScopes = existingIPsWithScopes.Add(report.MakeAddressNodeID("", ip)) + ipsWithScope := report.MakeStringSet() + for _, ip := range entry.ips { + ipsWithScope = ipsWithScope.Add(report.MakeAddressNodeID("", ip)) } - node.Metadata[docker.ContainerIPsWithScopes] = strings.Join(existingIPsWithScopes, " ") - - node.Metadata[WeaveMACAddress] = e.macAddress + 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 } diff --git a/probe/overlay/weave_test.go b/probe/overlay/weave_test.go index 3950653d8..02914d48d 100644 --- a/probe/overlay/weave_test.go +++ b/probe/overlay/weave_test.go @@ -54,8 +54,9 @@ func TestWeaveTaggerOverlayTopology(t *testing.T) { docker.ContainerID: mockContainerID, overlay.WeaveDNSHostname: mockHostname, overlay.WeaveMACAddress: mockContainerMAC, - docker.ContainerIPs: mockContainerIP, - docker.ContainerIPsWithScopes: mockContainerIPWithScope, + }).WithSets(report.Sets{ + docker.ContainerIPs: report.MakeStringSet(mockContainerIP), + docker.ContainerIPsWithScopes: report.MakeStringSet(mockContainerIPWithScope), }), }, }, diff --git a/render/mapping.go b/render/mapping.go index 3fead832d..b381a3ca9 100644 --- a/render/mapping.go +++ b/render/mapping.go @@ -311,8 +311,8 @@ var portMappingMatch = regexp.MustCompile(`([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\. // the endpoint topology. func MapContainer2IP(m RenderableNode, _ report.Networks) RenderableNodes { result := RenderableNodes{} - if addrs, ok := m.Metadata[docker.ContainerIPsWithScopes]; ok { - for _, addr := range strings.Fields(addrs) { + if addrs, ok := m.Sets[docker.ContainerIPsWithScopes]; ok { + for _, addr := range addrs { scope, addr, ok := report.ParseAddressNodeID(addr) if !ok { continue @@ -326,12 +326,14 @@ func MapContainer2IP(m RenderableNode, _ report.Networks) RenderableNodes { // Also output all the host:port port mappings (see above comment). // In this case we assume this doesn't need a scope, as they are for host IPs. - for _, mapping := range portMappingMatch.FindAllStringSubmatch(m.Metadata[docker.ContainerPorts], -1) { - ip, port := mapping[1], mapping[2] - id := report.MakeScopedEndpointNodeID("", ip, port) - node := NewRenderableNodeWith(id, "", "", "", m) - node.Counters[containersKey] = 1 - result[id] = node + for _, portMapping := range m.Sets[docker.ContainerPorts] { + if mapping := portMappingMatch.FindStringSubmatch(portMapping); mapping != nil { + ip, port := mapping[1], mapping[2] + id := report.MakeScopedEndpointNodeID("", ip, port) + node := NewRenderableNodeWith(id, "", "", "", m) + node.Counters[containersKey] = 1 + result[id] = node + } } return result diff --git a/render/renderable_node.go b/render/renderable_node.go index 591ede43d..7af08e81b 100644 --- a/render/renderable_node.go +++ b/render/renderable_node.go @@ -130,6 +130,7 @@ func (rn RenderableNode) Prune() RenderableNode { cp.Node.Metadata = report.Metadata{} // snip cp.Node.Counters = report.Counters{} // snip cp.Node.Edges = report.EdgeMetadatas{} // snip + cp.Node.Sets = report.Sets{} // snip return cp } diff --git a/render/short_lived_connections_test.go b/render/short_lived_connections_test.go index b5d6b1a93..7461a5bd5 100644 --- a/render/short_lived_connections_test.go +++ b/render/short_lived_connections_test.go @@ -50,9 +50,10 @@ var ( containerNodeID: report.MakeNode().WithMetadata(map[string]string{ docker.ContainerID: containerID, docker.ContainerName: containerName, - docker.ContainerIPs: containerIP, - docker.ContainerPorts: fmt.Sprintf("%s:%s->%s/tcp", serverIP, serverPort, serverPort), report.HostNodeID: serverHostNodeID, + }).WithSets(report.Sets{ + docker.ContainerIPs: report.MakeStringSet(containerIP), + docker.ContainerPorts: report.MakeStringSet(fmt.Sprintf("%s:%s->%s/tcp", serverIP, serverPort, serverPort)), }), }, }, diff --git a/report/topology.go b/report/topology.go index 679337267..7b5c5e0c7 100644 --- a/report/topology.go +++ b/report/topology.go @@ -124,6 +124,13 @@ func (n Node) WithSet(key string, set StringSet) Node { return result } +// WithSets returns a fresh copy of n, with sets merged in. +func (n Node) WithSets(sets Sets) Node { + result := n.Copy() + result.Sets = result.Sets.Merge(sets) + return result +} + // WithAdjacent returns a fresh copy of n, with 'a' added to Adjacency func (n Node) WithAdjacent(a string) Node { result := n.Copy() @@ -216,7 +223,7 @@ type Sets map[string]StringSet func (s Sets) Merge(other Sets) Sets { result := s.Copy() for k, v := range other { - result[k].Merge(v) + result[k] = result[k].Merge(v) } return result }