Skip to content

Expose Config v2 validation and migration CLI#2679

Open
MrAlias wants to merge 24 commits into
open-telemetry:mainfrom
MrAlias:agent/config-v2-cli
Open

Expose Config v2 validation and migration CLI#2679
MrAlias wants to merge 24 commits into
open-telemetry:mainfrom
MrAlias:agent/config-v2-cli

Conversation

@MrAlias

@MrAlias MrAlias commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • expose obi config validate for standalone and Collector receiver Config v2 files
  • expose deterministic obi config migrate support for the v1-to-v2 contract
  • reject malformed, unsupported, unknown, or lossy input with actionable errors and stable exit codes
  • validate generated migrations through the shared schema and runtime conversion path before emitting YAML
  • document command usage, stream behavior, environment substitution, and exit codes

Migration behavior

Migration starts from the v1 runtime configuration model, applies the existing v1 normalization semantics, and reuses the internal Config v2 converter. It emits canonical YAML on stdout and a deterministic mapping report on stderr. A source-field round trip prevents known-but-unrepresented v1 settings from being silently dropped and reports the exact v1 paths that require manual migration.

Validation is explicitly v2-only and never falls back to v1 interpretation. Receiver mode uses the receiver schema boundary and rejects standalone-only sections before runtime validation.

Validation

  • make generate
  • go test ./cmd/obi/internal/configcmd ./pkg/obi ./internal/config/convert ./internal/config/schema
  • project golangci-lint configuration on the changed Go packages
  • make compile
  • make lint-markdown
  • make license-header-check
  • built-binary smoke tests for standalone validation, receiver validation, and representative v1 migration

Closes #2534

Part of #2251

@MrAlias MrAlias added this to the v0.11.0 milestone Jul 15, 2026
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 72.34432% with 151 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.06%. Comparing base (27fbfa6) to head (fa6626f).

Files with missing lines Patch % Lines
cmd/obi/internal/configcmd/configcmd.go 69.52% 97 Missing and 24 partials ⚠️
internal/config/convert/export_parity.go 81.61% 22 Missing and 3 partials ⚠️
cmd/obi/main.go 0.00% 4 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2679      +/-   ##
==========================================
- Coverage   69.88%   69.06%   -0.82%     
==========================================
  Files         359      360       +1     
  Lines       51142    52250    +1108     
