diff --git a/x-pack/elastic-agent/CHANGELOG.asciidoc b/x-pack/elastic-agent/CHANGELOG.asciidoc index d3fd7758e166..35f2003ba113 100644 --- a/x-pack/elastic-agent/CHANGELOG.asciidoc +++ b/x-pack/elastic-agent/CHANGELOG.asciidoc @@ -39,7 +39,8 @@ - Remove fleet admin from setup script {pull}18611[18611] - Correctly report platform and family. {issue}18665[18665] - Clean action store after enrolling to new configuration {pull}18656[18656] - [Ingest Manager] Avoid watching monitor logs {pull}18723[18723] +- Avoid watching monitor logs {pull}18723[18723] +- Guard against empty stream.datasource and namespace {pull}18769[18769] ==== New features diff --git a/x-pack/elastic-agent/pkg/agent/program/supported.go b/x-pack/elastic-agent/pkg/agent/program/supported.go index ca70abd8771a..64463ce29c30 100644 --- a/x-pack/elastic-agent/pkg/agent/program/supported.go +++ b/x-pack/elastic-agent/pkg/agent/program/supported.go @@ -19,7 +19,7 @@ func init() { // Packed Files // spec/filebeat.yml // spec/metricbeat.yml - unpacked := packer.MustUnpack("eJzsWF9zs7j1vv99jNz+Oi2I15mlM3thyCLADnmNE0noDkkOYEuYDdgYOv3uHWHjf8m73W2nN51excZHOv+e85yH/O2hrlb8L++FXLFV2vy5U/Lhrw9MeQ193WaxkjXFoUzIYpYAc/NSOCrFB5kolItplXMl+pfCYUFhekHRZkEZSeGjdq5kzZYTyZRXMIg23zHNmR/JwebetowlI06dkFjOFdolOKwpXthUeTUHb8XcnRbzt+Nfhr1dgoVkGO2EO2kYiOV3kjUceuu0MxWDSAo3qAM3aOKl/hs2CZ7kFKCG4olxfb/wQ5Mub2xrBkSZ4kk5VwcpFKq/41gmJSoDacwSYO+okqUgYZ6og3wpnJKXztotQ5NB1L9k2yaAcpcqtBaeXTEVy9XTdha40yzw4wmHb48BPOyp9TxzCyNL8eRXiiODWJHBFcoZsluu7DUlUc+s4NEtplngOnsm7TUDE8WgXIunrT7XUxIaBHhKQNSd7IwVcXRMOofeHWJB34Qf5okVvzMoex2TgKjh/RiTkwuYPQYwzgX0emahLgGoP9032L4UTsVKxxT+85jH/vIs6oUfygSbJ39mzp/u75Y77iODjzmS8Z5zzTL9fb501sxyJgR4NfNsg5l2nZLIGH+/8n3xWUzPvzEweT/251Al1uIxgJM9s6az81nXkSsYSe4vHgOvLrgVdxR7De+Gvld0wEx4xusRn07HQCS5Fe15+VyQxV2sVrwn4FBxa/F4HUtKYsletxn3w72uJwd2x9t/NQ+54wB1wrMLiumeq7fZH+vtD+oPpUGx8Rj493257u8Rpwx77dgHDj0jPWKwFSQesdIJfJBn366R6dhYGQ0zfdvDU1zHebjuT5MQp6UkuKll4B7xfMQ1v7LXOSAwzDSgFRtn67rO7jSjhEpWLvbcijcp/jbkS6Hc3fnQs74Trm0k1lTHtubTr+8ROG5fCsek/vQulsOedvaGgehD5xDAeJ+ARvLs9h4G7XJuhZJC2RMrqpkldF6PgX989jl3vueW7PU5jZkViYY6HDFAK+bHkksbJPhgUvI8ckZPNUdb8Z6vP/Xqg5LNbf19zc3opn/a3ymW5q5mTeCjzVif+dLRNTufo9Bep2DkJG17k5e+a8LBpU/zpdM/Xz7vKIkVg7Z1toe5IXznVw7si3/4Ux+tUS5wXIlLHPmqRB3FR0ykPiou9rrOaEOVbTIVd6vLHJcM2CWDqBU47AUOznmkwFMp+GXAP1Wy1jxLrLs6+ZFkEK0FtLtPPAkbuXrdZhRPhl1BT3EK5dUC3/CewUskj/2M9tzfjD1UXNk/4t+rHbydzZfDd+MyO1f9L0dMTI94gaig2DMuz2xT+I55VccPSmSvc6KLykoh2r0UTpCQKBz4pcvkymwu/t3JuAvE+3KThUWSLaHXv2r9QKI2wZGcuWIvSNwKsijn7rSk+JBzK64SK5IJCdepy+vAFR3FccU7XuvYQtDkVDV52LVZqPFiRUZCom3YbWYPfzpKFrVqPgr+hWh5xcjgSq5PImXNsCZSUwo/rBJwEjMkLHm/zXB3Xv49JbHJdULQ2J0b92SqBB/6O6Ew2hoUmy2DnkH/mdhRZs6UV1JsaiLZMWxv6Kv5bU6cPAF1Q7UvsvgtsXO5n8SdwHfCCNolBXJHu0k9kNWTuaE4NGkXCldFe6ZoRfWC1+JHA9MK26StWmZFBgFyx604Z7AdwDJfOg2zqCQnYj2T0kjebqiF17DA52oxEJQGx7yUDXODMzEK6HUUIOOl0LnYm2FJdJPN3Iom3IolW04mDLc7TRAnUVb8MTF16ul/VlA1lMRdiqP/iar/ZlGliZ7kBleexttQJwK0SDL7H4mfc76nOM4x3j0X8KdLz9prwg7fx4VALFEJmL9zhUpK8rPgSgGavBRHLI5iS88vKb59zMEZ/5vfXPz/rliA55emHwqG4WVqMeTWJGQ63t0mJN5+xvsnnOq67zg45AKidwGkkXp2R7GQK396g4OxB8KXLV1c9z/Us7qaPdmL70d++P95UVefa3TiJu3jaZuFN0LUyPjwgmjeilZIOwaMr0SrwfptNnLbZamaeQrQe0LCLiGbL3HMTjuKA2TcxDVgZYxZvyA/X8d24uVBXFzHcerT1bnLQu8oNvdCofcBSzd5fS1SftcZ6OmFLE8CZJjd0Y6W4V7neIelU62ud/NwttP+GX67Fz4j7w6CZa7O83Ndpz31UU3J841QO88rQLXeB8wKr7F2c+/vE0LbmQC5ZOvtIG6WuofkeRuSht3kc/yHxIBtQowqcBMV/JLn3ND5oZ5Db02XWcksZOhcjuIG1QmJDL1fKPa6BGTlfIjhIogCV3wkmH4ky+Hz8EKkd0vq8srNfv754e//948AAAD//7sC+54=") + unpacked := packer.MustUnpack("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") SupportedMap = make(map[string]bool) for f, v := range unpacked { diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/constraints_config-filebeat.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/constraints_config-filebeat.yml index 20e08dbdd7ed..a620d40de2e5 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/constraints_config-filebeat.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/constraints_config-filebeat.yml @@ -4,6 +4,7 @@ filebeat: paths: - /var/log/hello1.log - /var/log/hello2.log + dataset: generic index: logs-generic-default processors: - add_fields: diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_output_true-filebeat.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_output_true-filebeat.yml index 26d5dfdca2f7..71c959208293 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_output_true-filebeat.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_output_true-filebeat.yml @@ -4,6 +4,7 @@ filebeat: paths: - /var/log/hello1.log - /var/log/hello2.log + dataset: generic index: logs-generic-default processors: - add_fields: diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_true-filebeat.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_true-filebeat.yml index feac81692f76..176df2f76753 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_true-filebeat.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/enabled_true-filebeat.yml @@ -5,6 +5,7 @@ filebeat: paths: - /var/log/hello1.log - /var/log/hello2.log + dataset: generic index: logs-generic-default processors: - add_fields: diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-filebeat.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-filebeat.yml index 54604b76801c..442457c5dc13 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-filebeat.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-filebeat.yml @@ -5,6 +5,7 @@ filebeat: - /var/log/hello1.log - /var/log/hello2.log index: logs-generic-default + dataset: generic vars: var: value processors: diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-metricbeat.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-metricbeat.yml index 6342d2b54260..af734fb28d86 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-metricbeat.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config-metricbeat.yml @@ -11,6 +11,17 @@ metricbeat: type: metrics dataset: docker.status namespace: default + - module: docker + metricsets: [info] + index: metrics-generic-default + hosts: ["http://127.0.0.1:8080"] + processors: + - add_fields: + target: "stream" + fields: + type: metrics + dataset: generic + namespace: default - module: apache metricsets: [info] index: metrics-generic-testing diff --git a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config.yml b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config.yml index bcf158e74d6d..d84687cf98ba 100644 --- a/x-pack/elastic-agent/pkg/agent/program/testdata/single_config.yml +++ b/x-pack/elastic-agent/pkg/agent/program/testdata/single_config.yml @@ -26,6 +26,8 @@ datasources: streams: - metricset: status dataset: docker.status + - metricset: info + dataset: "" hosts: ["http://127.0.0.1:8080"] - type: logs streams: diff --git a/x-pack/elastic-agent/pkg/agent/transpiler/rules.go b/x-pack/elastic-agent/pkg/agent/transpiler/rules.go index 1b6a2c56cab3..4554912e066a 100644 --- a/x-pack/elastic-agent/pkg/agent/transpiler/rules.go +++ b/x-pack/elastic-agent/pkg/agent/transpiler/rules.go @@ -75,7 +75,8 @@ func (r *RuleList) MarshalYAML() (interface{}, error) { name = "make_array" case *RemoveKeyRule: name = "remove_key" - + case *FixStreamRule: + name = "fix_stream" default: return nil, fmt.Errorf("unknown rule of type %T", rule) } @@ -153,6 +154,8 @@ func (r *RuleList) UnmarshalYAML(unmarshal func(interface{}) error) error { r = &MakeArrayRule{} case "remove_key": r = &RemoveKeyRule{} + case "fix_stream": + r = &FixStreamRule{} default: return fmt.Errorf("unknown rule of type %s", name) } @@ -345,6 +348,100 @@ func CopyAllToList(to, onMerge string, except ...string) *CopyAllToListRule { } } +// FixStreamRule fixes streams to contain default values +// in case no value or invalid value are provided +type FixStreamRule struct { +} + +// Apply stream fixes. +func (r *FixStreamRule) Apply(ast *AST) error { + const defaultNamespace = "default" + const defaultDataset = "generic" + + datasourcesNode, found := Lookup(ast, "datasources") + if !found { + return nil + } + + datasourcesList, ok := datasourcesNode.Value().(*List) + if !ok { + return nil + } + + for _, datasourceNode := range datasourcesList.value { + nsNode, found := datasourceNode.Find("namespace") + if found { + nsKey, ok := nsNode.(*Key) + if ok { + if newNamespace := nsKey.value.String(); newNamespace == "" { + nsKey.value = &StrVal{value: defaultNamespace} + } + } + } else { + datasourceMap, ok := datasourceNode.(*Dict) + if !ok { + continue + } + datasourceMap.value = append(datasourceMap.value, &Key{ + name: "namespace", + value: &StrVal{value: defaultNamespace}, + }) + } + + // get input + inputNode, found := datasourceNode.Find("inputs") + if !found { + continue + } + + inputsList, ok := inputNode.Value().(*List) + if !ok { + continue + } + + for _, inputNode := range inputsList.value { + streamsNode, ok := inputNode.Find("streams") + if !ok { + continue + } + + streamsList, ok := streamsNode.Value().(*List) + if !ok { + continue + } + + for _, streamNode := range streamsList.value { + streamMap, ok := streamNode.(*Dict) + if !ok { + continue + } + + dsNode, found := streamNode.Find("dataset") + if found { + dsKey, ok := dsNode.(*Key) + if ok { + if newDataset := dsKey.value.String(); newDataset == "" { + dsKey.value = &StrVal{value: defaultDataset} + } + } + } else { + streamMap.value = append(streamMap.value, &Key{ + name: "dataset", + value: &StrVal{value: defaultDataset}, + }) + } + } + } + } + + return nil +} + +// FixStream creates a FixStreamRule +func FixStream() *FixStreamRule { + return &FixStreamRule{} +} + // InjectIndexRule injects index to each input. // Index is in form {type}-{namespace}-{dataset-type} // type: is provided to the rule. @@ -375,7 +472,9 @@ func (r *InjectIndexRule) Apply(ast *AST) error { if found { nsKey, ok := nsNode.(*Key) if ok { - namespace = nsKey.value.String() + if newNamespace := nsKey.value.String(); newNamespace != "" { + namespace = newNamespace + } } } @@ -413,7 +512,9 @@ func (r *InjectIndexRule) Apply(ast *AST) error { if found { dsKey, ok := dsNode.(*Key) if ok { - dataset = dsKey.value.String() + if newDataset := dsKey.value.String(); newDataset != "" { + dataset = newDataset + } } } @@ -464,7 +565,9 @@ func (r *InjectStreamProcessorRule) Apply(ast *AST) error { if found { nsKey, ok := nsNode.(*Key) if ok { - namespace = nsKey.value.String() + if newNamespace := nsKey.value.String(); newNamespace != "" { + namespace = newNamespace + } } } @@ -502,7 +605,9 @@ func (r *InjectStreamProcessorRule) Apply(ast *AST) error { if found { dsKey, ok := dsNode.(*Key) if ok { - dataset = dsKey.value.String() + if newDataset := dsKey.value.String(); newDataset != "" { + dataset = newDataset + } } } diff --git a/x-pack/elastic-agent/pkg/agent/transpiler/rules_test.go b/x-pack/elastic-agent/pkg/agent/transpiler/rules_test.go index 2fc9fedd20f2..6da73a3dd05a 100644 --- a/x-pack/elastic-agent/pkg/agent/transpiler/rules_test.go +++ b/x-pack/elastic-agent/pkg/agent/transpiler/rules_test.go @@ -22,6 +22,86 @@ func TestRules(t *testing.T) { expectedYAML string rule Rule }{ + "fix streams": { + givenYAML: ` +datasources: + - name: All default + inputs: + - type: file + streams: + - paths: /var/log/mysql/error.log + - name: Specified namespace + namespace: nsns + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + - name: Specified dataset + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + dataset: dsds + - name: All specified + namespace: nsns + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + dataset: dsds + - name: All specified with empty strings + namespace: "" + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + dataset: "" +`, + expectedYAML: ` +datasources: + - name: All default + namespace: default + inputs: + - type: file + streams: + - paths: /var/log/mysql/error.log + dataset: generic + - name: Specified namespace + namespace: nsns + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + dataset: generic + - name: Specified dataset + namespace: default + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + dataset: dsds + - name: All specified + namespace: nsns + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + dataset: dsds + - name: All specified with empty strings + namespace: default + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + dataset: generic +`, + rule: &RuleList{ + Rules: []Rule{ + FixStream(), + }, + }, + }, + "inject index": { givenYAML: ` datasources: @@ -49,6 +129,13 @@ datasources: streams: - paths: /var/log/mysql/access.log dataset: dsds + - name: All specified with empty strings + namespace: "" + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + dataset: "" `, expectedYAML: ` datasources: @@ -80,6 +167,14 @@ datasources: - paths: /var/log/mysql/access.log dataset: dsds index: mytype-dsds-nsns + - name: All specified with empty strings + namespace: "" + inputs: + - type: file + streams: + - paths: /var/log/mysql/access.log + dataset: "" + index: mytype-generic-default `, rule: &RuleList{ Rules: []Rule{ @@ -564,6 +659,7 @@ func TestSerialization(t *testing.T) { InjectStreamProcessor("insert_after", "index-type"), CopyToList("t1", "t2", "insert_after"), CopyAllToList("t2", "insert_before", "a", "b"), + FixStream(), ) y := `- rename: @@ -623,6 +719,7 @@ func TestSerialization(t *testing.T) { - a - b on_conflict: insert_before +- fix_stream: {} ` t.Run("serialize_rules", func(t *testing.T) { diff --git a/x-pack/elastic-agent/spec/filebeat.yml b/x-pack/elastic-agent/spec/filebeat.yml index 0ed7bd422d43..ab4d7e96cba1 100644 --- a/x-pack/elastic-agent/spec/filebeat.yml +++ b/x-pack/elastic-agent/spec/filebeat.yml @@ -3,6 +3,7 @@ cmd: filebeat args: ["-E", "setup.ilm.enabled=false", "-E", "setup.template.enabled=false", "-E", "management.mode=x-pack-fleet", "-E", "management.enabled=true", "-E", "logging.level=debug"] configurable: grpc rules: +- fix_stream: {} - inject_index: type: logs diff --git a/x-pack/elastic-agent/spec/metricbeat.yml b/x-pack/elastic-agent/spec/metricbeat.yml index 3dc7f6507d54..ca244027f85f 100644 --- a/x-pack/elastic-agent/spec/metricbeat.yml +++ b/x-pack/elastic-agent/spec/metricbeat.yml @@ -7,6 +7,7 @@ post_install: path: "modules.d/system.yml" target: "modules.d/system.yml.disabled" rules: +- fix_stream: {} - inject_index: type: metrics