Skip to content

support for 'compilation' of new dashboards-as-code format via elastic-package build#3531

Open
tommyers-elastic wants to merge 11 commits intomainfrom
feature/dashboards-as-code
Open

support for 'compilation' of new dashboards-as-code format via elastic-package build#3531
tommyers-elastic wants to merge 11 commits intomainfrom
feature/dashboards-as-code

Conversation

@tommyers-elastic
Copy link
Copy Markdown
Contributor

@tommyers-elastic tommyers-elastic commented May 7, 2026

Lets package authors write dashboards in the new dashboards-as-code JSON format under _dev/shared/*.json.

During build, each dashboard is installed to Kibana via the new API, exported back through the standard dashboards pipeline, and written to kibana/dashboard/<package>-<id>.json. The imported dashboard is cleaned up in Kibana.

<id> is derived from the source filename, so output is stable across rebuilds. Requires Kibana ≥ 9.4.0; build fails with the usual ErrUnavailableStack when the source dir is present and no stack is reachable. Packages without _dev/shared/*.json still build offline.

End-to-end test: test/packages/dashboards_as_code/sample/ plus scripts/test-check-packages-dashboards-as-code.sh, which brings up a stack and asserts the compiled SO is produced (the SO is deliberately not committed).

tommyers-elastic and others added 7 commits May 7, 2026 15:23
Adds support for authoring dashboards in the new dashboards-as-code JSON
format under _dev/dashboards_as_code/. During elastic-package build,
each source file is POSTed to Kibana's /api/dashboards endpoint, the
returned dashboard id is exported back through the standard dashboards
export pipeline, and the imported saved object is deleted from Kibana.

The compile step runs before CopyWithoutDev so the existing build
pipeline (encodeDashboards, validation) handles the resulting saved
objects unchanged. BuildPackage now takes a context.Context and an
optional KibanaClient on BuildOptions; the client is constructed lazily
in cmd/build.go only when _dev/dashboards_as_code/ is present, so
packages that do not use the feature still build offline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The /api/dashboards import endpoint that backs dashboards-as-code is
only available in Kibana 9.4.0 and later. The previous version check
reused the dashboards export gate (which exists for an unrelated
8.8-8.10 export bug); replace it with a dedicated minimum-version check
and drop the no-longer-needed CheckKibanaVersion export from the export
package.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Be consistent with the existing dashboards-export version check, which
just lets semver parsing fail on an empty version string.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switch the imported-dashboard cleanup from DELETE
/api/saved_objects/dashboard/<id> to DELETE /api/dashboards/<id>, the
companion of the import endpoint we already use. Accept 204 No Content
in addition to 200 since the dashboards-as-code DELETE returns 204 on
success.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
POST /api/dashboards generates a fresh UUID on every import, which made
the compiled kibana/dashboard/<id>.json filename non-deterministic and
caused old artifacts to accumulate in the source tree on each rebuild.

Switch to PUT /api/dashboards/<id> and derive the id from the source
filename (sans .json extension), so _dev/dashboards_as_code/foo.json
always compiles to kibana/dashboard/<package>-foo.json after
standardizeObjectID prefixes the package name. The compiled output is
now stable across builds and reviewable in PRs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Group with other build-time inputs (build.yml, docs/) under _dev/build/
rather than introducing a top-level _dev/ category. Dashboards-as-code
files now live at _dev/build/dashboards_as_code/<name>.json.

Note: enabling this in real packages requires elastic/package-spec to
allow _dev/build/dashboards_as_code/ — the spec change must land and
the package-spec dependency be bumped before the feature is usable end
to end (today the linter rejects the unknown folder).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds test/packages/dashboards_as_code/sample/ with a single source under
_dev/build/dashboards_as_code/overview.json. The compiled saved object
is intentionally absent so the test can prove the build wrote it.

Adds scripts/test-check-packages-dashboards-as-code.sh (modeled on the
composable-packages script): brings up the stack, runs `elastic-package
check` on each fixture, then for every <name>.json source asserts that
kibana/dashboard/<package>-<name>.json was written by the build. Pre-flight
guards against fixtures that already contain compiled SO files. Cleanup
trap removes generated artefacts and brings the stack down.

Wires the new target into the umbrella test-check-packages Makefile rule.

The fixture and test require a package-spec release that allows
_dev/build/dashboards_as_code/ and a corresponding bump of the
github.com/elastic/package-spec/v3 dependency before this branch can
pass CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tommyers-elastic tommyers-elastic requested a review from a team as a code owner May 7, 2026 15:39
Comment thread cmd/build.go Outdated
if err != nil {
return fmt.Errorf("getting Kibana version information: %w", err)
}
if err := checkDashboardsAsCodeKibanaVersion(versionInfo); err != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this not checked by the package validation? when the version of a package is set with its kibana version?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the intention here is just to check if the stack being used to build the package supports the API. it won't check vs the manifest version because existing check/build doesn't require a stack at all.

Comment thread internal/builder/dashboards_as_code.go Outdated
// form of the API guarantees the resulting saved object uses the id we choose,
// rather than a freshly generated one). Returns the id reported by Kibana,
// which should match the supplied id.
func (c *Client) ImportDashboardAsCode(ctx context.Context, id string, body []byte) (string, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not following the function, sorry. So ImportDashboardAsCode means:

  • attach a body and update whatever dashboard is at kibana? with the given id, if not exists, creates it? from the elastic-package pov, isnt this exporting it to kibana? where is the object saved?
    OR
  • is this sending the body to kibana and responding it with a good-to-go dashboard instead? in that case... can we rename the function, i feel Import semantics feels is a one way road, but is actually 2 ways? although i dont see where it saves it :D

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this creates or updates the dashboard in kibana.

the new dashboard API handles the underlying saved object management. you can create, update, and delete dashboards via the new API without touching saved objects.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the semantics of import/export in elastic-package follow this naming convention. 'export' is exporting objects from kibana.

tommyers-elastic and others added 2 commits May 8, 2026 10:06
The package-spec already exposes _dev/shared as a generic shared-files
folder (with additionalContents: true on integration packages, and the
content-package spec explicitly mentioning dashboards-as-YML files
there). Putting our sources in _dev/shared lets the feature ship
without an upstream package-spec change.

Convention: any *.json file directly under _dev/shared/ is treated as
a dashboards-as-code source; the filename (sans .json) becomes the id.
Other files in _dev/shared remain untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the auto-detection (any *.json under _dev/shared/) with an
opt-in --compile-dashboards-as-code flag on elastic-package build.
This avoids interpreting unrelated *.json files in _dev/shared/ as
dashboards-as-code sources, and makes the intent (and the resulting
dependency on a running Kibana) explicit at the command line.

The builder treats the kibanaClient pointer as the gate: callers that
want compilation pass a non-nil client; otherwise compileDashboardsAsCode
returns immediately.

`elastic-package check` doesn't forward flags to its composed `build`
sub-command, so the test script now runs `lint` and `build
--compile-dashboards-as-code` separately to exercise the full path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@elasticmachine
Copy link
Copy Markdown
Collaborator

elasticmachine commented May 8, 2026

💔 Build Failed

Failed CI Steps

History

The contextcheck linter flags passing context.Background() inside a
function that already has a ctx parameter. Use context.WithoutCancel
instead — it preserves any values/tracing on the parent ctx while
detaching from its cancellation, so cleanup still runs if the build's
context has been cancelled by the time the defer fires.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants