diff --git a/client/app/scripts/components/node-details.js b/client/app/scripts/components/node-details.js index 701e58896..d7a654586 100644 --- a/client/app/scripts/components/node-details.js +++ b/client/app/scripts/components/node-details.js @@ -129,7 +129,7 @@ export default class NodeDetails extends React.Component { renderDetails() { const details = this.props.details; - const showSummary = details.metadata !== undefined || details.metrics !== undefined; + const showSummary = (details.metadata || details.metrics || details.docker_labels) !== undefined; const showControls = details.controls && details.controls.length > 0; const nodeColor = getNodeColorDark(details.rank, details.label, details.pseudo); const {error, pending} = (this.props.nodeControlStatus || {}); @@ -168,7 +168,9 @@ export default class NodeDetails extends React.Component { {showSummary &&
Status
{details.metrics && } - {details.metadata && } + {details.metadata && } + {details.docker_labels &&
Docker Labels
} + {details.docker_labels && }
} {details.children && details.children.map(children => { diff --git a/client/app/scripts/components/node-details/node-details-info.js b/client/app/scripts/components/node-details/node-details-info.js index 1f9b2e27d..eab95092d 100644 --- a/client/app/scripts/components/node-details/node-details-info.js +++ b/client/app/scripts/components/node-details/node-details-info.js @@ -4,7 +4,7 @@ export default class NodeDetailsInfo extends React.Component { render() { return (
- {this.props.metadata && this.props.metadata.map(field => { + {this.props.rows && this.props.rows.map(field => { return (
diff --git a/render/detailed/docker_labels.go b/render/detailed/docker_labels.go new file mode 100644 index 000000000..b8f886ecc --- /dev/null +++ b/render/detailed/docker_labels.go @@ -0,0 +1,30 @@ +package detailed + +import ( + "sort" + + "github.com/weaveworks/scope/probe/docker" + "github.com/weaveworks/scope/report" +) + +// NodeDockerLabels produces a table (to be consumed directly by the UI) based +// on an origin ID, which is (optimistically) a node ID in one of our +// topologies. +func NodeDockerLabels(nmd report.Node) []MetadataRow { + if nmd.Topology != report.Container && nmd.Topology != report.ContainerImage { + return nil + } + + var rows []MetadataRow + // Add labels in alphabetical order + labels := docker.ExtractLabels(nmd) + labelKeys := make([]string, 0, len(labels)) + for k := range labels { + labelKeys = append(labelKeys, k) + } + sort.Strings(labelKeys) + for _, labelKey := range labelKeys { + rows = append(rows, MetadataRow{ID: "label_" + labelKey, Value: labels[labelKey]}) + } + return rows +} diff --git a/render/detailed/docker_labels_test.go b/render/detailed/docker_labels_test.go new file mode 100644 index 000000000..0eefa342b --- /dev/null +++ b/render/detailed/docker_labels_test.go @@ -0,0 +1,50 @@ +package detailed_test + +import ( + "reflect" + "testing" + + "github.com/weaveworks/scope/probe/docker" + "github.com/weaveworks/scope/render/detailed" + "github.com/weaveworks/scope/report" + "github.com/weaveworks/scope/test" + "github.com/weaveworks/scope/test/fixture" +) + +func TestNodeDockerLabels(t *testing.T) { + inputs := []struct { + name string + node report.Node + want []detailed.MetadataRow + }{ + { + name: "container", + node: report.MakeNodeWith(map[string]string{ + docker.ContainerID: fixture.ClientContainerID, + docker.LabelPrefix + "label1": "label1value", + docker.ContainerState: docker.StateRunning, + }).WithTopology(report.Container).WithSets(report.EmptySets. + Add(docker.ContainerIPs, report.MakeStringSet("10.10.10.0/24", "10.10.10.1/24")), + ), + want: []detailed.MetadataRow{ + { + ID: "label_label1", + Value: "label1value", + }, + }, + }, + { + name: "unknown topology", + node: report.MakeNodeWith(map[string]string{ + docker.ContainerID: fixture.ClientContainerID, + }).WithTopology("foobar").WithID(fixture.ClientContainerNodeID), + want: nil, + }, + } + for _, input := range inputs { + have := detailed.NodeDockerLabels(input.node) + if !reflect.DeepEqual(input.want, have) { + t.Errorf("%s: %s", input.name, test.Diff(input.want, have)) + } + } +} diff --git a/render/detailed/labels.go b/render/detailed/labels.go index 28afb9228..a2743c6f9 100644 --- a/render/detailed/labels.go +++ b/render/detailed/labels.go @@ -1,7 +1,6 @@ package detailed import ( - "fmt" "strings" "github.com/weaveworks/scope/probe/docker" @@ -54,7 +53,7 @@ func Label(key string) string { return label } if strings.HasPrefix(key, "label_") { - return fmt.Sprintf("Label %q", strings.TrimPrefix(key, "label_")) + return strings.TrimPrefix(key, "label_") } return key } diff --git a/render/detailed/metadata.go b/render/detailed/metadata.go index 109abb47f..089ba53a7 100644 --- a/render/detailed/metadata.go +++ b/render/detailed/metadata.go @@ -2,7 +2,6 @@ package detailed import ( "encoding/json" - "sort" "strings" "github.com/weaveworks/scope/probe/docker" @@ -32,11 +31,9 @@ var ( ltst(docker.ContainerCommand), ltst(overlay.WeaveMACAddress), ltst(overlay.WeaveDNSHostname), - getDockerLabelRows, ) containerImageNodeMetadata = renderMetadata( ltst(docker.ImageID), - getDockerLabelRows, ) podNodeMetadata = renderMetadata( ltst(kubernetes.PodID), @@ -123,18 +120,3 @@ func ltst(id string) func(report.Node) []MetadataRow { return nil } } - -func getDockerLabelRows(nmd report.Node) []MetadataRow { - rows := []MetadataRow{} - // Add labels in alphabetical order - labels := docker.ExtractLabels(nmd) - labelKeys := make([]string, 0, len(labels)) - for k := range labels { - labelKeys = append(labelKeys, k) - } - sort.Strings(labelKeys) - for _, labelKey := range labelKeys { - rows = append(rows, MetadataRow{ID: "label_" + labelKey, Value: labels[labelKey]}) - } - return rows -} diff --git a/render/detailed/metadata_test.go b/render/detailed/metadata_test.go index 2322a1e68..2e55999fc 100644 --- a/render/detailed/metadata_test.go +++ b/render/detailed/metadata_test.go @@ -30,10 +30,6 @@ func TestNodeMetadata(t *testing.T) { {ID: docker.ContainerID, Value: fixture.ClientContainerID}, {ID: docker.ContainerState, Value: "running"}, {ID: docker.ContainerIPs, Value: "10.10.10.0/24, 10.10.10.1/24"}, - { - ID: "label_label1", - Value: "label1value", - }, }, }, { diff --git a/render/detailed/node_test.go b/render/detailed/node_test.go index 69cde0de5..8f7931def 100644 --- a/render/detailed/node_test.go +++ b/render/detailed/node_test.go @@ -121,6 +121,8 @@ func TestMakeDetailedContainerNode(t *testing.T) { {ID: "docker_container_id", Value: fixture.ServerContainerID}, {ID: "docker_image_id", Value: fixture.ServerContainerImageID}, {ID: "docker_container_state", Value: "running"}, + }, + DockerLabels: []detailed.MetadataRow{ {ID: "label_" + render.AmazonECSContainerNameLabel, Value: `server`}, {ID: "label_foo1", Value: `bar1`}, {ID: "label_foo2", Value: `bar2`}, diff --git a/render/detailed/summary.go b/render/detailed/summary.go index 83c0ebf92..07c3f6e74 100644 --- a/render/detailed/summary.go +++ b/render/detailed/summary.go @@ -34,11 +34,12 @@ func (g NodeSummaryGroup) Copy() NodeSummaryGroup { // NodeSummary is summary information about a child for a Node. type NodeSummary struct { - ID string `json:"id"` - Label string `json:"label"` - Linkable bool `json:"linkable"` // Whether this node can be linked-to - Metadata []MetadataRow `json:"metadata,omitempty"` - Metrics []MetricRow `json:"metrics,omitempty"` + ID string `json:"id"` + Label string `json:"label"` + Linkable bool `json:"linkable"` // Whether this node can be linked-to + Metadata []MetadataRow `json:"metadata,omitempty"` + DockerLabels []MetadataRow `json:"docker_labels,omitempty"` + Metrics []MetricRow `json:"metrics,omitempty"` } // MakeNodeSummary summarizes a node, if possible. @@ -66,12 +67,26 @@ func (n NodeSummary) Copy() NodeSummary { for _, row := range n.Metadata { result.Metadata = append(result.Metadata, row.Copy()) } + for _, row := range n.DockerLabels { + result.DockerLabels = append(result.DockerLabels, row.Copy()) + } for _, row := range n.Metrics { result.Metrics = append(result.Metrics, row.Copy()) } return result } +func baseNodeSummary(id, label string, linkable bool, nmd report.Node) NodeSummary { + return NodeSummary{ + ID: id, + Label: label, + Linkable: linkable, + Metadata: NodeMetadata(nmd), + DockerLabels: NodeDockerLabels(nmd), + Metrics: NodeMetrics(nmd), + } +} + func processNodeSummary(nmd report.Node) NodeSummary { var ( id string @@ -84,57 +99,29 @@ func processNodeSummary(nmd report.Node) NodeSummary { id = render.MakeProcessID(report.ExtractHostID(nmd), pid) } _, isConnected := nmd.Latest.Lookup(render.IsConnected) - return NodeSummary{ - ID: id, - Label: label, - Linkable: isConnected, - Metadata: processNodeMetadata(nmd), - Metrics: processNodeMetrics(nmd), - } + return baseNodeSummary(id, label, isConnected, nmd) } func containerNodeSummary(nmd report.Node) NodeSummary { label, _ := render.GetRenderableContainerName(nmd) containerID, _ := nmd.Latest.Lookup(docker.ContainerID) - return NodeSummary{ - ID: render.MakeContainerID(containerID), - Label: label, - Linkable: true, - Metadata: containerNodeMetadata(nmd), - Metrics: containerNodeMetrics(nmd), - } + return baseNodeSummary(render.MakeContainerID(containerID), label, true, nmd) } func containerImageNodeSummary(nmd report.Node) NodeSummary { imageName, _ := nmd.Latest.Lookup(docker.ImageName) - return NodeSummary{ - ID: render.MakeContainerImageID(render.ImageNameWithoutVersion(imageName)), - Label: imageName, - Linkable: true, - Metadata: containerImageNodeMetadata(nmd), - } + return baseNodeSummary(render.MakeContainerImageID(render.ImageNameWithoutVersion(imageName)), imageName, true, nmd) } func podNodeSummary(nmd report.Node) NodeSummary { podID, _ := nmd.Latest.Lookup(kubernetes.PodID) podName, _ := nmd.Latest.Lookup(kubernetes.PodName) - return NodeSummary{ - ID: render.MakePodID(podID), - Label: podName, - Linkable: true, - Metadata: podNodeMetadata(nmd), - } + return baseNodeSummary(render.MakePodID(podID), podName, true, nmd) } func hostNodeSummary(nmd report.Node) NodeSummary { hostName, _ := nmd.Latest.Lookup(host.HostName) - return NodeSummary{ - ID: render.MakeHostID(hostName), - Label: hostName, - Linkable: true, - Metadata: hostNodeMetadata(nmd), - Metrics: hostNodeMetrics(nmd), - } + return baseNodeSummary(render.MakeHostID(hostName), hostName, true, nmd) } type nodeSummariesByID []NodeSummary