Skip to content

Commit

Permalink
Merge pull request #396 from weaveworks/weave-docker-ips
Browse files Browse the repository at this point in the history
Tag containers with Weave and Docker IPs
  • Loading branch information
tomwilkie committed Aug 26, 2015
2 parents 64d9a1b + 1ad1197 commit d9ab9d8
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ probe/probe
probe/scope-probe
docker/scope-app
docker/scope-probe
docker/docker*
docker/weave
experimental/bridge/bridge
experimental/demoprobe/demoprobe
experimental/fixprobe/fixprobe
Expand Down
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,23 @@ SCOPE_EXPORT=scope.tar
SCOPE_UI_BUILD_EXPORT=scope_ui_build.tar
SCOPE_UI_BUILD_IMAGE=$(DOCKERHUB_USER)/scope-ui-build
SCOPE_VERSION=$(shell git rev-parse --short HEAD)
DOCKER_VERSION=1.3.1
DOCKER_DISTRIB=docker/docker-$(DOCKER_VERSION).tgz
DOCKER_DISTRIB_URL=https://get.docker.com/builds/Linux/x86_64/docker-$(DOCKER_VERSION).tgz

all: $(SCOPE_EXPORT)

$(SCOPE_EXPORT): $(APP_EXE) $(PROBE_EXE) docker/*
$(DOCKER_DISTRIB):
curl -o $(DOCKER_DISTRIB) $(DOCKER_DISTRIB_URL)

docker/weave:
curl -L git.io/weave -o docker/weave
chmod u+x docker/weave

$(SCOPE_EXPORT): $(APP_EXE) $(PROBE_EXE) $(DOCKER_DISTRIB) docker/weave docker/entrypoint.sh docker/Dockerfile docker/run-app docker/run-probe
@if [ -z '$(DOCKER_SQUASH)' ]; then echo "Please install docker-squash by running 'make deps'." && exit 1; fi
cp $(APP_EXE) $(PROBE_EXE) docker/
cp $(DOCKER_DISTRIB) docker/docker.tgz
$(SUDO) docker build -t $(SCOPE_IMAGE) docker/
$(SUDO) docker save $(SCOPE_IMAGE):latest | sudo $(DOCKER_SQUASH) -t $(SCOPE_IMAGE) | tee $@ | $(SUDO) docker load

Expand Down
4 changes: 3 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ FROM gliderlabs/alpine
MAINTAINER Weaveworks Inc <[email protected]>
WORKDIR /home/weave
RUN echo "http://dl-4.alpinelinux.org/alpine/edge/testing" >>/etc/apk/repositories && \
apk add --update runit conntrack-tools && \
apk add --update runit conntrack-tools iproute2 util-linux && \
rm -rf /var/cache/apk/*
ADD ./docker.tgz /
ADD ./weave /usr/bin/
COPY ./scope-app ./scope-probe ./entrypoint.sh /home/weave/
COPY ./run-app /etc/service/app/run
COPY ./run-probe /etc/service/probe/run
Expand Down
8 changes: 8 additions & 0 deletions probe/docker/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
ContainerCommand = "docker_container_command"
ContainerPorts = "docker_container_ports"
ContainerCreated = "docker_container_created"
ContainerIPs = "docker_container_ips"

NetworkRxDropped = "network_rx_dropped"
NetworkRxBytes = "network_rx_bytes"
Expand Down Expand Up @@ -212,6 +213,8 @@ func (c *container) GetNodeMetadata() report.NodeMetadata {
ContainerCreated: c.container.Created.Format(time.RFC822),
ContainerCommand: c.container.Path + " " + strings.Join(c.container.Args, " "),
ImageID: c.container.Image,
ContainerIPs: strings.Join(append(c.container.NetworkSettings.SecondaryIPAddresses,
c.container.NetworkSettings.IPAddress), " "),
})

if c.latestStats == nil {
Expand Down Expand Up @@ -241,3 +244,8 @@ func (c *container) GetNodeMetadata() report.NodeMetadata {
}))
return result
}

// ExtractContainerIPs returns the list of container IPs given a NodeMetadata from the Container topology.
func ExtractContainerIPs(nmd report.NodeMetadata) []string {
return strings.Fields(nmd.Metadata[ContainerIPs])
}
3 changes: 3 additions & 0 deletions probe/docker/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ var (
Name: "pong",
Image: "baz",
State: client.State{Pid: 1, Running: true},
NetworkSettings: &client.NetworkSettings{
IPAddress: "1.2.3.4",
},
}
container2 = &client.Container{
ID: "wiff",
Expand Down
83 changes: 83 additions & 0 deletions probe/overlay/weave.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package overlay

import (
"bufio"
"encoding/json"
"fmt"
"io"
"log"
"net"
"net/http"
"net/url"
"os/exec"
"regexp"
"strings"

"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/report"
)

Expand All @@ -21,8 +27,25 @@ const (

// WeaveDNSHostname is the ket for the WeaveDNS hostname
WeaveDNSHostname = "weave_dns_hostname"

// WeaveMACAddress is the key for the mac address of the container on the
// weave network, to be found in container node metadata
WeaveMACAddress = "weave_mac_address"
)

var weavePsMatch = regexp.MustCompile(`^([0-9a-f]{12}) ((?:[0-9a-f][0-9a-f]\:){5}(?:[0-9a-f][0-9a-f]))(.*)$`)
var ipMatch = regexp.MustCompile(`([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(/[0-9]+)`)

// Cmd is a hook for mocking
type Cmd interface {
StdoutPipe() (io.ReadCloser, error)
Start() error
Wait() error
}

// ExecCommand is a hook for mocking
var ExecCommand = func(name string, args ...string) Cmd { return exec.Command(name, args...) }

// Weave represents a single Weave router, presumably on the same host
// as the probe. It is both a Reporter and a Tagger: it produces an Overlay
// topology, and (in theory) can tag existing topologies with foreign keys to
Expand Down Expand Up @@ -83,6 +106,59 @@ func (w Weave) update() (weaveStatus, error) {
return result, json.NewDecoder(resp.Body).Decode(&result)
}

type psEntry struct {
containerIDPrefix string
macAddress string
ips []string
}

func (w Weave) ps() ([]psEntry, error) {
var result []psEntry
cmd := ExecCommand("weave", "--local", "ps")
out, err := cmd.StdoutPipe()
if err != nil {
return result, err
}
if err := cmd.Start(); err != nil {
return result, err
}
defer func() {
if err := cmd.Wait(); err != nil {
log.Printf("Weave tagger, cmd failed: %v", err)
}
}()
scanner := bufio.NewScanner(out)
for scanner.Scan() {
line := scanner.Text()
groups := weavePsMatch.FindStringSubmatch(line)
if len(groups) == 0 {
continue
}
containerIDPrefix, macAddress, ips := groups[1], groups[2], []string{}
for _, ipGroup := range ipMatch.FindAllStringSubmatch(groups[3], -1) {
ips = append(ips, ipGroup[1])
}
result = append(result, psEntry{containerIDPrefix, macAddress, ips})
}
return result, scanner.Err()
}

func (w Weave) tagContainer(r report.Report, containerIDPrefix, macAddress string, ips []string) {
for nodeid, nmd := range r.Container.NodeMetadatas {
idPrefix := nmd.Metadata[docker.ContainerID][:12]
if idPrefix != containerIDPrefix {
continue
}

existingIPs := report.MakeIDList(docker.ExtractContainerIPs(nmd)...)
existingIPs = existingIPs.Add(ips...)
nmd.Metadata[docker.ContainerIPs] = strings.Join(existingIPs, " ")
nmd.Metadata[WeaveMACAddress] = macAddress
r.Container.NodeMetadatas[nodeid] = nmd
break
}
}

// Tag implements Tagger.
func (w Weave) Tag(r report.Report) (report.Report, error) {
status, err := w.update()
Expand All @@ -105,6 +181,13 @@ func (w Weave) Tag(r report.Report) (report.Report, error) {
r.Container.NodeMetadatas[nodeID] = node
}

psEntries, err := w.ps()
if err != nil {
return r, nil
}
for _, e := range psEntries {
w.tagContainer(r, e.containerIDPrefix, e.macAddress, e.ips)
}
return r, nil
}

Expand Down
45 changes: 43 additions & 2 deletions probe/overlay/weave_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,52 @@
package overlay_test

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"reflect"
"testing"

"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/overlay"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
)

type mockCmd struct {
*bytes.Buffer
}

func (c *mockCmd) Start() error {
return nil
}

func (c *mockCmd) Wait() error {
return nil
}

func (c *mockCmd) StdoutPipe() (io.ReadCloser, error) {
return struct {
io.Reader
io.Closer
}{
c.Buffer,
ioutil.NopCloser(nil),
}, nil
}

func TestWeaveTaggerOverlayTopology(t *testing.T) {
oldExecCmd := overlay.ExecCommand
defer func() { overlay.ExecCommand = oldExecCmd }()
overlay.ExecCommand = func(name string, args ...string) overlay.Cmd {
return &mockCmd{
bytes.NewBufferString(fmt.Sprintf("%s %s %s/24\n", mockContainerID, mockContainerMAC, mockContainerIP)),
}
}

s := httptest.NewServer(http.HandlerFunc(mockWeaveRouter))
defer s.Close()

Expand Down Expand Up @@ -46,15 +80,20 @@ func TestWeaveTaggerOverlayTopology(t *testing.T) {
Container: report.Topology{
NodeMetadatas: report.NodeMetadatas{
nodeID: report.MakeNodeMetadataWith(map[string]string{
docker.ContainerID: mockContainerID,
overlay.WeaveDNSHostname: mockHostname,
overlay.WeaveMACAddress: mockContainerMAC,
docker.ContainerIPs: mockContainerIP,
}),
},
},
}
have, err := w.Tag(report.Report{
Container: report.Topology{
NodeMetadatas: report.NodeMetadatas{
nodeID: report.MakeNodeMetadata(),
nodeID: report.MakeNodeMetadataWith(map[string]string{
docker.ContainerID: mockContainerID,
}),
},
},
})
Expand All @@ -71,7 +110,9 @@ const (
mockHostID = "host1"
mockWeavePeerName = "winnebago"
mockWeavePeerNickName = "winny"
mockContainerID = "a1b2c3d4e5"
mockContainerID = "83183a667c01"
mockContainerMAC = "d6:f2:5a:12:36:a8"
mockContainerIP = "10.0.0.123"
mockHostname = "hostname.weave.local"
)

Expand Down
9 changes: 7 additions & 2 deletions render/detailed_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,17 +297,22 @@ 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"},
{docker.ContainerCommand, "Command"},
{overlay.WeaveMACAddress, "Weave MAC"},
{overlay.WeaveDNSHostname, "Weave DNS Hostname"},
} {
if val, ok := nmd.Metadata[tuple.key]; ok {
if val, ok := nmd.Metadata[tuple.key]; ok && val != "" {
rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
}
}

for _, ip := range docker.ExtractContainerIPs(nmd) {
rows = append(rows, Row{Key: "IP Address", ValueMajor: ip, ValueMinor: ""})
}

if val, ok := nmd.Metadata[docker.MemoryUsage]; ok {
memory, err := strconv.ParseFloat(val, 64)
if err == nil {
Expand Down

0 comments on commit d9ab9d8

Please sign in to comment.