mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-17 20:41:51 +00:00
plugins/traffic-control: add status information in metadata
This patch sends the delay and packet loss values along with the container metadata. In this way the user has a direct feedback about the traffic control plugin status.
This commit is contained in:
@@ -13,12 +13,23 @@ type report struct {
|
||||
}
|
||||
|
||||
type topology struct {
|
||||
Nodes map[string]node `json:"nodes"`
|
||||
Controls map[string]control `json:"controls"`
|
||||
Nodes map[string]node `json:"nodes"`
|
||||
Controls map[string]control `json:"controls"`
|
||||
MetadataTemplates map[string]metadataTemplate `json:"metadata_templates,omitempty"`
|
||||
}
|
||||
|
||||
type metadataTemplate struct {
|
||||
ID string `json:"id"`
|
||||
Label string `json:"label,omitempty"` // Human-readable descriptor for this row
|
||||
Truncate int `json:"truncate,omitempty"` // If > 0, truncate the value to this length.
|
||||
Datatype string `json:"dataType,omitempty"`
|
||||
Priority float64 `json:"priority,omitempty"`
|
||||
From string `json:"from,omitempty"` // Defines how to get the value from a report node
|
||||
}
|
||||
|
||||
type node struct {
|
||||
LatestControls map[string]controlEntry `json:"latestControls,omitempty"`
|
||||
Latest map[string]stringEntry `json:"latest,omitempty"`
|
||||
}
|
||||
|
||||
type controlEntry struct {
|
||||
@@ -37,6 +48,11 @@ type control struct {
|
||||
Rank int `json:"rank"`
|
||||
}
|
||||
|
||||
type stringEntry struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type pluginSpec struct {
|
||||
ID string `json:"id"`
|
||||
Label string `json:"label"`
|
||||
@@ -58,8 +74,9 @@ func NewReporter(store *Store) *Reporter {
|
||||
func (r *Reporter) RawReport() ([]byte, error) {
|
||||
rpt := &report{
|
||||
Container: topology{
|
||||
Nodes: r.getContainerNodes(),
|
||||
Controls: getTrafficControls(),
|
||||
Nodes: r.getContainerNodes(),
|
||||
Controls: getTrafficControls(),
|
||||
MetadataTemplates: getMetadataTemplate(),
|
||||
},
|
||||
Plugins: []pluginSpec{
|
||||
{
|
||||
@@ -120,14 +137,34 @@ func (r *Reporter) getContainerNodes() map[string]node {
|
||||
fallthrough
|
||||
case Running:
|
||||
nodeID := containerIDToNodeID(containerID)
|
||||
latency, _ := getLatency(container.PID)
|
||||
nodes[nodeID] = node{
|
||||
LatestControls: getTrafficNodeControls(timestamp, dead),
|
||||
Latest: map[string]stringEntry{
|
||||
"traffic-control-latency": {
|
||||
Timestamp: timestamp,
|
||||
Value: latency,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
return nodes
|
||||
}
|
||||
|
||||
func getMetadataTemplate() map[string]metadataTemplate {
|
||||
return map[string]metadataTemplate{
|
||||
"traffic-control-latency": metadataTemplate{
|
||||
ID: "traffic-control-latency",
|
||||
Label: "Latency",
|
||||
Truncate: 0,
|
||||
Datatype: "",
|
||||
Priority: 13.5,
|
||||
From: "latest",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getTrafficNodeControls(timestamp time.Time, dead bool) map[string]controlEntry {
|
||||
controls := map[string]controlEntry{}
|
||||
entry := controlEntry{
|
||||
|
||||
@@ -46,6 +46,67 @@ func DoTrafficControl(pid int, delay uint32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLatency(pid int) (string, error) {
|
||||
output := "-"
|
||||
var err error
|
||||
if output, err = getStatus(pid); err != nil {
|
||||
return "-", err
|
||||
} else if output == "" {
|
||||
return "-", fmt.Errorf("Error: output is empty")
|
||||
}
|
||||
outputSplited := split(output)
|
||||
for i, s := range outputSplited {
|
||||
if s == "delay" {
|
||||
if i < len(outputSplited)-1 {
|
||||
output = outputSplited[i+1]
|
||||
} else {
|
||||
output = "-"
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
}
|
||||
return output, fmt.Errorf("delay not found")
|
||||
}
|
||||
|
||||
func getPktLoss(pid int) (string, error) {
|
||||
output := "-"
|
||||
var err error
|
||||
if output, err = getStatus(pid); err != nil {
|
||||
return "-", err
|
||||
} else if output == "" {
|
||||
return "-", fmt.Errorf("Error: output is empty")
|
||||
}
|
||||
outputSplited := split(output)
|
||||
for i, s := range outputSplited {
|
||||
if s == "loss" {
|
||||
if i < len(outputSplited)-1 {
|
||||
output = outputSplited[i+1]
|
||||
} else {
|
||||
output = "-"
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
}
|
||||
return output, fmt.Errorf("delay not found")
|
||||
}
|
||||
|
||||
func getStatus(pid int) (string, error) {
|
||||
cmd := split("tc qdisc show dev eth0")
|
||||
netNS := fmt.Sprintf("/proc/%d/ns/net", pid)
|
||||
var output string
|
||||
err := ns.WithNetNSPath(netNS, func(hostNS ns.NetNS) error {
|
||||
if cmdOut, err := exec.Command(cmd[0], cmd[1:]...).CombinedOutput(); err != nil {
|
||||
log.Error(string(cmdOut))
|
||||
output = "-"
|
||||
return fmt.Errorf("failed to execute command: tc qdisc show dev eth0: %v", err)
|
||||
} else {
|
||||
output = string(cmdOut)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return output, err
|
||||
}
|
||||
|
||||
func split(cmd string) []string {
|
||||
return strings.Split(cmd, " ")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user