mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 01:31:17 +00:00
Merge pull request #396 from weaveworks/weave-docker-ips
Tag containers with Weave and Docker IPs
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||
|
||||
13
Makefile
13
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
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ FROM gliderlabs/alpine
|
||||
MAINTAINER Weaveworks Inc <help@weave.works>
|
||||
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
|
||||
|
||||
@@ -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,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 {
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -46,7 +80,10 @@ 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,
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -54,7 +91,9 @@ func TestWeaveTaggerOverlayTopology(t *testing.T) {
|
||||
have, err := w.Tag(report.Report{
|
||||
Container: report.Topology{
|
||||
NodeMetadatas: report.NodeMetadatas{
|
||||
nodeID: report.MakeNodeMetadata(),
|
||||
nodeID: report.MakeNodeMetadataWith(map[string]string{
|
||||
docker.ContainerID: mockContainerID,
|
||||
}),
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user