==========================================
+ Hits        35739    36085     +346     
- Misses      13172    13912     +740     
- Partials     2231     2253      +22     
Flag Coverage Δ
integration-test 46.40% <0.86%> (-4.03%) ⬇️
integration-test-arm 23.57% <0.91%> (-2.54%) ⬇️
integration-test-vm-5.15-lts 24.39% <0.86%> (-2.29%) ⬇️
integration-test-vm-6.18-lts 26.04% <0.86%> (-0.81%) ⬇️
k8s-integration-test 31.24% <0.86%> (-3.02%) ⬇️
oats-test 31.70% <0.86%> (-2.88%) ⬇️
unittests 68.04% <84.73%> (+0.19%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mariomac mariomac left a comment

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.

This is looking great!

When the functionality is finally available I wonder if, as an extra testing, we can pick up few existing integration tests (e.g. 2 docker integration tests and 2 k8s tests), then convert v1 config to v2, and make OBI run with V2 and see that the required configuration is still active.

Comment thread cmd/obi/internal/configcmd/configcmd.go
@MrAlias

MrAlias commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

When the functionality is finally available I wonder if, as an extra testing, we can pick up few existing integration tests (e.g. 2 docker integration tests and 2 k8s tests), then convert v1 config to v2, and make OBI run with V2 and see that the required configuration is still active.

Agreed 👍. I'll look into adding this when the standalone OBI runtime loading for Config v2 is added in #2682.

@MrAlias

This comment was marked as resolved.

MrAlias and others added 15 commits July 20, 2026 15:17
Add scriptable validation for standalone and receiver Config v2 files and
lossless v1-to-v2 migration through the shared schema and conversion paths.

Reject unsupported or lossy input before emitting output, document stable
exit codes, and verify generated migrations with the same validation path.
Validate receiver configurations with explicit host-provided signal sink
context instead of installing Collector test consumers into runtime config.

Preserve standalone exporter requirements while keeping structural and
signal-specific validation common to both deployment modes.
The CLI has a single supported v1-to-v2 migration, so source and
destination options added usage surface without offering a choice.

Make the fixed contract clear in command help and documentation, and reserve
version flags for a future release that supports multiple migrations.
The config CLI imports the internal conversion and schema packages. Copy
those packages into production and debug image build contexts so cmd/obi
can compile in both images.
otelconf/x leaves AdditionalProperties untagged for YAML output, causing
nil implementation fields to appear in migrated configuration.

Normalize the encoded document so generated migration output contains only
declarative configuration keys.
Coverage and integration OBI images compile cmd/obi from reduced source
contexts. Include the internal Config v2 packages so those builds resolve
the CLI imports.
Honor default-include capture policies during CLI validation and reject
correlation filters that the runtime converter cannot represent.

Model enrichment rules explicitly, reject unknown document fields, and
require exactly one YAML document so malformed input cannot bypass
validation.
Escape environment substitution tokens in generated Config v2 YAML so a
subsequent load preserves literals from the v1 configuration.

Cover brace and Kubernetes-style variables, including existing escapes, to
prevent migration from silently changing their runtime values.
Treat Collector-provided metrics sinks as active exporters while
validating network and stats features in receiver mode.

This lets stats-only receiver configurations pass without requiring a
redundant standalone exporter.
Separate structural configuration validation from runtime Cilium
compatibility checks.

The validation and migration commands now produce the same result for a
given file regardless of the machine where the command runs.
Materialize include-by-default capture policies in the shared runtime
conversion so validation and execution use the same selector semantics.

Emit an exclude-by-default policy when migrating application-disabled v1
configurations so migration does not unexpectedly enable app capture.
Reject published OBI fields that have no runtime mapping so validation
cannot silently discard user intent.

Recognize upstream declarative extension points during schema parsing and
report their paths as unsupported components during runtime conversion.
Document why migration must decode v1 structs with their original YAML
module so custom compatibility unmarshallers remain active.
Use representative Docker and Kubernetes configuration inputs to verify
that migrated documents preserve selectors, exporters, routes, and
Kubernetes metadata. Handle case-insensitive v1 log levels so valid
lowercase settings are retained.
Drop the stale support-boundary test retained during the rebase.\n\nIts schema types were replaced by the merged conversion-boundary work\nand it duplicated the current coverage, preventing the package from\ncompiling.
@MrAlias
MrAlias force-pushed the agent/config-v2-cli branch from 12df615 to 97cdf8a Compare July 20, 2026 15:30
MrAlias added 7 commits July 22, 2026 17:57
Legacy discovery.services inputs produced regex capture rules beside a
glob rule for Linux system paths. The mixed selector families made valid
v1 configurations fail migration before output could be emitted.

Emit system-path exclusions in the active selector family and keep
discovery criteria conversion free of runtime logging. Treat the moved
system-path field as a migration alias so its behavior is verified
through the generated capture rules.
The config command group treated -h and --help as unknown subcommands,
returning the usage-error exit code despite documenting help as success.

Recognize both help flags at the group boundary and return the stable
success code while printing the available subcommands.
The receiver v2 fixture expected a single explicit selector while omitting
default_action. The documented include default correctly adds a catch-all
selector, making the fixture assertion inconsistent with its input.

Declare an exclude default so the test represents port-only selection and
the full repository suite can verify the intended receiver conversion.
Legacy discovery.services entries can select only an open port. Because
ports are shared by both selector families, their generated rules were
classified as globs and rejected alongside other legacy regex rules.

Tag non-empty, family-neutral legacy selectors with a match-all executable
regex. This preserves their behavior while keeping newer top-level port
selection in the glob family.
Top-level executable_path produces regex discovery criteria without using
the deprecated discovery.services list. Export treated its default and
system exclusions as globs, so valid v1 input still failed migration.

Derive the rule family from effective criteria and report top-level
selector reshaping. Port-only fallback remains glob because it has no regex
predicate.
Regex executable selection requires every v2 rule to use the same family.
Choosing the legacy exclusion defaults changed v1 behavior when modern
glob defaults or custom exclusions were empty or overridden.

Translate the effective glob exclusion predicates into equivalent anchored
regexes and clear the replaced Linux path list when v2 rules are present.
This preserves explicit empty values and custom exclusion semantics.
Glob exclusions moved into the regex family were rejected by
migration verification. Naive alternative splitting could also corrupt
valid patterns containing lists or escaped commas.

Parse simple alternatives structurally and alias only supported exclusion
predicates that move between selector families. Keep unsupported fields
visible to migration verification.
Legacy exe_path_regexp selectors are exported losslessly to v2 regex
rules, but migration verification treated the normalized field name as a
semantic loss and rejected the configuration.

Alias only that field under legacy include and exclusion selectors. Keep
unsupported selector fields visible to the verification check.
@MrAlias
MrAlias marked this pull request as ready for review July 23, 2026 00:02
@MrAlias
MrAlias requested a review from a team as a code owner July 23, 2026 00:02
Bring this pull request up to date with the latest base branch changes so it can be tested and reviewed against the current codebase.
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.

Add Config v2 validation and migration CLI commands

2 participants