bundle templates of required input packages#3329
bundle templates of required input packages#3329teresaromero wants to merge 10 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
cmd/install.go
Outdated
| return fmt.Errorf("can't load configuration: %w", err) | ||
| } | ||
|
|
||
| eprClient := registry.NewClient(appConfig.PackageRegistryBaseURL()) |
There was a problem hiding this comment.
As the installation would depend also on the profile being set, the EPR url should be also retrieved taken into account the one that could be set in the profile.
In the stack module, this is done via this method:
elastic-package/internal/stack/registry.go
Lines 34 to 44 in 997b47d
There was a problem hiding this comment.
i've made the function public and used it at install cmd. build command is still using appconfig as the command does not use profile
…undle-templates-required-input-packages
💔 Build Failed
Failed CI StepsHistory
|
| Composable (integration) packages can also depend on other packages — specifically **input | ||
| packages** — by declaring them under `requires.input` in `manifest.yml`: |
There was a problem hiding this comment.
Nit. They can also depend on content packages, but at the moment they are resolved at runtime.
| 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.
| elastic-package build | ||
|
|
||
| # Start a local registry serving the build/ directory | ||
| docker run --rm -p 8080:8080 \ |
There was a problem hiding this comment.
Starting a local registry on local port 8080 is going to conflict with the registry started with elastic-package stack up.
There was a problem hiding this comment.
Nit. Avoid using underscores in Go file or package names.
| 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.
| 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.
| func removeKey(node *yaml.Node, key string) { | ||
| for i := 0; i+1 < len(node.Content); i += 2 { | ||
| if node.Content[i].Value == key { | ||
| node.Content = append(node.Content[:i], node.Content[i+2:]...) | ||
| return | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Nit. We can possibly reuse slices package here and in other helpers.
| func removeKey(node *yaml.Node, key string) { | |
| for i := 0; i+1 < len(node.Content); i += 2 { | |
| if node.Content[i].Value == key { | |
| node.Content = append(node.Content[:i], node.Content[i+2:]...) | |
| return | |
| } | |
| } | |
| } | |
| func removeKey(node *yaml.Node, key string) { | |
| node.Content = slices.DeleteFunc(node.Content, func(n *yaml.Node) bool { | |
| return n.Value == key | |
| }) | |
| } |
| 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.
| // accommodate the common monorepo layout where packages live under a top-level | ||
| // "packages/" directory. Returns the package root path and its manifest, or an | ||
| // error when the package cannot be found. | ||
| func FindPackageInRepo(repoRoot string, packageName string) (string, *PackageManifest, error) { |
| } | ||
| tmpFile.Close() | ||
|
|
||
| pkgRoot, err := extractZipPackage(tmpPath, destDir) |
There was a problem hiding this comment.
We should not need to extract the zips, it is possible to use a zip reader as a filesystem.
Even if we need to do it at the end, I think it should not be a responsibility of the DownloadPackage method to extract it.
Bundle input package templates for composable integrations
This PR adds support for composable integrations: packages that declare a
requires.inputsection in their manifest to pull agent input templates from aseparate input-type package at build time.
Dependencies
This PR requires the following change to be merged first:
What changed
4f25ab87requires.inputsupport — revert before mergeadf728b2Requires,PackageDependency,RequiresOverride,TemplatePaths; addFindPackageInRepo3ecf9d60bundleInputPackageTemplatesin the builder; addDownloadPackageto fetch packages from EPR; add unit tests and fixtureseba23df1RegistryURLandRequiresOverridesthroughFleetPackage→BuildOptions; support per-test-type overrides in_dev/test/config.yml; inject registry client from app configb43bf5b1How it works
When
elastic-package buildruns on an integration that declaresrequires.input,it now:
local source override configured in
_dev/test/config.yml.data_stream/<ds>/agent/stream/with a<pkgname>-prefix to avoidcollisions.
template_paths, listing the inputpackage templates first and the integration's own template last.
Testing
setStreamTemplatePaths) withminimal fixtures under
internal/builder/testdata/input_packages/.bundleInputPackageTemplatespathusing real on-disk fixture packages under
test/packages/required_inputs/.sourceoverride in_dev/test/config.ymllets tests bypass the registryand use a local fixture package instead.
Docs
A new HOWTO guide at
docs/howto/local_package_registry.mdexplains how torun a local registry when developing composable integrations.