Skip to content

Commit

Permalink
Add support to export dashboard to Beat (#7239)
Browse files Browse the repository at this point in the history
Currently to export a Dashboard from the Kibana exporter API it has to be done manually or the Beats repository must be used. To simplify the exporting of own dashboards the command `beat export dashboard --id="dashboard-id"` is added. This should allow all users to export their own dashboards.

The output is written to stdout, so the expected usage is to pipe it into a file inside the `kibana/dashboards/6` directory.

For the Kibana connection settings it uses the setting from `setup.kibana.*`. If none are set it uses the defaults.
  • Loading branch information
ruflin authored and jsoriano committed Jun 4, 2018
1 parent 7b5a7e4 commit ccd36fb
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ https://github.com/elastic/beats/compare/v6.2.3...master[Check the HEAD diff]
- Add support for keyword multifields in field.yml. {pull}7131[7131]
- Add dissect processor. {pull}6925[6925]
- Add owner object info to Kubernetes metadata. {pull}7231[7231]
- Add beat export dashboard command. {pull}7239[7239]

*Auditbeat*

Expand Down
1 change: 1 addition & 0 deletions libbeat/cmd/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func genExportCmd(name, idxPrefix, beatVersion string) *cobra.Command {

exportCmd.AddCommand(export.GenExportConfigCmd(name, idxPrefix, beatVersion))
exportCmd.AddCommand(export.GenTemplateConfigCmd(name, idxPrefix, beatVersion))
exportCmd.AddCommand(export.GenDashboardCmd(name, idxPrefix, beatVersion))

return exportCmd
}
56 changes: 56 additions & 0 deletions libbeat/cmd/export/dashboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package export

import (
"fmt"
"os"

"github.com/spf13/cobra"

"github.com/elastic/beats/libbeat/cmd/instance"
"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/kibana"
)

// GenDashboardCmd is the command used to export a dashboard.
func GenDashboardCmd(name, idxPrefix, beatVersion string) *cobra.Command {
genTemplateConfigCmd := &cobra.Command{
Use: "dashboard",
Short: "Export defined dashboard to stdout",
Run: func(cmd *cobra.Command, args []string) {
dashboard, _ := cmd.Flags().GetString("id")

b, err := instance.NewBeat(name, idxPrefix, beatVersion)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating beat: %s\n", err)
os.Exit(1)
}
err = b.Init()
if err != nil {
fmt.Fprintf(os.Stderr, "Error initializing beat: %s\n", err)
os.Exit(1)
}

// Use empty config to use default configs if not set
if b.Config.Kibana == nil {
b.Config.Kibana = common.NewConfig()
}

client, err := kibana.NewKibanaClient(b.Config.Kibana)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating Kibana client: %+v\n", err)
os.Exit(1)
}

result, err := client.GetDashboard(dashboard)
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting dashboard: %+v\n", err)
os.Exit(1)
}
fmt.Println(result.StringToPrint())
},
}

genTemplateConfigCmd.Flags().String("id", "", "Dashboard id")

return genTemplateConfigCmd
}
16 changes: 16 additions & 0 deletions libbeat/kibana/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,22 @@ func (client *Client) ImportJSON(url string, params url.Values, jsonBody map[str

func (client *Client) Close() error { return nil }

// GetDashboard returns the dashboard with the given id with the index pattern removed
func (client *Client) GetDashboard(id string) (common.MapStr, error) {
params := url.Values{}
params.Add("dashboard", id)
_, response, err := client.Request("GET", "/api/kibana/dashboards/export", params, nil, nil)
if err != nil {
return nil, fmt.Errorf("error exporting dashboard: %+v", err)
}

result, err := RemoveIndexPattern(response)
if err != nil {
return nil, fmt.Errorf("error removing index pattern: %+v", err)
}
return result, nil
}

// truncateString returns a truncated string if the length is greater than 250
// runes. If the string is truncated "... (truncated)" is appended. Newlines are
// replaced by spaces in the returned string.
Expand Down
47 changes: 47 additions & 0 deletions libbeat/kibana/dashboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package kibana

import (
"encoding/json"
"fmt"

"github.com/elastic/beats/libbeat/common"
)

// RemoveIndexPattern removes the index pattern entry from a given dashboard export
func RemoveIndexPattern(data []byte) (common.MapStr, error) {

var kbResult struct {
// Has to be defined as interface instead of Type directly as it has to be assigned again
// and otherwise would not contain the full content.
Objects []interface{}
}

var result common.MapStr
// Full struct need to not loose any data
err := json.Unmarshal(data, &result)
if err != nil {
return nil, err
}

// For easier handling, unmarshal into predefined struct
err = json.Unmarshal(data, &kbResult)
if err != nil {
return nil, err
}

var objs []interface{}

for _, obj := range kbResult.Objects {
t, ok := obj.(map[string]interface{})["type"].(string)
if !ok {
return nil, fmt.Errorf("type key not found or not string")
}
if t != "index-pattern" {
objs = append(objs, obj)
}
}

result["objects"] = objs

return result, nil
}

0 comments on commit ccd36fb

Please sign in to comment.