mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 10:11:03 +00:00
Add Containers topology populated by the Docker tagger.
This commit is contained in:
@@ -99,11 +99,17 @@ func main() {
|
||||
|
||||
case <-spyTick:
|
||||
r.Merge(spy(hostID, hostName, *spyProcs))
|
||||
|
||||
if pidTree, err := tag.NewPIDTree(*procRoot); err == nil {
|
||||
r.Process.Merge(pidTree.ProcessTopology(hostID))
|
||||
} else {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
if dockerTagger != nil {
|
||||
r.Container.Merge(dockerTagger.ContainerTopology(hostID))
|
||||
}
|
||||
|
||||
r = tag.Apply(r, taggers)
|
||||
|
||||
case <-quit:
|
||||
|
||||
@@ -16,6 +16,15 @@ const (
|
||||
start = "start"
|
||||
)
|
||||
|
||||
// These constants are keys used in node metadata
|
||||
// TODO: use these constants in report/{mapping.go, detailed_node.go} - pending some circular references
|
||||
const (
|
||||
ContainerID = "docker_container_id"
|
||||
ContainerName = "docker_container_name"
|
||||
ImageID = "docker_image_id"
|
||||
ImageName = "docker_image_name"
|
||||
)
|
||||
|
||||
var (
|
||||
newDockerClientStub = newDockerClient
|
||||
newPIDTreeStub = NewPIDTree
|
||||
@@ -290,9 +299,9 @@ func (t *DockerTagger) Tag(r report.Report) report.Report {
|
||||
}
|
||||
|
||||
md := report.NodeMetadata{
|
||||
"docker_container_id": container.ID,
|
||||
"docker_container_name": strings.TrimPrefix(container.Name, "/"),
|
||||
"docker_image_id": container.Image,
|
||||
ContainerID: container.ID,
|
||||
ContainerName: strings.TrimPrefix(container.Name, "/"),
|
||||
ImageID: container.Image,
|
||||
}
|
||||
|
||||
t.RLock()
|
||||
@@ -300,7 +309,7 @@ func (t *DockerTagger) Tag(r report.Report) report.Report {
|
||||
t.RUnlock()
|
||||
|
||||
if ok && len(image.RepoTags) > 0 {
|
||||
md["docker_image_name"] = image.RepoTags[0]
|
||||
md[ImageName] = image.RepoTags[0]
|
||||
}
|
||||
|
||||
r.Endpoint.NodeMetadatas[nodeID].Merge(md)
|
||||
@@ -308,3 +317,27 @@ func (t *DockerTagger) Tag(r report.Report) report.Report {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// ContainerTopology produces a Toplogy of Containers
|
||||
func (t *DockerTagger) ContainerTopology(scope string) report.Topology {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
result := report.NewTopology()
|
||||
for _, container := range t.containers {
|
||||
nmd := report.NodeMetadata{
|
||||
ContainerID: container.ID,
|
||||
ContainerName: strings.TrimPrefix(container.Name, "/"),
|
||||
ImageID: container.Image,
|
||||
}
|
||||
|
||||
image, ok := t.images[container.Image]
|
||||
if ok && len(image.RepoTags) > 0 {
|
||||
nmd[ImageName] = image.RepoTags[0]
|
||||
}
|
||||
|
||||
nodeID := report.MakeContainerNodeID(scope, container.ID)
|
||||
result.NodeMetadatas[nodeID] = nmd
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -70,10 +70,10 @@ func TestDockerTagger(t *testing.T) {
|
||||
endpoint1NodeID = "somehost.com;192.168.1.1;12345"
|
||||
endpoint2NodeID = "somehost.com;192.168.1.1;67890"
|
||||
processNodeMetadata = report.NodeMetadata{
|
||||
"docker_container_id": "foo",
|
||||
"docker_container_name": "bar",
|
||||
"docker_image_id": "baz",
|
||||
"docker_image_name": "bang",
|
||||
ContainerID: "foo",
|
||||
ContainerName: "bar",
|
||||
ImageID: "baz",
|
||||
ImageName: "bang",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -91,4 +91,11 @@ func TestDockerTagger(t *testing.T) {
|
||||
t.Errorf("%q: want %+v, have %+v", endpointNodeID, want, have)
|
||||
}
|
||||
}
|
||||
|
||||
wantTopology := report.NewTopology()
|
||||
wantTopology.NodeMetadatas[report.MakeContainerNodeID("", "foo")] = processNodeMetadata
|
||||
haveTopology := dockerTagger.ContainerTopology("")
|
||||
if !reflect.DeepEqual(wantTopology, haveTopology) {
|
||||
t.Errorf("toplog want %+v, have %+v", wantTopology, haveTopology)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,9 @@ func OriginTable(r Report, originID string) (Table, bool) {
|
||||
if nmd, ok := r.Process.NodeMetadatas[originID]; ok {
|
||||
return processOriginTable(nmd)
|
||||
}
|
||||
if nmd, ok := r.Container.NodeMetadatas[originID]; ok {
|
||||
return containerOriginTable(nmd)
|
||||
}
|
||||
if nmd, ok := r.Host.NodeMetadatas[originID]; ok {
|
||||
return hostOriginTable(nmd)
|
||||
}
|
||||
@@ -72,7 +75,6 @@ func endpointOriginTable(nmd NodeMetadata) (Table, bool) {
|
||||
{"docker_container_name", "Container name"},
|
||||
{"docker_image_id", "Container image ID"},
|
||||
{"docker_image_name", "Container image name"},
|
||||
{"cgroup", "cgroup"},
|
||||
} {
|
||||
if val, ok := nmd[tuple.key]; ok {
|
||||
rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
|
||||
@@ -118,6 +120,25 @@ func processOriginTable(nmd NodeMetadata) (Table, bool) {
|
||||
}, len(rows) > 0
|
||||
}
|
||||
|
||||
func containerOriginTable(nmd NodeMetadata) (Table, bool) {
|
||||
rows := []Row{}
|
||||
for _, tuple := range []struct{ key, human string }{
|
||||
{"docker_container_id", "Container ID"},
|
||||
{"docker_container_name", "Container name"},
|
||||
{"docker_image_id", "Container image ID"},
|
||||
{"docker_image_name", "Container image name"},
|
||||
} {
|
||||
if val, ok := nmd[tuple.key]; ok {
|
||||
rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
|
||||
}
|
||||
}
|
||||
return Table{
|
||||
Title: "Origin Container",
|
||||
Numeric: false,
|
||||
Rows: rows,
|
||||
}, len(rows) > 0
|
||||
}
|
||||
|
||||
func hostOriginTable(nmd NodeMetadata) (Table, bool) {
|
||||
rows := []Row{}
|
||||
if val, ok := nmd["host_name"]; ok {
|
||||
|
||||
@@ -72,6 +72,11 @@ func MakeHostNodeID(hostID string) string {
|
||||
return hostID + ScopeDelim + "<host>"
|
||||
}
|
||||
|
||||
// MakeContainerNodeID produces a container node ID from its composite parts.
|
||||
func MakeContainerNodeID(hostID, containerID string) string {
|
||||
return hostID + ScopeDelim + containerID
|
||||
}
|
||||
|
||||
// ParseNodeID produces the scope and remainder from a node ID
|
||||
func ParseNodeID(nodeID string) (string, string, bool) {
|
||||
fields := strings.SplitN(nodeID, ScopeDelim, 2)
|
||||
|
||||
@@ -9,6 +9,7 @@ func (r *Report) Merge(other Report) {
|
||||
r.Endpoint.Merge(other.Endpoint)
|
||||
r.Address.Merge(other.Address)
|
||||
r.Process.Merge(other.Process)
|
||||
r.Container.Merge(other.Container)
|
||||
r.Host.Merge(other.Host)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,11 @@ type Report struct {
|
||||
// Process nodes are processes on each host. Edges are not present.
|
||||
Process Topology
|
||||
|
||||
// Container nodes represent all Docker containers on hosts running probes.
|
||||
// Metadata includes things like Docker image, name etc.
|
||||
// Edges are not present.
|
||||
Container Topology
|
||||
|
||||
// Host nodes are physical hosts that run probes. Metadata includes things
|
||||
// like operating system, load, etc. The information is scraped by the
|
||||
// probes with each published report. Edges are not present.
|
||||
@@ -70,10 +75,11 @@ type Row struct {
|
||||
// MakeReport makes a clean report, ready to Merge() other reports into.
|
||||
func MakeReport() Report {
|
||||
return Report{
|
||||
Endpoint: NewTopology(),
|
||||
Address: NewTopology(),
|
||||
Process: NewTopology(),
|
||||
Host: NewTopology(),
|
||||
Endpoint: NewTopology(),
|
||||
Address: NewTopology(),
|
||||
Process: NewTopology(),
|
||||
Container: NewTopology(),
|
||||
Host: NewTopology(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +90,7 @@ func (r Report) Squash() Report {
|
||||
r.Endpoint = r.Endpoint.Squash(EndpointIDAddresser, localNetworks)
|
||||
r.Address = r.Address.Squash(AddressIDAddresser, localNetworks)
|
||||
r.Process = r.Process.Squash(PanicIDAddresser, localNetworks)
|
||||
r.Container = r.Container.Squash(PanicIDAddresser, localNetworks)
|
||||
r.Host = r.Host.Squash(PanicIDAddresser, localNetworks)
|
||||
return r
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user