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)) + } +}