Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Commit a8ac059

Browse files
trzysieknablaonemieciupdelewski
authored
Parser to exported dashboard json (#374)
Co-authored-by: Rafał Strzaliński <[email protected]> Co-authored-by: przemyslaw <[email protected]> Co-authored-by: Przemek Delewski <[email protected]>
1 parent 3602087 commit a8ac059

File tree

17 files changed

+1435
-0
lines changed

17 files changed

+1435
-0
lines changed

bin/unjson-dashboards/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
dashboards/*.ndjson
2+
mappings/*.json
3+
screenshots/*.png
4+

bin/unjson-dashboards/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[INTERNAL ONLY] Checking how Quesma MVP works with provided Kibana dashboards
2+
======================================================================
3+
4+
:warning: **This is an internal-only document.** Despite our open-source DNA, procedures described here cannot be replayed
5+
without access to internal resources.
6+
7+
8+
Let's say someone provided you with some Kibana dashboards exported as NDJSON files.
9+
10+
1. Place dashboard json files in `bin/unjson-dashboards/dashboards`
11+
2. Run `local-dev-chrome.yml` docker compose file from `quesma-examples` repository (private repo)
12+
3. Open `bin/unjson-dashboards/main.go` in your IDE \
13+
We will be running steps by changing `if` statement condition in that file and running go program.
14+
15+
There are 4 stages there:
16+
* `extractMappings()` - figures out indices/mappings from the dashboards and writes them to `bin/unjson-dashboards/mappings` directory
17+
* `ingestAll()` - generates some test data according to the mappings and ingests it using Elasticsearch API to ClickHouse via Quesma
18+
* `createDataViews()/importDashboards()` - creates relevant data views in Kibana
19+
* `visitDashboards()` - opens headless chrome which makes screenshot of these dashboards, saves them in `bin/unjson-dashboards/screenshots` and adds `index.html` so that these can be browsed in a convenient manner.

bin/unjson-dashboards/const.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright Quesma, licensed under the Elastic License 2.0.
2+
// SPDX-License-Identifier: Elastic-2.0
3+
package main
4+
5+
const (
6+
kibanaURL = "http://localhost:5601" // Update this with your Kibana URL
7+
kibanaSpace = "default" // Change if using a specific space
8+
apiKey = "" // Add API key if required
9+
ndjsonFolder = "dashboards" // Directory containing NDJSON files
10+
dashboardListEndpoint = "/api/saved_objects/_find?type=dashboard&per_page=10000"
11+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Place your dashboards in this directory.

bin/unjson-dashboards/dataviews.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright Quesma, licensed under the Elastic License 2.0.
2+
// SPDX-License-Identifier: Elastic-2.0
3+
package main
4+
5+
import (
6+
"bytes"
7+
"encoding/json"
8+
"fmt"
9+
"log"
10+
"net/http"
11+
)
12+
13+
func createDataViews() {
14+
15+
indexes, err := readIndexMappings()
16+
if err != nil {
17+
log.Fatalf("Error reading index mappings: %v", err)
18+
}
19+
20+
for _, index := range indexes {
21+
22+
var timestampField string
23+
for field, mapping := range index.Properties {
24+
25+
if mapping.Type == "date" {
26+
timestampField = field
27+
break
28+
}
29+
}
30+
31+
err = CreateDataView(index.Pattern, timestampField)
32+
if err != nil {
33+
log.Printf("Failed to create Data View: %v", err)
34+
}
35+
36+
}
37+
38+
}
39+
40+
type DataViewRequest struct {
41+
Attributes struct {
42+
Title string `json:"title"` // Index pattern name
43+
TimeFieldName string `json:"timeFieldName,omitempty"` // Optional time field
44+
} `json:"attributes"`
45+
}
46+
47+
// CreateDataView creates a new Data View (Index Pattern) in Kibana
48+
func CreateDataView(dataViewName string, timeField string) error {
49+
// Construct the API URL
50+
url := "http://localhost:5601/api/saved_objects/index-pattern"
51+
52+
// Create the request payload
53+
payload := DataViewRequest{}
54+
payload.Attributes.Title = dataViewName
55+
if timeField != "" {
56+
payload.Attributes.TimeFieldName = timeField
57+
}
58+
59+
// Convert to JSON
60+
jsonData, err := json.Marshal(payload)
61+
if err != nil {
62+
return fmt.Errorf("failed to marshal JSON: %v", err)
63+
}
64+
65+
// Create HTTP request
66+
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
67+
if err != nil {
68+
return fmt.Errorf("failed to create request: %v", err)
69+
}
70+
71+
// Set headers
72+
req.Header.Set("Content-Type", "application/json")
73+
req.Header.Set("kbn-xsrf", "true") // Required to bypass CSRF protection
74+
75+
// Execute the request
76+
client := &http.Client{}
77+
resp, err := client.Do(req)
78+
if err != nil {
79+
return fmt.Errorf("failed to send request: %v", err)
80+
}
81+
defer resp.Body.Close()
82+
83+
// Check response status
84+
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
85+
return fmt.Errorf("failed to create Data View, status: %d", resp.StatusCode)
86+
}
87+
88+
log.Printf("✅ Successfully created Data View: %s", dataViewName)
89+
return nil
90+
}

0 commit comments

Comments
 (0)