From e99275eb5ad80d3ef90c8d0a5451fa5ad3e3143b Mon Sep 17 00:00:00 2001 From: Steffen Siering Date: Thu, 26 Apr 2018 14:31:25 +0200 Subject: [PATCH] Fix heartbeat races on event updates (#6950) Heartbeat has a many components, each adding fields to an existing event. As events are created per 'TaskRun', this is normally fine. But in case the TaskRunner branches of into multiple Sub-tasks, we will see races on shared event structures. This is the case with multiple ports in the http/tcp configuration or the IPAll setting (ping all known IPs of a given domain). Namespaces in an event can be potentially populated via globally shared structures. This can also lead to unwanted updates or races. This fix clones the event structure before continuing event updates, so to remove the chance of races. (cherry picked from commit e92ed3e82270df051038e36d74ad78c18cff2f0e) --- CHANGELOG.asciidoc | 1 + heartbeat/monitors/util.go | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index dd230fb5a40..a6856b4c1c2 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -67,6 +67,7 @@ https://github.com/elastic/beats/compare/v6.0.0-beta2...master[Check the HEAD di - Add raw JSON to message field when JSON parsing fails. {issue}6516[6516] *Heartbeat* +- Fix race due to updates of shared a map, that was not supposed to be shared between multiple go-routines. {issue}6616[6616] *Metricbeat* diff --git a/heartbeat/monitors/util.go b/heartbeat/monitors/util.go index 88b58984e2f..efd6c755196 100644 --- a/heartbeat/monitors/util.go +++ b/heartbeat/monitors/util.go @@ -122,6 +122,8 @@ func annotated( } if fields != nil { + fields = fields.Clone() + status := look.Status(err) fields.DeepUpdate(common.MapStr{ "monitor": common.MapStr{ @@ -130,7 +132,7 @@ func annotated( }, }) if user := settings.Fields; user != nil { - fields.DeepUpdate(user) + fields.DeepUpdate(user.Clone()) } event.Timestamp = start @@ -370,10 +372,13 @@ func resolveErr(host string, err error) (common.MapStr, []TaskRunner, error) { func WithFields(fields common.MapStr, r TaskRunner) TaskRunner { return MakeCont(func() (common.MapStr, []TaskRunner, error) { event, cont, err := r.Run() - if event == nil { + if event != nil { + event = event.Clone() + event.DeepUpdate(fields) + } else if err != nil { event = common.MapStr{} + event.DeepUpdate(fields) } - event.DeepUpdate(fields) for i := range cont { cont[i] = WithFields(fields, cont[i])