diff --git a/.gitignore b/.gitignore index 09088897b6..830caffec7 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/Makefile b/Makefile index d561456181..5833c1efa6 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/docker/Dockerfile b/docker/Dockerfile index 974f012d9d..d2c98b0e27 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,8 +2,10 @@ FROM gliderlabs/alpine MAINTAINER Weaveworks Inc 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 diff --git a/probe/docker/container.go b/probe/docker/container.go index ad005fac9c..d09a3a5c5b 100644 --- a/probe/docker/container.go +++ b/probe/docker/container.go @@ -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" @@ -212,6 +213,7 @@ 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: c.container.NetworkSettings.IPAddress, }) if c.latestStats == nil { diff --git a/probe/docker/registry_test.go b/probe/docker/registry_test.go index cffc4f4c33..2408394262 100644 --- a/probe/docker/registry_test.go +++ b/probe/docker/registry_test.go @@ -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", diff --git a/probe/overlay/weave.go b/probe/overlay/weave.go index 64288ea96a..288b4516dc 100644 --- a/probe/overlay/weave.go +++ b/probe/overlay/weave.go @@ -1,13 +1,18 @@ package overlay import ( + "bufio" "encoding/json" "fmt" + "log" "net" "net/http" "net/url" + "os/exec" + "regexp" "strings" + "github.com/weaveworks/scope/probe/docker" "github.com/weaveworks/scope/report" ) @@ -21,8 +26,15 @@ 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]+)`) + // 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 @@ -83,6 +95,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 := exec.Command("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(strings.Fields(nmd.Metadata[docker.ContainerIPs])...) + 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() @@ -105,6 +170,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 } diff --git a/render/detailed_node.go b/render/detailed_node.go index 11bca87fed..f1e0297884 100644 --- a/render/detailed_node.go +++ b/render/detailed_node.go @@ -297,11 +297,13 @@ 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"}, + {docker.ContainerIPs, "IP Addresses"}, + {overlay.WeaveMACAddress, "Weave MAC"}, + {overlay.WeaveDNSHostname, "Weave DNS Hostname"}, } { if val, ok := nmd.Metadata[tuple.key]; ok { rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})