Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 75 additions & 9 deletions internal/builder/dashboards.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ import (
"github.com/elastic/elastic-package/internal/common"
)

const (
panelsAttribute = "attributes.panelsJSON"
embeddableConfigAttribute = "embeddableConfig"
)

var fieldsToEncode = []string{
"attributes.controlGroupInput.ignoreParentSettingsJSON",
"attributes.controlGroupInput.panelsJSON",
"attributes.kibanaSavedObjectMeta.searchSourceJSON",
"attributes.layerListJSON",
"attributes.mapStateJSON",
"attributes.optionsJSON",
"attributes.panelsJSON",
"attributes.uiStateJSON",
"attributes.visState",
panelsAttribute,
}

func encodeDashboards(destinationDir string) error {
Expand All @@ -29,14 +36,13 @@ func encodeDashboards(destinationDir string) error {
return err
}
for _, file := range savedObjects {

data, err := os.ReadFile(file)
if err != nil {
return err
}
output, changed, err := encodedSavedObject(data)
output, changed, err := encodeSavedObject(data)
if err != nil {
return err
return fmt.Errorf("encoding %s: %w", file, err)
}

if changed {
Expand All @@ -53,16 +59,28 @@ func encodeDashboards(destinationDir string) error {
// which are stored in encoded JSON in Kibana.
// The reason is that for versioning it is much nicer to have the full
// json so only on packaging this is changed.
func encodedSavedObject(data []byte) ([]byte, bool, error) {
func encodeSavedObject(data []byte) ([]byte, bool, error) {
savedObject := common.MapStr{}
err := json.Unmarshal(data, &savedObject)
if err != nil {
return nil, false, fmt.Errorf("unmarshalling saved object failed: %w", err)
}

var changed bool
object, changed, err := encodeObjectMapStr(savedObject)
if err != nil {
return nil, false, err
}

return []byte(object.StringToPrint()), changed, nil
}

func encodeObjectMapStr(object common.MapStr) (common.MapStr, bool, error) {
object, changed, err := encodeEmbeddedPanels(object)
if err != nil {
return nil, false, err
}
for _, v := range fieldsToEncode {
out, err := savedObject.GetValue(v)
out, err := object.GetValue(v)
// This means the key did not exists, no conversion needed.
if err != nil {
continue
Expand All @@ -80,11 +98,59 @@ func encodedSavedObject(data []byte) ([]byte, bool, error) {
if err != nil {
return nil, false, err
}
_, err = savedObject.Put(v, string(r))
_, err = object.Put(v, string(r))
if err != nil {
return nil, false, fmt.Errorf("can't put value to the saved object: %w", err)
}
changed = true
}
return []byte(savedObject.StringToPrint()), changed, nil
return object, changed, nil
}

func encodeEmbeddedPanels(object common.MapStr) (common.MapStr, bool, error) {
embeddedPanelsValue, err := object.GetValue(panelsAttribute)
if err == common.ErrKeyNotFound {
return object, false, nil
}
if err != nil {
return nil, false, fmt.Errorf("retrieving embedded panels failed: %w", err)
}
_, isEncoded := embeddedPanelsValue.(string)
if isEncoded {
// This is already encoded, probably exported with an old version of elastic-package, do nothing.
return object, false, nil
}
embeddedPanels, ok := embeddedPanelsValue.([]any)
if !ok {
return nil, false, fmt.Errorf("expected list of panels, found %T", embeddedPanelsValue)
}

changed := false
for i, panelValue := range embeddedPanels {
panel, ok := panelValue.(map[string]any)
if !ok {
return nil, false, fmt.Errorf("expected panel in map format, found %T", panel)
}
embeddableConfigValue, ok := panel[embeddableConfigAttribute]
if !ok {
continue
}
embeddableConfig, ok := embeddableConfigValue.(map[string]any)
if !ok {
return nil, false, fmt.Errorf("embeddable config is not a map, found %T", embeddableConfigValue)
}
embeddableConfig, embeddableChanged, err := encodeObjectMapStr(common.MapStr(embeddableConfig))
if err != nil {
return nil, false, fmt.Errorf("econding embedded object failed: %w", err)
}
if embeddableChanged {
changed = true
}

panel[embeddableConfigAttribute] = embeddableConfig
embeddedPanels[i] = panel
}
object.Put(panelsAttribute, embeddedPanels)

return object, changed, nil
}
64 changes: 54 additions & 10 deletions internal/export/transform_decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,23 @@ import (
"github.com/elastic/elastic-package/internal/common"
)

var (
encodedFields = []string{
"attributes.kibanaSavedObjectMeta.searchSourceJSON",
"attributes.layerListJSON",
"attributes.mapStateJSON",
"attributes.optionsJSON",
"attributes.panelsJSON",
"attributes.uiStateJSON",
"attributes.visState",
}
const (
panelsAttribute = "attributes.panelsJSON"
embeddableConfigAttribute = "embeddableConfig"
)

var encodedFields = []string{
"attributes.controlGroupInput.ignoreParentSettingsJSON",
"attributes.controlGroupInput.panelsJSON",
"attributes.kibanaSavedObjectMeta.searchSourceJSON",
"attributes.layerListJSON",
"attributes.mapStateJSON",
"attributes.optionsJSON",
"attributes.uiStateJSON",
"attributes.visState",
panelsAttribute,
}

func decodeObject(ctx *transformationContext, object common.MapStr) (common.MapStr, error) {
for _, fieldToDecode := range encodedFields {
v, err := object.GetValue(fieldToDecode)
Expand Down Expand Up @@ -51,5 +56,44 @@ func decodeObject(ctx *transformationContext, object common.MapStr) (common.MapS
return nil, fmt.Errorf("can't update field (key: %s): %w", fieldToDecode, err)
}
}

object, err := decodeEmbeddedPanels(ctx, object)
if err != nil {
return nil, err
}
return object, nil
}

func decodeEmbeddedPanels(ctx *transformationContext, object common.MapStr) (common.MapStr, error) {
embeddedPanelsValue, err := object.GetValue(panelsAttribute)
if err == common.ErrKeyNotFound {
return object, nil
}
if err != nil {
return nil, fmt.Errorf("retrieving embedded panels failed: %w", err)
}
embeddedPanels, ok := embeddedPanelsValue.([]map[string]any)
if !ok {
return nil, fmt.Errorf("expected list of panels, found %T", embeddedPanelsValue)
}
for i, panel := range embeddedPanels {
embeddableConfigValue, ok := panel[embeddableConfigAttribute]
if !ok {
continue
}
embeddableConfig, ok := embeddableConfigValue.(map[string]any)
if !ok {
return nil, fmt.Errorf("embeddable config is not a map, found %T", embeddableConfigValue)
}
embeddableConfig, err = decodeObject(ctx, common.MapStr(embeddableConfig))
if err != nil {
return nil, fmt.Errorf("decoding embedded object failed: %w", err)
}

panel[embeddableConfigAttribute] = embeddableConfig
embeddedPanels[i] = panel
}
object.Put(panelsAttribute, embeddedPanels)

return object, nil
}
Loading