--- name: migrate-required-input-dependency description: >- Migrate an Elastic integration package from a legacy inline agent template to integrations with required input dependencies (`requires.input`, `streams[].package`). Gathers developer decisions on dataset naming, variable overrides, stack constraints, and tests before applying changes. Use when the user asks to migrate an integration to an input package, adopt `requires.input`, switch to `streams[].package`, or mentions required input dependencies. Requires elastic-package CLI. compatibility: Requires `elastic-package` CLI. Designed for packages in elastic/integrations. license: Apache-2.0 metadata: origin: elastic/integrations guide: elastic-package/docs/howto/migrate_integration_required_input_dependency.md --- # migrate-required-input-dependency Migrate an integration package to **integrations with required input dependencies**. **Authoritative guide:** [HOWTO: Migrate an integration package to use required input dependencies](https://github.com/elastic/elastic-package/blob/main/docs/howto/migrate_integration_required_input_dependency.md) (`docs/howto/migrate_integration_required_input_dependency.md` in elastic-package on `main`) At the start of Phase 1, read that guide from a local elastic-package checkout or from the URL above. **Reference implementation:** [elastic/integrations#19719](https://github.com/elastic/integrations/pull/19719) (`packages/elastic_package_registry`). If `main` still shows legacy `input:` / inline collector templates, diff against the PR branch — do not copy pre-migration patterns from `main`. ## Rules 1. **Never edit package files until all decision gates in Phase 2 are answered** and you have presented a migration plan summary for confirmation. 2. Prefer **manifest variable overrides** over hardcoding values in `stream.yml.hbs` (hardcoding causes Fleet UI values that have no effect). For each variable, be explicit about **intent** per the [how-to guide Variable overrides section](https://github.com/elastic/elastic-package/blob/main/docs/howto/migrate_integration_required_input_dependency.md#variable-overrides): who sets it (integration author vs end user), whether it appears in Fleet, and whether the rendered agent template references it via `{{variable}}` rather than a hardcoded literal. 3. Set **`dataset:` on the data stream manifest** when the integration dataset must differ from the input package default — do not expose `data_stream.dataset` as a user variable unless the developer explicitly chooses that approach. 4. Keep local `stream.yml.hbs` limited to integration-owned template fragments only. 5. Run `elastic-package build` and `elastic-package test` after migration; use `elastic-package test policy --generate` only after the developer reviews generated expectations. 6. **Do not treat an unmigrated reference package on `main` as source of truth** — use the guide and PR #19719 when `packages/elastic_package_registry` is still legacy. ## Phase 1 — Discover the package 0. Confirm `elastic-package version` succeeds. If missing, stop and point to the [elastic-package install guide](https://github.com/elastic/elastic-package#getting-started). Version should be minimum v0.125.1. 1. Locate the integration package root (`manifest.yml`, `type: integration`). 2. Read the legacy setup: - `manifest.yml` — `policy_templates`, `format_version`, `conditions`, existing `requires` - Each data stream's `manifest.yml` and `agent/stream/*.hbs` - `fields/`, ingest pipelines, dashboards tied to the current dataset/index name - `_dev/test/config.yml`, policy/system/pipeline tests 3. Identify the target **input package** — search local `packages/` for `type: input`; if not found, check the package registry or ask the developer. 4. Diff legacy template vars/defaults against the input package manifest vars/defaults. Flag **input-only variables** (present on input, absent from legacy template) for Gate D. 5. Record the integration's **historical dataset** name(s) from policy tests, dashboards, `output_permissions`, or `data_stream.dataset` usage. Present a short inventory: package name, data streams, legacy input type, proposed input package, variables that differ between legacy and input defaults, input-only variables, and common diffs (for example `hosts` path format). ## Phase 2 — Gather developer decisions (required before migration) Use `AskQuestion` when available; otherwise ask conversationally. **Do not proceed to Phase 3 until every applicable gate below is resolved.** ### Gate 0 — Migration appropriateness | Decision | Options / prompt | | --- | --- | | Suitable input package exists? | Yes — proceed · No — stop; recommend creating/publishing an input package first | | Stack supports `format_version` ≥ 3.6? | Yes (stack 9.4+) · No — stop; plan stack upgrade or defer migration | | Drop-in replacement assumed? | Confirm developer understands dataset, variable precedence, and policy expectations need explicit work | | Multiple data streams | Same input package for all streams, or per-stream input packages (rare)? | ### Gate A — Scope and dependency | Decision | Options / prompt | | --- | --- | | Input package | Which input package? (e.g. `prometheus_input`) | | Input version pin | Exact version for `requires.input` (e.g. `"1.0.1"`) — use `elastic-package requires update` later to bump pins | | Input version source | Published registry version · Unpublished — local `requires.source` for tests (build still fetches from registry unless using a [local registry](https://github.com/elastic/elastic-package/blob/main/docs/howto/local_package_registry.md)) | | Data streams in scope | All data streams or a subset? | ### Gate B — Stack and format version | Decision | Options / prompt | | --- | --- | | `format_version` | Default `3.6.5` unless developer specifies otherwise (minimum `3.6` for `requires.input`) | | `conditions.kibana.version` | Required minimum for target stack? (guide example: `^9.4.4`) | | Changelog type for stack drop | `enhancement` (typical) or `breaking-change`? | ### Gate C — Dataset management Explain the risk: without an explicit dataset, documents may index under the **input package default** (e.g. `metrics-prometheus-*`). | Decision | Options / prompt | | --- | --- | | Dataset name per data stream | Confirm historical name (e.g. `elastic_package_registry.metrics`) | | Dataset strategy | **`dataset:` on data stream manifest (recommended)** · `data_stream.dataset` stream var · Auto-naming `package_name.stream_type` (only if historically correct) | Default recommendation when unsure: **`dataset:` on the data stream manifest**. ### Gate D — Variable overrides (per variable) Follow the [how-to guide Variable overrides section](https://github.com/elastic/elastic-package/blob/main/docs/howto/migrate_integration_required_input_dependency.md#variable-overrides). The rendered agent policy merges three layers: input package template defaults, integration `stream.yml.hbs`, and user-selected values. **Understanding which layer wins is critical.** Include **every** variable from the input package manifest, even if absent from the legacy template. For `data_stream.dataset` on the input package, prefer manifest `dataset:` (Gate C), not a stream var override. Variables can be declared at **stream level** (`streams[].vars` in the data stream manifest) or **input level** (`policy_templates[].inputs[].vars` in the package manifest). Input-level declarations are **promoted** to input-scoped variables. Use stream-level vars for per-data-stream tuning; use input-level vars when the override applies to every data stream that references the input package in that policy template. For each variable, ask the developer to classify: | Category | Meaning | Action | | --- | --- | --- | | **A — Integration-only** | Not in input package (e.g. `metrics_path`) | Add data stream var + reference in slim `stream.yml.hbs` via `{{variable}}` | | **B — Override input default** | Input default differs from legacy behaviour (e.g. `rate_counters: false`) | Redeclare on `streams[].vars` with integration default | | **C — Inherit** | Input default matches legacy (e.g. `use_types: true`) | Remove from local template and data stream manifest; do not redeclare or hardcode | For each **A** and **B** variable, also confirm **variable intent**: - **Who sets it:** integration author default vs end user at policy creation? - **Fleet visibility:** `show_user: true` (user-facing) or `false` (advanced/hidden)? - **Template binding:** referenced via `{{variable}}` in `stream.yml.hbs` or merged from the input template — not a hardcoded literal that bypasses Fleet? - Default value (confirm against legacy template) Category **C** variables inherit from the input package during bundling with `show_user: false` by default (advanced options in Fleet) — no explicit redeclaration needed. **Explicitly ask** whether any variable should be **hardcoded in `stream.yml.hbs`**. If yes, warn that Fleet may still show the input default in the UI and user edits will not apply. Document the choice in the migration plan. Present the variable matrix (name → category → intent → default → `show_user` → template binding) and get confirmation before editing. ### Gate E — Local development and tests | Decision | Options / prompt | | --- | --- | | Local input `source` path | Relative path for `_dev/test/config.yml` (e.g. `../prometheus_input`) if input is unpublished — affects `elastic-package test` only | | Policy tests | Confirm default (`vars: ~`) + overrides test; which vars to exercise in overrides? For multiple data streams sharing the same input type, policy expectations must list sibling streams as `enabled: false` | | Policy expectation generation | Generate with `--generate` after plan approval, or defer until post-edit review? | | Pipeline regression tests | Any known edge cases (null **and** missing fields)? | | System test traffic | Does the service need synthetic traffic for metrics to appear? Which hit assertions need extending? | | Fleet variable spot-check | Install built package in local stack and create a policy when possible — confirm Fleet-visible variables map to the rendered agent template and user edits take effect | ### Gate F — Collateral changes | Decision | Options / prompt | | --- | --- | | Field mapping fixes | Any `long` → `double` or similar type corrections? Compare integration and input package `fields/` against collector output. **Check for breaking changes** if users may already have data indexed under the old type (mapping conflicts, reindex). Changelog: `bugfix` when the prior type was wrong and never worked; `breaking-change` when the correction is incompatible with existing indices. | | Ingest pipeline re-test | Re-test against real collector output after input package switch? | | Dashboard migration | Re-export for target stack Lens version · Validate only · N/A | | Documentation | Manually document input dependency if `{{ inputDocs }}` is empty? | | Package version bump | Minor bump typical for this migration? | ### Gate G — Plan confirmation Summarize the full plan: - Manifest changes (`requires.input`, `policy_templates`, `format_version`, `version` bump) - Per data stream: remove legacy `input:` key, `streams[].package`, `dataset:`, category A/B `streams[].vars` only, slim template contents with `{{variable}}` bindings - Variable intent matrix (categories A/B/C, Fleet visibility, template binding) - Test and changelog changes **Ask the developer to confirm the plan before making any edits.** ## Phase 3 — Execute migration Apply changes in this order (see [migrate_integration_required_input_dependency.md](https://github.com/elastic/elastic-package/blob/main/docs/howto/migrate_integration_required_input_dependency.md)): 1. **`manifest.yml`** — `format_version`, `requires.input`, `policy_templates` → `package: `, bump `version` per Gate F 2. **`data_stream//manifest.yml`** — set `dataset:`; replace legacy `input:` with `streams[].package`; add `template_path: stream.yml.hbs`; declare `streams[].vars` for categories A/B only; remove category C vars from local manifest 3. **`agent/stream/stream.yml.hbs`** — keep only integration-owned fragments; remove all collector config merged from the input package 4. **`_dev/test/config.yml`** — `policy`/`system` `requires.source` if Gate E applies 5. **Policy tests** — `test-default.yml`, `test-overrides.yml`; generate expectations only after developer approval; confirm every Fleet-visible variable maps to the rendered agent template and user-set values take effect; confirm every Fleet-visible variable maps to the rendered agent template and user-set values take effect 6. **Ingest pipelines** — re-run pipeline tests; add null and missing-field cases per Gate E/F 7. **System tests** — extend hit assertions and traffic fixtures per Gate E 8. **`changelog.yml`** — migration (`enhancement`), stack constraint, field fixes (`bugfix`) per Gate B/F 9. **Docs** — `elastic-package build` to regenerate docs; then manual input section in `_dev/build/docs/` if Gate F requires it Do not bump unrelated packages or refactor outside migration scope. ## Phase 4 — Verify From the package directory: ```bash elastic-package build elastic-package check elastic-package test -v ``` If system tests need variants or traffic, run what the developer confirmed in Gate E. ### Verify variables in Fleet Per the [how-to guide end-to-end verification step](https://github.com/elastic/elastic-package/blob/main/docs/howto/migrate_integration_required_input_dependency.md#8-verify-end-to-end), install the built package in a local stack and create an agent policy when possible: 1. **Fleet UI ↔ template binding** — every variable shown in Fleet should have a corresponding entry in the rendered agent template (`{{variable}}` reference or merged input-template binding). Flag any variable visible in the UI whose effective value is a hardcoded literal in `stream.yml.hbs` — user edits to that field will not apply. 2. **User overrides take effect** — change a Fleet-visible variable in the policy UI and confirm the rendered agent policy updates (policy test overrides should cover this; Fleet spot-check when a variable is not exercised in tests). 3. **Defaults match intent** — Fleet defaults for categories A/B match the integration manifest; category C inherited vars appear under advanced options unless explicitly redeclared. Report: - Build/test pass/fail with relevant log excerpts - Policy output: `data_stream.dataset` and `output_permissions` index names (e.g. `metrics--ep`); confirm every Fleet-visible variable maps to the rendered agent template - Fleet variable spot-check results (UI fields shown, template bindings, user override behaviour) when a local stack was available - Dashboard spot-check on target stack when Gate F confirmed - Platform gaps still relevant after migration: | Gap | Tracking | | --- | --- | | Variables visible in UI but ignored by template | [elastic/integrations#19719](https://github.com/elastic/integrations/pull/19719) | | No integration-level opt-out for input variables | Future enhancement | | `{{ inputDocs }}` empty for `streams[].package` | [elastic/elastic-package#3696](https://github.com/elastic/elastic-package/issues/3696) | | Dataset variable vs manifest `dataset:` field | [elastic/elastic-package#3713](https://github.com/elastic/elastic-package/pull/3713), [elastic/elastic-package#3719](https://github.com/elastic/elastic-package/pull/3719), [elastic/kibana#275312](https://github.com/elastic/kibana/pull/275312) | ### Verification checklist Mark each item done or N/A: - [ ] `format_version` ≥ 3.6.5 and `requires.input` pinned to a published input version - [ ] `dataset:` explicitly set on the data stream manifest when it must differ from the input default - [ ] Local `stream.yml.hbs` contains only integration-owned template fragments; integration-specific or overridden values use `{{variable}}` references, not hardcoded literals that bypass Fleet - [ ] Variable intent is explicit per [Variable overrides](https://github.com/elastic/elastic-package/blob/main/docs/howto/migrate_integration_required_input_dependency.md#variable-overrides): manifest `vars` for categories A/B, inherit input defaults when acceptable (category C) — avoid silent template hardcoding that leaves misleading values in the Fleet UI - [ ] Variable overrides use `streams[].vars`, not silent template hardcoding - [ ] Legacy `input:` key removed; `streams[].package` in place - [ ] `_dev/test/config.yml` declares `requires` for local input package during development - [ ] Policy tests (default + overrides): expectations confirm every Fleet-visible variable maps to the rendered agent template and user-set values take effect — review dataset, overridden defaults, sibling streams (`enabled: false` where required); spot-check in Fleet when policy tests do not cover a variable - [ ] System tests pass with realistic service traffic where needed - [ ] Pipeline regression tests for edge cases found during migration - [ ] Changelog entries: migration, stack constraint, field-mapping fixes (use `breaking-change` when mapping type updates affect existing indices) - [ ] Docs manually updated if `{{ inputDocs }}` is empty - [ ] Dashboards validated on the target stack version ## Decision quick-reference ``` Suitable input package + stack 3.6+? → Gate 0 must pass before migrating Legacy var differs from input default? → B: redeclare on streams[].vars Var only in integration template? → A: add var + {{variable}} in slim template Input default matches legacy? → C: inherit; remove from local template/manifest Input-only var on input package? → Classify in Gate D (often C or N/A) Per-stream vs all-streams override? → streams[].vars vs policy_templates[].inputs[].vars Variable intent unclear? → Who sets it, Fleet visibility, template binding — see how-to Variable overrides Fleet UI shows var but template ignores?→ Hardcoding anti-pattern; use manifest override or document intentional Dataset must stay stable? → dataset: on data stream manifest Unpublished input package? → _dev/test/config.yml requires.source (tests only) Bump input pins later? → elastic-package requires update ``` ## Anti-patterns - Starting migration without Gate 0 — no suitable input package or unsupported stack - Copying patterns from `packages/elastic_package_registry` on `main` while PR #19719 is unmerged - Migrating without confirming dataset name → silent index rename - Skipping `output_permissions` index name review in policy expectations - Hardcoding overrides in `stream.yml.hbs` without developer acknowledgement → Fleet UI mismatch; variable shown in UI but user edits ignored - Using hardcoded literals in `stream.yml.hbs` for values that should be Fleet-configurable — use `{{variable}}` and manifest `vars` instead - Using `data_stream.dataset` as a user variable when `dataset:` field suffices - Leaving legacy `input:` alongside new `streams[].package` - Running `elastic-package test policy --generate` and committing expectations without developer review - Leaving full collector config in local template after switching to `streams[].package` - Skipping ingest pipeline re-test after collector output shape changes - Assuming `requires.source` in test config satisfies `elastic-package build` (build still uses registry)