Ensure backward compatilibity in report's node controls

The new probe will convert all node's LatestControls to Controls, so
the old app can consume them. Also, the new app will convert all
node's Controls to LatestControl, so it can consume the reports from
old probes.
This commit is contained in:
Krzesimir Nowak
2016-08-02 11:30:11 +02:00
parent 2a0972653c
commit 0ecb908c22
4 changed files with 103 additions and 2 deletions

View File

@@ -118,7 +118,9 @@ func (c *collector) Report(_ context.Context) (report.Report, error) {
}
c.clean()
return c.merger.Merge(c.reports), nil
rpt := c.merger.Merge(c.reports).Upgrade()
c.cached = &rpt
return rpt, nil
}
func (c *collector) clean() {

View File

@@ -200,7 +200,7 @@ ForLoop:
}
}
if err := p.publisher.Publish(rpt); err != nil {
if err := p.publisher.Publish(rpt.BackwardCompatible()); err != nil {
log.Infof("publish: %v", err)
}
}

View File

@@ -6,6 +6,7 @@ import (
"strings"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/scope/common/xfer"
)
@@ -254,6 +255,57 @@ func (r Report) Validate() error {
return nil
}
// Upgrade returns a new report based on a report received from the old probe.
//
// This for now creates node's LatestControls from Controls.
func (r Report) Upgrade() Report {
cp := r.Copy()
ncd := NodeControlData{
Dead: false,
}
cp.WalkTopologies(func(topology *Topology) {
n := Nodes{}
for name, node := range topology.Nodes {
if node.LatestControls.Size() == 0 && len(node.Controls.Controls) > 0 {
for _, control := range node.Controls.Controls {
node.LatestControls = node.LatestControls.Set(control, node.Controls.Timestamp, ncd)
}
}
n[name] = node
}
topology.Nodes = n
})
return cp
}
// BackwardCompatible returns a new backward-compatible report.
//
// This for now creates node's Controls from LatestControls.
func (r Report) BackwardCompatible() Report {
now := mtime.Now()
cp := r.Copy()
cp.WalkTopologies(func(topology *Topology) {
n := Nodes{}
for name, node := range topology.Nodes {
var controls []string
node.LatestControls.ForEach(func(k string, _ time.Time, v NodeControlData) {
if !v.Dead {
controls = append(controls, k)
}
})
if len(controls) > 0 {
node.Controls = NodeControls{
Timestamp: now,
Controls: MakeStringSet(controls...),
}
}
n[name] = node
}
topology.Nodes = n
})
return cp
}
// Sampling describes how the packet data sources for this report were
// sampled. It can be used to calculate effective sample rates. We can't
// just put the rate here, because that can't be accurately merged. Counts

View File

@@ -3,8 +3,12 @@ package report_test
import (
"reflect"
"testing"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
s_reflect "github.com/weaveworks/scope/test/reflect"
)
func newu64(value uint64) *uint64 { return &value }
@@ -74,3 +78,46 @@ func TestNode(t *testing.T) {
}
}
}
func TestReportBackwardCompatibility(t *testing.T) {
mtime.NowForce(time.Now())
defer mtime.NowReset()
rpt := report.MakeReport()
controls := map[string]report.NodeControlData{
"dead": {
Dead: true,
},
"alive": {
Dead: false,
},
}
node := report.MakeNode("foo").WithLatestControls(controls)
expectedNode := node.WithControls("alive")
rpt.Pod.AddNode(node)
expected := report.MakeReport()
expected.Pod.AddNode(expectedNode)
got := rpt.BackwardCompatible()
if !s_reflect.DeepEqual(expected, got) {
t.Error(test.Diff(expected, got))
}
}
func TestReportUpgrade(t *testing.T) {
mtime.NowForce(time.Now())
defer mtime.NowReset()
node := report.MakeNode("foo").WithControls("alive")
controls := map[string]report.NodeControlData{
"alive": {
Dead: false,
},
}
expectedNode := node.WithLatestControls(controls)
rpt := report.MakeReport()
rpt.Pod.AddNode(node)
expected := report.MakeReport()
expected.Pod.AddNode(expectedNode)
got := rpt.Upgrade()
if !s_reflect.DeepEqual(expected, got) {
t.Error(test.Diff(expected, got))
}
}