From 7d72fbfc4f7ce43053e0ad6aced92eb397f1f658 Mon Sep 17 00:00:00 2001 From: Jaime Soriano Pastor Date: Fri, 10 Aug 2018 09:09:40 +0200 Subject: [PATCH] Replace index patterns in TSVB visualizations (#7929) (#7932) When customizing the index pattern with `setup.dashboards.index`, references to index patterns need to be replaced in imported dashboards. It was not being done with objects that contain the index pattern in the `visState` object, as is the case of TSVB visualizations. (cherry picked from commit 7a8a476bda573f87cb196a7bf1057844acaff81b) --- CHANGELOG.asciidoc | 3 +- libbeat/dashboards/es_loader.go | 5 +- libbeat/dashboards/modify_json.go | 104 ++++++++++++++++++------- libbeat/dashboards/modify_json_test.go | 42 ++++++++++ 4 files changed, 124 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 795e36d6e6f7..94ae15e64d6c 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -38,7 +38,8 @@ https://github.com/elastic/beats/compare/v6.4.0...6.4[Check the HEAD diff] - Fix potential data loss on OS X in spool file by using fcntl with F_FULLFSYNC. {pull}7859[7859] - Improve fsync on linux, by assuming the kernel resets error flags of failed writes. {pull}7859[7859] - Remove unix-like permission checks on Windows, so files can be opened. {issue}7849[7849] -- Deregister pipeline loader callback when inputsRunner is stopped. {pull}[7893][7893] +- Deregister pipeline loader callback when inputsRunner is stopped. {pull}7893[7893] +- Replace index patterns in TSVB visualizations. {pull}7929[7929] *Auditbeat* diff --git a/libbeat/dashboards/es_loader.go b/libbeat/dashboards/es_loader.go index 95b0415cd89a..270e2f26dd0a 100644 --- a/libbeat/dashboards/es_loader.go +++ b/libbeat/dashboards/es_loader.go @@ -217,9 +217,12 @@ func (loader ElasticsearchLoader) importVisualization(file string) error { if loader.config.Index != "" { if savedObject, ok := vizContent["kibanaSavedObjectMeta"].(map[string]interface{}); ok { - vizContent["kibanaSavedObjectMeta"] = ReplaceIndexInSavedObject(loader.config.Index, savedObject) } + + if visState, ok := vizContent["visState"].(string); ok { + vizContent["visState"] = ReplaceIndexInVisState(loader.config.Index, visState) + } } vizName := strings.TrimSuffix(filepath.Base(file), filepath.Ext(file)) diff --git a/libbeat/dashboards/modify_json.go b/libbeat/dashboards/modify_json.go index be31fa8b84a4..f844a0bb19bc 100644 --- a/libbeat/dashboards/modify_json.go +++ b/libbeat/dashboards/modify_json.go @@ -42,24 +42,29 @@ type JSONFormat struct { } func ReplaceIndexInIndexPattern(index string, content common.MapStr) common.MapStr { + if index == "" { + return content + } + + objects, ok := content["objects"].([]interface{}) + if !ok { + return content + } + + // change index pattern name + for i, object := range objects { + objectMap, ok := object.(map[string]interface{}) + if !ok { + continue + } - if index != "" { - // change index pattern name - if objects, ok := content["objects"].([]interface{}); ok { - for i, object := range objects { - if objectMap, ok := object.(map[string]interface{}); ok { - objectMap["id"] = index - - if attributes, ok := objectMap["attributes"].(map[string]interface{}); ok { - attributes["title"] = index - objectMap["attributes"] = attributes - } - objects[i] = objectMap - } - } - content["objects"] = objects + objectMap["id"] = index + if attributes, ok := objectMap["attributes"].(map[string]interface{}); ok { + attributes["title"] = index } + objects[i] = objectMap } + content["objects"] = objects return content } @@ -97,28 +102,71 @@ func ReplaceIndexInSavedObject(index string, kibanaSavedObject map[string]interf return kibanaSavedObject } -func ReplaceIndexInDashboardObject(index string, content common.MapStr) common.MapStr { +// ReplaceIndexInVisState replaces index appearing in visState params objects +func ReplaceIndexInVisState(index string, visStateJSON string) string { + + var visState map[string]interface{} + err := json.Unmarshal([]byte(visStateJSON), &visState) + if err != nil { + logp.Err("Fail to unmarshal visState: %v", err) + return visStateJSON + } + + params, ok := visState["params"].(map[string]interface{}) + if !ok { + return visStateJSON + } + + // Don't set it if it was not set before + if pattern, ok := params["index_pattern"].(string); !ok || len(pattern) == 0 { + return visStateJSON + } + params["index_pattern"] = index + + d, err := json.Marshal(visState) + if err != nil { + logp.Err("Fail to marshal visState: %v", err) + return visStateJSON + } + + return string(d) +} + +// ReplaceIndexInDashboardObject replaces references to the index pattern in dashboard objects +func ReplaceIndexInDashboardObject(index string, content common.MapStr) common.MapStr { if index == "" { return content } - if objects, ok := content["objects"].([]interface{}); ok { - for i, object := range objects { - if objectMap, ok := object.(map[string]interface{}); ok { - if attributes, ok := objectMap["attributes"].(map[string]interface{}); ok { - if kibanaSavedObject, ok := attributes["kibanaSavedObjectMeta"].(map[string]interface{}); ok { + objects, ok := content["objects"].([]interface{}) + if !ok { + return content + } + + for i, object := range objects { + objectMap, ok := object.(map[string]interface{}) + if !ok { + continue + } + + attributes, ok := objectMap["attributes"].(map[string]interface{}) + if !ok { + continue + } - attributes["kibanaSavedObjectMeta"] = ReplaceIndexInSavedObject(index, kibanaSavedObject) - } + if kibanaSavedObject, ok := attributes["kibanaSavedObjectMeta"].(map[string]interface{}); ok { + attributes["kibanaSavedObjectMeta"] = ReplaceIndexInSavedObject(index, kibanaSavedObject) + } - objectMap["attributes"] = attributes - } - objects[i] = objectMap - } + if visState, ok := attributes["visState"].(string); ok { + attributes["visState"] = ReplaceIndexInVisState(index, visState) } - content["objects"] = objects + + objects[i] = objectMap } + content["objects"] = objects + return content } diff --git a/libbeat/dashboards/modify_json_test.go b/libbeat/dashboards/modify_json_test.go index 5855bec350d6..6874c5ba1943 100644 --- a/libbeat/dashboards/modify_json_test.go +++ b/libbeat/dashboards/modify_json_test.go @@ -69,3 +69,45 @@ func TestReplaceStringInDashboard(t *testing.T) { assert.Equal(t, test.expected, result) } } + +func TestReplaceIndexInDashboardObject(t *testing.T) { + tests := []struct { + dashboard common.MapStr + pattern string + expected common.MapStr + }{ + { + common.MapStr{"objects": []interface{}{map[string]interface{}{ + "attributes": map[string]interface{}{ + "kibanaSavedObjectMeta": map[string]interface{}{ + "searchSourceJSON": "{\"index\":\"metricbeat-*\"}", + }, + }}}}, + "otherindex-*", + common.MapStr{"objects": []interface{}{map[string]interface{}{ + "attributes": map[string]interface{}{ + "kibanaSavedObjectMeta": map[string]interface{}{ + "searchSourceJSON": "{\"index\":\"otherindex-*\"}", + }, + }}}}, + }, + { + common.MapStr{"objects": []interface{}{map[string]interface{}{ + "attributes": map[string]interface{}{ + "kibanaSavedObjectMeta": map[string]interface{}{}, + "visState": "{\"params\":{\"index_pattern\":\"metricbeat-*\"}}", + }}}}, + "otherindex-*", + common.MapStr{"objects": []interface{}{map[string]interface{}{ + "attributes": map[string]interface{}{ + "kibanaSavedObjectMeta": map[string]interface{}{}, + "visState": "{\"params\":{\"index_pattern\":\"otherindex-*\"}}", + }}}}, + }, + } + + for _, test := range tests { + result := ReplaceIndexInDashboardObject(test.pattern, test.dashboard) + assert.Equal(t, test.expected, result) + } +}