bundle templates of required input packages#3329
bundle templates of required input packages#3329teresaromero wants to merge 44 commits intoelastic:mainfrom
Conversation
|
blocked for merge until 3.6 elastic/package-spec#1060 |
Replace the existing package-spec dependency with a specific pre-release version that includes support for the requires.input manifest section. NOTE: Remove the replace directive before merging and use the latest released version when available. Made-with: Cursor
Add Requires, PackageDependency, and RequiresOverride types. Extend Stream with PackageRef and TemplatePaths, PolicyTemplate with TemplatePaths, and PackageManifest with a Requires field. Add FindPackageInRepo to search the repository for a package by name, scanning up to 4 directory levels to accommodate monorepo layouts.
Add Client.DownloadPackage which fetches a package by name and version from the Elastic Package Registry, extracts the zip archive into a temporary directory, and returns the path to the extracted package root. Add bundleInputPackageTemplates, which runs after the package content is copied to the build directory. For each integration that declares requires.input, it resolves every required input package (from the registry or a local source override), copies agent input templates into data_stream/<ds>/agent/stream/ with a "<pkgname>-" prefix, and rewrites the data stream manifest to use template_paths. Add test fixtures (test_input_pkg, with_input_package_requires) and unit tests for the YAML rewriting helpers and the full bundling path.
… pipeline Thread RequiresOverrides and RegistryURL through FleetPackage, installer.Options, and BuildOptions so test runners can supply source or version overrides for required input packages. Support requires overrides at both top-level and per-type sections in the global test config (_dev/test/config.yml). Per-type entries override global entries by package name. Inject the registry client from app config values to enable local or custom package registries during the build. Add an integration test that exercises the full template bundling path using a local fixture package, bypassing the package registry.
Add a new HOWTO guide explaining how to configure elastic-package to use a local or custom package registry when developing composable integrations that declare required input packages. Update the build command description, README, and dependency management docs to document the relationship between the build process and the package registry for composable packages.
9b55229 to
b43bf5b
Compare
…undle-templates-required-input-packages
| This guide explains how to point elastic-package at a local or custom registry, which is | ||
| useful when the required input packages are still under development and not yet published to | ||
| the production registry. |
There was a problem hiding this comment.
elastic-package stack up with the compose provider (the default), starts a local package registry, that serves the packages under build/packages. This can be used to serve local packages. You only need to remember building the ones you need.
This mechanism would even be improved after your change in elastic/package-registry#1482, what would allow reloading the packages without needing to restart the registry.
In the documentation here we are adding another method to serve local packages. We should probably converge both methods in a single one.
internal/builder/packages.go
Outdated
| return "", fmt.Errorf("resolving transform manifests failed: %w", err) | ||
| } | ||
|
|
||
| err = bundleInputPackageTemplates(options.PackageRoot, buildPackageRoot, options.RegistryClient, options.RequiresOverrides) |
There was a problem hiding this comment.
For a future refactor. We have several methods that receive options.PackageRoot to read the manifest. We could maybe make these methods members of an object that shares the manifest and maybe other parts of a package.
There was a problem hiding this comment.
this was only required to extract the _dev/test configs... as i've removed this part i will see how to include this param when i implement the testing part
internal/builder/input_packages.go
Outdated
| dsRoot := filepath.Dir(dsManifestPath) | ||
| agentStreamDir := filepath.Join(dsRoot, "agent", "stream") | ||
|
|
||
| // Parse the YAML document preserving formatting for targeted modifications. |
There was a problem hiding this comment.
Preserving the format is nice, though we don't really need to keep the format here, as we are building the package, that is not intended for later human-driven modifications. I would be concerned of complicating things unnecessarily.
There was a problem hiding this comment.
does this mean we can modify using the structs and save a new copy from them? i thought we needed to preserve how the manifest was and working directly with yml
There was a problem hiding this comment.
We don't need the built package to be human-friendly, so we can do what is simpler to maintain.
There was a problem hiding this comment.
i've gave a try to not use the yaml node aproach, but the models (structs) from elastic-package do not cover all the manifest data... so when marshalling and unmarshalling, data is lost. I was thinking that perhps we should export the models from the spec as a library, and a single point of truth for go structs reflecting the manifest from yaml.
however, i kept the yaml implementation so we just modify the necessary fields, without data loss
| RegistryClient *registry.Client // Registry client for downloading input packages. | ||
| RequiresOverrides map[string]packages.RequiresOverride // Pre-merged requires overrides (test builds only). |
There was a problem hiding this comment.
Nit. Maybe for a future change. Instead of receiving the registry and the overrides, this could receive a higher level abstraction that gets dependencies. This abstraction would handle the different package sources, caches, overrides and so on.
There was a problem hiding this comment.
i've removed for now this, i am still wondering how to do the overrides. for now i am injecting an interface with the epr client, i am not sure if there should be an implementation for tests and other for build/install
i am still understanding how this should work, could you provide an example of what should be expected when the override is defined?
…ncies resolution. Enhance local package registry instructions with built-in stack registry usage and standalone registry setup.
…undle-templates-required-input-packages
…undle-templates-required-input-packages
…ociation bundleDataStreamTemplates now reads the integration's root manifest and builds a dsName→packages lookup from policy templates that explicitly declare data_streams[]. Stream entries are only bundled when their package is present in this lookup, preventing implicit 1:1 assumptions between data streams and policy templates. Adds TestBundleDataStreamTemplates_SkipWhenNoDataStreamsAssociation, moves shared test helpers to testhelpers_test.go, and updates the with_input_package_requires fixture with an explicit data_streams field. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bundle templates based solely on the data stream manifest's streams[].package reference, without requiring an explicit data_streams association in the root policy template. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
When installing the package or running policy tests for a composable package fleet returns error
Implementing tests and running installation of the composable will require #3380 |
…esolver Add NoopRequiredInputsResolver to avoid nil interface panics in integration tests that don't have an EPR client. Replace filepath.Join/Dir with path.Join/Dir in policytemplates.go and streams.go so fs.FS and os.Root receive forward-slash paths on all platforms including Windows. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Relocate test_input_pkg and with_input_package_requires out of test/packages so CI build/install zip loops no longer pick them up. Add test/manual_packages/README.md with manual testing steps. Made-with: Cursor
…registry" This reverts commit 86557d8.
…undle-templates-required-input-packages
| // for each policy template, with an input package reference: | ||
| // collect the templates from the input package and copy them to the agent/input directory of the build package | ||
| // then update the policy template manifest to include the copied templates as template_paths |
There was a problem hiding this comment.
Have this process being tested with linked files ?
Checking the spec, template paths could also be linked files. For instance:
https://github.com/elastic/package-spec/blob/73ad6a82946c4880c327b09bb28327bb0d44c0f8/spec/integration/data_stream/agent/spec.yml#L30
There was a problem hiding this comment.
For packages downloaded from EPR those files should be already resolved, but maybe while testing using local folders (e.g. in system tests), could there be any issue if package contains linked files?
There was a problem hiding this comment.
i have not tested with linked files yet. the feature for testing and replacing epr for a local source is still WIP
| zipPath := filepath.Join(destDir, fmt.Sprintf("%s-%s.zip", name, version)) | ||
| if err := os.WriteFile(zipPath, zipBytes, 0644); err != nil { | ||
| return "", fmt.Errorf("writing package zip %s-%s: %w", name, version, err) | ||
| } |
There was a problem hiding this comment.
During this process, once the package has been downloaded, should it be validated that package with the corresponding signature (if exists) here too ? signature_path from the package response (metadata in this method). cc @jsoriano
Use os.OpenRoot and root.FS() instead of os.DirFS so reads stay scoped to the package subtree like the build root path. Callers must close the root via the returned close function; update openPackageFS godoc accordingly. Made-with: Cursor
Use a "failed to <action>" pattern across policy template bundling, data stream bundling, and YAML formatting. Distinguish read versus parse failures for package manifests. Update tests that assert on error substrings. Made-with: Cursor
Use docker.elastic.co/package-registry/package-registry:v1.37.0 to match PackageRegistryBaseImage. Document distribution:lite as a smaller alternative and point readers to internal/stack/versions.go for the canonical tag. Made-with: Cursor
| type requiredInputsResolver interface { | ||
| BundleInputPackageTemplates(buildPackageRoot string) error | ||
| } |
There was a problem hiding this comment.
I see this is duplicated in different packages.
If this is moved for instance under the new requiredinputs package, does it results in circular dependencies?
There was a problem hiding this comment.
i used this as a pattern to avoid exporting interfaces and make implementations independent from each other. i've moved the interface to the package as it does not create circular dependencies.
Replace per-package private requiredInputsResolver definitions with a single exported Resolver interface in internal/requiredinputs. Consumers import requiredinputs for the contract; *RequiredInputsResolver still implements it. Made-with: Cursor
…undle-templates-required-input-packages
💚 Build Succeeded
History
|
Bundle input package templates for composable integrations
Closes #3278
Summary
Implements build-time template bundling for integration packages that declare dependencies on input packages via
requires.inputin their manifest. At build time,elastic-packagedownloads the required input packages from EPR and copies their agent templates into the integration's build output so Fleet can render them correctly. Bothtemplate_pathandtemplate_pathsfields are handled — input package templates are prepended to the integration's own templates, so the integration takes precedence during rendering.Bundling runs in two paths:
Policy template inputs (
bundlePolicyTemplatesInputPackageTemplates): triggered whenpolicy_templates[].inputs[].packagereferences an input package. Templates fromagent/input/are copied to the integration'sagent/input/directory (prefixed with the package name), and the manifest is rewritten to usetemplate_paths.Data stream streams (
bundleDataStreamTemplates): triggered whendata_stream/<name>/manifest.yml → streams[].packagereferences an input package. Templates from the input package'sagent/input/are copied to the data stream'sagent/stream/directory andtemplate_pathsis updated. Bundling is driven solely by this per-streampackagereference — Fleet then selects the appropriate templates at render time.What changed
internal/requiredinputs(new package)RequiredInputsResolver: downloads required input packages from EPR into a temp directory; supports directory and zip formats.bundlePolicyTemplatesInputPackageTemplates: copies and wires input packageagent/input/templates for policy template inputs.bundleDataStreamTemplates: copies and wires input packageagent/input/templates for data stream stream entries.internal/packages— extended manifest typesPolicyTemplate: addsDataStreams,TemplatePaths.PackageManifest.Input: addsPackage,TemplatePath,TemplatePaths.DataStreamManifest.Stream: addsPackage,TemplatePath,TemplatePaths.Requires/PackageDependencytypes;PackageManifest.Requireswired up.internal/registry—DownloadPackagefetches and extracts packages from EPR; TLS support via profile CA cert or env-provided cert.Build pipeline —
BundleInputPackageTemplatescalled duringbuildafter package assembly;RequiredInputsResolverthreaded throughBuildOptionsand installer.Test fixtures —
test/manual_packages/required_inputs/test_input_pkg(minimal input package) andtest/manual_packages/required_inputs/with_input_package_requires(integration consuming it).How to test
Build the input package so it is available in the local build output:
Start the stack from anywhere inside the
elastic-packagerepository so the built package is served by the stack's built-in registry:Build the local tool binary from the repo root, then run it against the integration package:
Inspect the
build/directory — the input package's agent templates should appear inagent/input/anddata_stream/test_logs/agent/stream/, and the manifests should reference them viatemplate_paths.Dependencies
Not included
Local source override for input package resolution (bypass EPR during development) — removed pending a cleaner design, to be addressed in a follow-up.