From 0ecb908c22994bde00cc54ec432ee766ed15b005 Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Tue, 2 Aug 2016 11:30:11 +0200 Subject: [PATCH] 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. --- app/collector.go | 4 +++- probe/probe.go | 2 +- report/report.go | 52 +++++++++++++++++++++++++++++++++++++++++++ report/report_test.go | 47 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/app/collector.go b/app/collector.go index deadce4a8..18b67bcc8 100644 --- a/app/collector.go +++ b/app/collector.go @@ -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() { diff --git a/probe/probe.go b/probe/probe.go index a9139fc4d..80d1bf458 100644 --- a/probe/probe.go +++ b/probe/probe.go @@ -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) } } diff --git a/report/report.go b/report/report.go index a92dc4914..75c8e591b 100644 --- a/report/report.go +++ b/report/report.go @@ -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 diff --git a/report/report_test.go b/report/report_test.go index 6db2c3184..95c10b685 100644 --- a/report/report_test.go +++ b/report/report_test.go @@ -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)) + } +}