In this post we will review the steps to export and import kibana dashboards using Go code.
To handle these operation we will use a kibana config struct:
const configFolder = "config"
type KibanaConfig struct {
kibanaUrl string
elasticPassword string
}
func ProduceKibanaConfig(
kibanaUrl string,
elasticPassword string,
) *KibanaConfig {
return &KibanaConfig{
kibanaUrl: kibanaUrl,
elasticPassword: elasticPassword,
}
}
To export the dashboards, we send a request to list all dashboards, and then export them one by one.
func (k *KibanaConfig) ExportConfig() {
data := k.sendKibanaApiGet("/api/saved_objects/_find?type=dashboard")
var objects savedObjects
err := json.Unmarshal([]byte(data), &objects)
if err != nil {
panic(err)
}
for _, object := range objects.SavedObjects {
k.exportDashboard(object)
}
}
We keep methods to send GET and POST requests to kibana. The actual implementation is using Go net/http package, and is out of scope for this post.
func (k *KibanaConfig) sendKibanaApiGet(urlSuffix string) string {
webClient := web.CreateClient(0)
fullUrl := k.kibanaUrl + urlSuffix
headers := k.getHeaders()
var result string
webClient.Get(fullUrl, headers, &result)
return result
}
func (k *KibanaConfig) sendKibanaApiPost(
urlSuffix string,
headers map[string]string,
body interface{},
) string {
webClient := web.CreateClient(0)
fullUrl := k.kibanaUrl + urlSuffix
var result string
webClient.PostWithHeaders(fullUrl, body, headers, &result)
return result
}
We use the following structure to communicate with kibana:
type savedObjectAttributes struct {
Title string
}
type savedObject struct {
Id string
Attributes *savedObjectAttributes
}
type savedObjects struct {
SavedObjects []*savedObject `json:"saved_objects"`
}
For each of the dashboards, we get its details, and save it to a file.
func (k *KibanaConfig) exportDashboard(object *savedObject) {
title := object.Attributes.Title
body := exportBody{
Objects: []*exportObject{
{
Id: object.Id,
Type: "dashboard",
},
},
IncludeReferencesDeep: true,
}
headers := k.getHeaders()
data := k.sendKibanaApiPost("/api/saved_objects/_export", headers, &body)
outputPath := fmt.Sprintf("%v/%v.ndjson",
configFolder,
title,
)
err := os.WriteFile(outputPath, []byte(data), 0644)
if err != nil {
panic(err)
}
}
To import the dashboards to kibana we use the following method:
func listFolder(
folderPath string,
returnOnlyNames bool,
) []string {
files, err := os.ReadDir(folderPath)
if err != nil {
panic(err)
}
result := make([]string, 0)
for _, file := range files {
if returnOnlyNames {
result = append(result, file.Name())
} else {
result = append(result, folderPath+"/"+file.Name())
}
}
return result
}
func (k *KibanaConfig) ImportConfig() {
for _, filePath := range listFolder(configFolder, false) {
k.importDashboard(filePath)
}
}
The actual import uses form data to send the file.
func (k *KibanaConfig) importDashboard(filePath string) {
file, _ := os.Open(filePath)
defer func() {
err := file.Close()
if err != nil {
panic(err)
}
}()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", filepath.Base(file.Name()))
_, err := io.Copy(part, file)
if err != nil {
panic(err)
}
err = writer.Close()
if err != nil {
panic(err)
}
headers := k.getHeaders()
headers["Content-Type"] = writer.FormDataContentType()
k.sendKibanaApiPost("/api/saved_objects/_import?overwrite=true", headers, body)
}
Final Note
Once all is implemented, the usage is simple. To export the configuration, we use:
config := kibanaconfig.ProduceKibanaConfig(request.KibanaUrl, request.ElasticPassword)
config.ExportConfig()
And to import the configuration we use the following:
config := kibanaconfig.ProduceKibanaConfig(request.KibanaUrl, request.ElasticPassword)
config.ImportConfig()
No comments:
Post a Comment