From e9fad6136fba9421dc03368ed906611c76acb471 Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Tue, 25 Aug 2015 10:23:18 +0000 Subject: [PATCH] Tag containers with WeaveDNS hostnames. --- probe/main.go | 2 +- probe/overlay/weave.go | 49 ++++++++++++++++++----- probe/overlay/weave_test.go | 78 +++++++++++++++++++++++++++---------- render/detailed_node.go | 2 + 4 files changed, 101 insertions(+), 30 deletions(-) diff --git a/probe/main.go b/probe/main.go index d636b386a..c9afcc940 100644 --- a/probe/main.go +++ b/probe/main.go @@ -127,7 +127,7 @@ func main() { } if *weaveRouterAddr != "" { - weave, err := overlay.NewWeave(*weaveRouterAddr) + weave, err := overlay.NewWeave(hostID, *weaveRouterAddr) if err != nil { log.Fatalf("failed to start Weave tagger: %v", err) } diff --git a/probe/overlay/weave.go b/probe/overlay/weave.go index 1c272cd11..64288ea96 100644 --- a/probe/overlay/weave.go +++ b/probe/overlay/weave.go @@ -18,6 +18,9 @@ const ( // WeavePeerNickName is the key for the peer nickname, typically a // hostname. WeavePeerNickName = "weave_peer_nick_name" + + // WeaveDNSHostname is the ket for the WeaveDNS hostname + WeaveDNSHostname = "weave_dns_hostname" ) // Weave represents a single Weave router, presumably on the same host @@ -26,27 +29,37 @@ const ( // overlay -- though I'm not sure what that would look like in practice right // now. type Weave struct { - url string + url string + hostID string } type weaveStatus struct { Router struct { Peers []struct { - Name string `json:"name"` - NickName string `json:"nickname"` - } `json:"peers"` - } `json:"router"` + Name string + NickName string + } + } + + DNS struct { + Entries []struct { + Hostname string + ContainerID string + Tombstone int64 + } + } } // NewWeave returns a new Weave tagger based on the Weave router at // address. The address should be an IP or FQDN, no port. -func NewWeave(weaveRouterAddress string) (*Weave, error) { +func NewWeave(hostID, weaveRouterAddress string) (*Weave, error) { s, err := sanitize("http://", 6784, "/report")(weaveRouterAddress) if err != nil { return nil, err } return &Weave{ - url: s, + url: s, + hostID: hostID, }, nil } @@ -72,8 +85,26 @@ func (w Weave) update() (weaveStatus, error) { // Tag implements Tagger. func (w Weave) Tag(r report.Report) (report.Report, error) { - // The status-json endpoint doesn't return any link information, so - // there's nothing to tag, yet. + status, err := w.update() + if err != nil { + return r, nil + } + + for _, entry := range status.DNS.Entries { + if entry.Tombstone > 0 { + continue + } + nodeID := report.MakeContainerNodeID(w.hostID, entry.ContainerID) + node, ok := r.Container.NodeMetadatas[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, " ") + r.Container.NodeMetadatas[nodeID] = node + } + return r, nil } diff --git a/probe/overlay/weave_test.go b/probe/overlay/weave_test.go index b056d6b3b..9f557c455 100644 --- a/probe/overlay/weave_test.go +++ b/probe/overlay/weave_test.go @@ -16,43 +16,81 @@ func TestWeaveTaggerOverlayTopology(t *testing.T) { s := httptest.NewServer(http.HandlerFunc(mockWeaveRouter)) defer s.Close() - w, err := overlay.NewWeave(s.URL) + w, err := overlay.NewWeave(mockHostID, s.URL) if err != nil { t.Fatal(err) } - have, err := w.Report() - if err != nil { - t.Fatal(err) + { + have, err := w.Report() + if err != nil { + t.Fatal(err) + } + if want, have := (report.Topology{ + Adjacency: report.Adjacency{}, + EdgeMetadatas: report.EdgeMetadatas{}, + NodeMetadatas: report.NodeMetadatas{ + report.MakeOverlayNodeID(mockWeavePeerName): report.MakeNodeMetadataWith(map[string]string{ + overlay.WeavePeerName: mockWeavePeerName, + overlay.WeavePeerNickName: mockWeavePeerNickName, + }), + }, + }), have.Overlay; !reflect.DeepEqual(want, have) { + t.Error(test.Diff(want, have)) + } } - if want, have := (report.Topology{ - Adjacency: report.Adjacency{}, - EdgeMetadatas: report.EdgeMetadatas{}, - NodeMetadatas: report.NodeMetadatas{ - report.MakeOverlayNodeID(mockWeavePeerName): report.MakeNodeMetadataWith(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.Topology{ + NodeMetadatas: report.NodeMetadatas{ + nodeID: report.MakeNodeMetadataWith(map[string]string{ + overlay.WeaveDNSHostname: mockHostname, + }), + }, + }, + } + have, err := w.Tag(report.Report{ + Container: report.Topology{ + NodeMetadatas: report.NodeMetadatas{ + nodeID: report.MakeNodeMetadata(), + }, + }, + }) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(want, have) { + t.Error(test.Diff(want, have)) + } } } const ( + mockHostID = "host1" mockWeavePeerName = "winnebago" mockWeavePeerNickName = "winny" + mockContainerID = "a1b2c3d4e5" + mockHostname = "hostname.weave.local" ) var ( mockResponse = fmt.Sprintf(`{ - "router": { - "peers": [{ - "name": "%s", - "nickname": "%s" + "Router": { + "Peers": [{ + "Name": "%s", + "Nickname": "%s" + }] + }, + "DNS": { + "Entries": [{ + "ContainerID": "%s", + "Hostname": "%s.", + "Tombstone": 0 }] } - }`, mockWeavePeerName, mockWeavePeerNickName) + }`, mockWeavePeerName, mockWeavePeerNickName, mockContainerID, mockHostname) ) func mockWeaveRouter(w http.ResponseWriter, r *http.Request) { diff --git a/render/detailed_node.go b/render/detailed_node.go index 66e42d135..11bca87fe 100644 --- a/render/detailed_node.go +++ b/render/detailed_node.go @@ -7,6 +7,7 @@ import ( "github.com/weaveworks/scope/probe/docker" "github.com/weaveworks/scope/probe/host" + "github.com/weaveworks/scope/probe/overlay" "github.com/weaveworks/scope/probe/process" "github.com/weaveworks/scope/report" ) @@ -296,6 +297,7 @@ func containerOriginTable(nmd report.NodeMetadata, addHostTag bool) (Table, bool rows := []Row{} for _, tuple := range []struct{ key, human string }{ {docker.ContainerID, "ID"}, + {overlay.WeaveDNSHostname, "Weave DNS Hostname"}, {docker.ImageID, "Image ID"}, {docker.ContainerPorts, "Ports"}, {docker.ContainerCreated, "Created"},