backwards-compatibility: unmarshall latestControls data from older probes

With a test.
This commit is contained in:
Bryan Boreham
2019-10-14 18:50:28 +00:00
parent eb381f167d
commit 635cea0b56
2 changed files with 101 additions and 0 deletions

View File

@@ -2,6 +2,57 @@ package report
// Backwards-compatibility: code to read older reports and convert
import (
"strings"
"time"
"github.com/ugorji/go/codec"
)
// For backwards-compatibility with probes that sent a map of latestControls data
type bcNode struct {
Node
LatestControls map[string]nodeControlDataLatestEntry `json:"latestControls,omitempty"`
}
type nodeControlDataLatestEntry struct {
Timestamp time.Time `json:"timestamp"`
Value nodeControlData `json:"value"`
}
type nodeControlData struct {
Dead bool `json:"dead"`
}
// CodecDecodeSelf implements codec.Selfer
func (n *Node) CodecDecodeSelf(decoder *codec.Decoder) {
var in bcNode
decoder.Decode(&in)
*n = in.Node
if len(in.LatestControls) > 0 {
// Convert the map into a delimited string
cs := make([]string, 0, len(in.LatestControls))
var ts time.Time
for name, v := range in.LatestControls {
if !v.Value.Dead {
cs = append(cs, name)
// Pull out the newest timestamp to use for the whole set
if ts.Before(v.Timestamp) {
ts = v.Timestamp
}
}
}
n.Latest = n.Latest.Set(NodeActiveControls, ts, strings.Join(cs, ScopeDelim))
}
}
type _Node Node // just so we don't recurse inside CodecEncodeSelf
// CodecEncodeSelf implements codec.Selfer
func (n *Node) CodecEncodeSelf(encoder *codec.Encoder) {
encoder.Encode((*_Node)(n))
}
// Upgrade returns a new report based on a report received from the old probe.
//
func (r Report) Upgrade() Report {

View File

@@ -1,12 +1,14 @@
package report_test
import (
"bytes"
"context"
"reflect"
"testing"
"time"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/common/test"
"github.com/weaveworks/scope/report"
s_reflect "github.com/weaveworks/scope/test/reflect"
)
@@ -71,3 +73,51 @@ func TestBiggerRoundtrip(t *testing.T) {
t.Errorf("%v != %v", r1, *r2)
}
}
func TestControlsCompat(t *testing.T) {
testData := `{
"Container": {
"nodes": {
"031d;<container>": {
"id": "031d;<container>",
"latest": {
"control_probe_id": {
"timestamp": "2019-10-14T14:36:01Z",
"value": "29b4f381044a89a3"
}
},
"latestControls": {
"docker_attach_container": {
"timestamp": "2019-10-14T14:36:01Z",
"value": {"dead": true}
},
"docker_remove_container": {
"timestamp": "2019-10-14T14:36:01Z",
"value": {"dead": false}
}
},
"topology": "container"
}
},
"shape": "hexagon"
}
}`
nowTime := time.Date(2019, 10, 14, 14, 36, 1, 0, time.UTC)
mtime.NowForce(nowTime)
expected := report.MakeReport()
expected.Container.AddNode(report.MakeNode(report.MakeContainerNodeID("031d")).
WithTopology("container").
WithLatestActiveControls("docker_remove_container").
WithLatests(map[string]string{"control_probe_id": "29b4f381044a89a3"}),
)
buf := bytes.NewBufferString(testData)
rpt, err := report.MakeFromBinary(context.Background(), buf, false, false)
if err != nil {
t.Fatal(err)
}
if !s_reflect.DeepEqual(&expected, rpt) {
t.Error(test.Diff(&expected, rpt))
}
}