From f3d18f91c1aeb4d49d2214f519430e02a173b357 Mon Sep 17 00:00:00 2001 From: Blake Rouse Date: Mon, 12 Oct 2020 10:05:51 -0400 Subject: [PATCH] [Elastic Agent] Fix issue where inputs without processors defined would panic (#21628) * Fix #21581. * Add changelog entry. * Add test for processors as a map. --- x-pack/elastic-agent/CHANGELOG.next.asciidoc | 1 + .../pkg/agent/application/emitter.go | 11 +- .../pkg/agent/application/emitter_test.go | 175 ++++++++++++++++++ 3 files changed, 183 insertions(+), 4 deletions(-) diff --git a/x-pack/elastic-agent/CHANGELOG.next.asciidoc b/x-pack/elastic-agent/CHANGELOG.next.asciidoc index 73dfe8ff9a4..eb98ef39ded 100644 --- a/x-pack/elastic-agent/CHANGELOG.next.asciidoc +++ b/x-pack/elastic-agent/CHANGELOG.next.asciidoc @@ -14,6 +14,7 @@ - Thread safe sorted set {pull}21290[21290] - Copy Action store on upgrade {pull}21298[21298] - Include inputs in action store actions {pull}21298[21298] +- Fix issue where inputs without processors defined would panic {pull}21628[21628] ==== New features diff --git a/x-pack/elastic-agent/pkg/agent/application/emitter.go b/x-pack/elastic-agent/pkg/agent/application/emitter.go index 3bd06043c30..07f8e1f460b 100644 --- a/x-pack/elastic-agent/pkg/agent/application/emitter.go +++ b/x-pack/elastic-agent/pkg/agent/application/emitter.go @@ -219,17 +219,20 @@ func promoteProcessors(dict *transpiler.Dict) *transpiler.Dict { if p == nil { return dict } + var currentList *transpiler.List current, ok := dict.Find("processors") - currentList, isList := current.Value().(*transpiler.List) - if !isList { - return dict + if ok { + currentList, ok = current.Value().(*transpiler.List) + if !ok { + return dict + } } ast, _ := transpiler.NewAST(map[string]interface{}{ "processors": p, }) procs, _ := transpiler.Lookup(ast, "processors") nodes := nodesFromList(procs.Value().(*transpiler.List)) - if ok { + if ok && currentList != nil { nodes = append(nodes, nodesFromList(currentList)...) } dictNodes := dict.Value().([]transpiler.Node) diff --git a/x-pack/elastic-agent/pkg/agent/application/emitter_test.go b/x-pack/elastic-agent/pkg/agent/application/emitter_test.go index 32770eaa5df..b2286552f9f 100644 --- a/x-pack/elastic-agent/pkg/agent/application/emitter_test.go +++ b/x-pack/elastic-agent/pkg/agent/application/emitter_test.go @@ -479,6 +479,181 @@ func TestRenderInputs(t *testing.T) { }), }, }, + "inputs without processors and vars with processors": { + input: transpiler.NewKey("inputs", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("type", transpiler.NewStrVal("logfile")), + transpiler.NewKey("streams", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("paths", transpiler.NewList([]transpiler.Node{ + transpiler.NewStrVal("/var/log/${var1.name}.log"), + })), + }), + })), + }), + })), + expected: transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("type", transpiler.NewStrVal("logfile")), + transpiler.NewKey("streams", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("paths", transpiler.NewList([]transpiler.Node{ + transpiler.NewStrVal("/var/log/value1.log"), + })), + }), + })), + transpiler.NewKey("processors", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("add_fields", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("fields", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("custom", transpiler.NewStrVal("value1")), + })), + transpiler.NewKey("to", transpiler.NewStrVal("dynamic")), + })), + }), + })), + }), + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("type", transpiler.NewStrVal("logfile")), + transpiler.NewKey("streams", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("paths", transpiler.NewList([]transpiler.Node{ + transpiler.NewStrVal("/var/log/value2.log"), + })), + }), + })), + transpiler.NewKey("processors", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("add_fields", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("fields", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("custom", transpiler.NewStrVal("value2")), + })), + transpiler.NewKey("to", transpiler.NewStrVal("dynamic")), + })), + }), + })), + }), + }), + varsArray: []*transpiler.Vars{ + mustMakeVarsP(map[string]interface{}{ + "var1": map[string]interface{}{ + "name": "value1", + }, + }, + "var1", + []map[string]interface{}{ + { + "add_fields": map[string]interface{}{ + "fields": map[string]interface{}{ + "custom": "value1", + }, + "to": "dynamic", + }, + }, + }), + mustMakeVarsP(map[string]interface{}{ + "var1": map[string]interface{}{ + "name": "value2", + }, + }, + "var1", + []map[string]interface{}{ + { + "add_fields": map[string]interface{}{ + "fields": map[string]interface{}{ + "custom": "value2", + }, + "to": "dynamic", + }, + }, + }), + }, + }, + "processors incorrectly a map": { + input: transpiler.NewKey("inputs", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("type", transpiler.NewStrVal("logfile")), + transpiler.NewKey("streams", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("paths", transpiler.NewList([]transpiler.Node{ + transpiler.NewStrVal("/var/log/${var1.name}.log"), + })), + }), + })), + transpiler.NewKey("processors", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("add_fields", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("invalid", transpiler.NewStrVal("value")), + })), + })), + }), + })), + expected: transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("type", transpiler.NewStrVal("logfile")), + transpiler.NewKey("streams", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("paths", transpiler.NewList([]transpiler.Node{ + transpiler.NewStrVal("/var/log/value1.log"), + })), + }), + })), + transpiler.NewKey("processors", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("add_fields", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("invalid", transpiler.NewStrVal("value")), + })), + })), + }), + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("type", transpiler.NewStrVal("logfile")), + transpiler.NewKey("streams", transpiler.NewList([]transpiler.Node{ + transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("paths", transpiler.NewList([]transpiler.Node{ + transpiler.NewStrVal("/var/log/value2.log"), + })), + }), + })), + transpiler.NewKey("processors", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("add_fields", transpiler.NewDict([]transpiler.Node{ + transpiler.NewKey("invalid", transpiler.NewStrVal("value")), + })), + })), + }), + }), + varsArray: []*transpiler.Vars{ + mustMakeVarsP(map[string]interface{}{ + "var1": map[string]interface{}{ + "name": "value1", + }, + }, + "var1", + []map[string]interface{}{ + { + "add_fields": map[string]interface{}{ + "fields": map[string]interface{}{ + "custom": "value1", + }, + "to": "dynamic", + }, + }, + }), + mustMakeVarsP(map[string]interface{}{ + "var1": map[string]interface{}{ + "name": "value2", + }, + }, + "var1", + []map[string]interface{}{ + { + "add_fields": map[string]interface{}{ + "fields": map[string]interface{}{ + "custom": "value2", + }, + "to": "dynamic", + }, + }, + }), + }, + }, } for name, test := range testcases {