Skip to content

Store xDS resources as YAML instead of JSON#1321

Merged
minwoox merged 2 commits into
line:mainfrom
minwoox:xds_yaml
Jul 13, 2026
Merged

Store xDS resources as YAML instead of JSON#1321
minwoox merged 2 commits into
line:mainfrom
minwoox:xds_yaml

Conversation

@minwoox

@minwoox minwoox commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Motivation:

  • xDS resources were stored as JSON files. YAML is more human-readable and is the preferred format for configuration in the Kubernetes/Envoy ecosystem.

Modifications:

  • XdsResourceManager: fileName() now returns .yaml; push() uses Change.ofYamlUpsert(); updateOrDelete() falls back to the legacy .json path when the .yaml file is absent; update() atomically removes the old .json and creates the new .yaml in a single commit.
  • XdsResourceWatchingService: changed handleXdsResource() signature from String contentAsText to JsonNode content; both call sites now pass entry.content() / change.content() directly instead of contentAsText(). Also accepts EntryType.YAML and handles UPSERT_YAML.

Result:

  • Newly created xDS resources are stored as .yaml files.
  • Existing .json files remain readable; they are atomically migrated to .yaml on the first update.

Motivation:
- xDS resources were stored as JSON files. YAML is more
  human-readable and is the preferred format for configuration
  in the Kubernetes/Envoy ecosystem.

Modifications:
- `XdsResourceManager`: `fileName()` now returns `.yaml`;
  `push()` uses `Change.ofYamlUpsert()`; `updateOrDelete()`
  falls back to the legacy `.json` path when the `.yaml` file
  is absent; `update()` atomically removes the old `.json` and
  creates the new `.yaml` in a single commit.
- `XdsResourceWatchingService`: changed `handleXdsResource()`
  signature from `String contentAsText` to `JsonNode content`;
  both call sites now pass `entry.content()` /
  `change.content()` directly instead of `contentAsText()`.
  Also accepts `EntryType.YAML` and handles `UPSERT_YAML`.

Result:
- Newly created xDS resources are stored as `.yaml` files.
- Existing `.json` files remain readable; they are atomically
  migrated to `.yaml` on the first update.
@minwoox minwoox added this to the 0.85.0 milestone Jun 30, 2026
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

XDS resource storage, watch handling, Kubernetes endpoint aggregation, webapp lookups, and tests were updated to use YAML resource paths with legacy JSON compatibility paths and migration handling.

Changes

XDS YAML Migration

Layer / File(s) Summary
Storage filenames and update flow
xds/.../internal/XdsResourceManager.java, xds/.../internal/XdsEndpointReadService.java, xds/.../cluster/v1/XdsClusterService.java, xds/.../endpoint/v1/XdsEndpointService.java, xds/.../listener/v1/XdsListenerService.java, xds/.../route/v1/XdsRouteService.java, xds/.../k8s/v1/XdsKubernetesService.java
Resource filenames now use .yaml, updates can remove legacy .json alongside YAML upserts, and endpoint reads fall back to YAML on misses.
Watch pipeline and endpoint flush
xds/.../internal/XdsResourceWatchingService.java, xds/.../endpoint/v1/XdsEndpointUpdateScheduler.java
Watch events now pass JsonNode content, include YAML entries, skip JSON removals during migration, and endpoint flushes branch between legacy migration and direct YAML transforms.
Kubernetes endpoint aggregation migration
xds/.../k8s/v1/XdsKubernetesEndpointFetchingService.java
Kubernetes endpoint aggregation now reuses migration state, removes persisted endpoint files on aggregator removal, and migrates endpoint writes from JSON to YAML.
Webapp xDS resource lookup
webapp/.../XdsTypes.ts, webapp/.../K8sAggregatorStatus.tsx, webapp/.../xdsApiSlice.ts
The webapp now strips either suffix from resource names, prefers YAML history with JSON fallback, and fetches xDS resources through YAML/JSON-aware query logic.
Legacy compatibility tests
xds/src/test/.../XdsLegacyJsonCompatibilityTest.java
New tests cover create conflicts, update migration, and delete behavior for legacy JSON across clusters, listeners, routes, and endpoints.
Updated YAML-based tests
xds/src/test/.../XdsResourceWatchingServiceTest.java, XdsEndpointReadPermissionTest.java, XdsWritePermissionTest.java, k8s/v1/AggregatingMultipleKubernetesTest.java, k8s/v1/XdsKubernetesServiceTest.java, internal/XdsEndpointReadServiceTest.java, it/.../XdsKubernetesNodeIpExtractorTest.java, endpoint/v1/XdsRegisterEndpointTest.java
Existing tests now query YAML paths, serialize YAML-backed content for assertions, push JSON endpoints directly where needed, and verify YAML watch and migration paths.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant XdsResourceManager
  participant XdsResourceWatchingService
  participant XdsEndpointUpdateScheduler
  participant Repository

  XdsResourceManager->>Repository: find existing YAML or JSON
  Repository-->>XdsResourceManager: resolved file
  XdsResourceWatchingService->>Repository: receive YAML/JSON diff
  XdsResourceWatchingService->>XdsEndpointUpdateScheduler: dispatch flush/update
  alt legacy JSON migration
    XdsEndpointUpdateScheduler->>Repository: push remove JSON + upsert YAML
  else direct YAML update
    XdsEndpointUpdateScheduler->>Repository: transform YAML content
  end
  Repository-->>XdsEndpointUpdateScheduler: commit result
Loading

Possibly related PRs

Suggested reviewers: trustin, jrhee17

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main change: moving xDS resource storage from JSON to YAML.
Description check ✅ Passed The description is on-topic and describes the YAML migration and compatibility behavior in the changeset.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java (1)

180-198: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Make the YAML-vs-JSON choice deterministic.

FIND_ONE_WITHOUT_CONTENT over base.* can return the legacy .json even when the .yaml counterpart also exists, so this path may transform stale JSON and upsert it over the YAML content. Fetch both matches without content and prefer .yaml; only migrate .json when no YAML entry exists.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java`
around lines 180 - 198, The selection logic in XdsEndpointUpdateScheduler.handle
currently relies on FIND_ONE_WITHOUT_CONTENT over baseFileName + ".*", which can
nondeterministically pick the legacy .json entry even when a .yaml counterpart
exists. Update the lookup to fetch both matching entries without content, then
explicitly prefer the .yaml path in the branch that calls executeTransform; only
fall back to executeTransformWithMigration when no .yaml entry is present and
the matched file is .json. Ensure the decision is based on the resolved entry
name, not the arbitrary first result from the map.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java`:
- Around line 248-249: The migration path in XdsEndpointUpdateScheduler
currently lets a failure from BatchUpdateTransformer.apply() abort the returned
stage without closing the copied gRPC observers. Update the callback around
entry.revision() / entry.content() so any exception from apply is caught and all
pending observers are completed or failed before propagating the error, similar
to how Command.transform handles cleanup.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java`:
- Around line 201-208: The resource lookup in XdsResourceManager is too broad
because baseFileName + ".*" can match unrelated sibling files and cause false
conflicts or wrong update/delete targets. Update the lookup in the
create/update/delete flow around the repository.find call to check only the
exact .yaml resource path and the legacy .json path, using the existing
fileName/baseFileName handling in XdsResourceManager so FIND_ONE_WITHOUT_CONTENT
only considers those two resource candidates.
- Around line 287-288: Retry the push when a legacy-file removal races with
migration: XdsResourceManager.updateOrDelete() can resolve a .json path that is
deleted and replaced by .yaml before executePush() runs, causing
Change.ofRemoval(legacyFileToRemove) to fail. Update the push flow around
executePush(), createLegacyChange, and the legacyFileToRemove handling so it
re-resolves the current resource path and retries with the YAML target instead
of surfacing the stale removal error.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java`:
- Around line 201-213: In XdsKubernetesEndpointFetchingService’s endpoint
cleanup flow, the current find/delete path only removes the first matching
endpoint file, so a leftover .json or .yaml counterpart can remain. Update the
repository.find(...).handle(...) logic to collect all matching endpoint paths
returned for the endpointBase prefix instead of using FIND_ONE_WITHOUT_CONTENT
and findFirst(), then call removeEndpointFile for each matched YAML/JSON path so
both legacy formats are cleaned up together.
- Around line 188-193: When an aggregator file is removed, the code in
XdsKubernetesEndpointFetchingService currently closes the corresponding
KubernetesEndpointsUpdater but leaves it in kubernetesEndpointsUpdaters. Update
the removal path to also delete the entry from the map after calling
updater.close(), using the existing aggregatorName key so stale updaters do not
accumulate.

---

Outside diff comments:
In
`@xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java`:
- Around line 180-198: The selection logic in XdsEndpointUpdateScheduler.handle
currently relies on FIND_ONE_WITHOUT_CONTENT over baseFileName + ".*", which can
nondeterministically pick the legacy .json entry even when a .yaml counterpart
exists. Update the lookup to fetch both matching entries without content, then
explicitly prefer the .yaml path in the branch that calls executeTransform; only
fall back to executeTransformWithMigration when no .yaml entry is present and
the matched file is .json. Ensure the decision is based on the resolved entry
name, not the arbitrary first result from the map.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bc455d39-0640-4f89-8c2e-49525ea44751

📥 Commits

Reviewing files that changed from the base of the PR and between b0011fd and fdef095.

📒 Files selected for processing (25)
  • it/xds-k8s-node-ip-extractor/src/test/java/com/linecorp/centraldogma/it/xds/k8s/XdsKubernetesNodeIpExtractorTest.java
  • server/src/main/java/com/linecorp/centraldogma/server/command/ContentTransformer.java
  • server/src/main/java/com/linecorp/centraldogma/server/internal/storage/repository/git/AbstractChangesApplier.java
  • server/src/main/java/com/linecorp/centraldogma/server/internal/storage/repository/git/TransformingChangesApplier.java
  • webapp/src/dogma/features/xds/K8sAggregatorStatus.tsx
  • webapp/src/dogma/features/xds/XdsTypes.ts
  • webapp/src/dogma/features/xds/xdsApiSlice.ts
  • xds/src/main/java/com/linecorp/centraldogma/xds/cluster/v1/XdsClusterService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/CentralDogmaXdsResources.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/ControlPlaneService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/listener/v1/XdsListenerService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/route/v1/XdsRouteService.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadPermissionTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsLegacyJsonCompatibilityTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingServiceTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsWritePermissionTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/k8s/v1/AggregatingMultipleKubernetesTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesServiceTest.java

Comment thread xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java Outdated
Comment thread xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java (1)

199-254: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Legacy .json.yaml migration path lacks the atomicity guarantee of the Command.transform path.

The .yaml branch (lines 233-254) uses Command.transform with a ContentTransformer, which recomputes against the latest content at commit time. The legacy .json migration branch (lines 204-232) instead reads content once via repository.get(Revision.HEAD, resolvedFileName), computes newJsonNode synchronously, and pushes a static Change.ofRemoval + Change.ofYamlUpsert pair — a raw overwrite with no "expected old value" check.

Given BatchUpdateTask.flush() releases its lock before the async I/O (pendingUpdates.clear()/scheduledFuture = null happen before repository.find(...)/.get(...) completes), a new update arriving for the same endpoint during that window can schedule an overlapping flush(). If both flushes race down the legacy-migration branch for the same file, the second push may be based on stale content, potentially silently dropping the first flush's register/deregister changes instead of surfacing a conflict.

Please confirm whether Command.push performs conflict detection for full-content Change.ofYamlUpsert/Change.ofRemoval against a moving Revision.HEAD, or add an explicit guard (e.g., patch-style expected-old-value check, similar to Change.ofJsonPatch(fileName, null, jsonNode) used for creates in XdsResourceManager) so the migration path detects concurrent changes rather than silently overwriting them.

#!/bin/bash
# Inspect how full-content upsert/removal changes are conflict-checked during commit application.
rg -n -B5 -A15 'ChangeConflictException' --type=java xds server | rg -n -B15 'ofYamlUpsert|ofJsonUpsert|ofRemoval'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java`
around lines 199 - 254, The legacy .json-to-.yaml migration branch in
XdsEndpointUpdateScheduler uses a read-then-push flow that can race with
overlapping flushes and overwrite newer changes. Update the migration path so
Command.push is either confirmed to enforce conflict detection for
Change.ofRemoval and Change.ofYamlUpsert against Revision.HEAD, or add an
explicit expected-old-value/patch-style guard like the create path uses in
XdsResourceManager. Keep the fix localized around the resolvedFileName branch
and the BatchUpdateTransformer-driven commit flow so concurrent updates fail
with a conflict instead of silently replacing content.
🧹 Nitpick comments (1)
xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java (1)

85-94: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate of XdsResourceManager.alternativeFileName.

Identical logic already exists as a private static method in XdsResourceManager (see xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java, lines 85-93). Consider exposing it as a package-private/public static utility there (or extracting to a shared helper class) and reusing it here instead of re-implementing the same extension-swap logic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java`
around lines 85 - 94, The alternativeFileName logic in
XdsEndpointUpdateScheduler duplicates the existing XdsResourceManager
alternativeFileName implementation; remove the local copy and reuse the shared
method instead. Either make XdsResourceManager.alternativeFileName accessible
from this package or extract the extension-swap helper into a shared utility,
then update XdsEndpointUpdateScheduler to call that shared symbol rather than
reimplementing the .json/.yaml conversion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java`:
- Around line 199-254: The legacy .json-to-.yaml migration branch in
XdsEndpointUpdateScheduler uses a read-then-push flow that can race with
overlapping flushes and overwrite newer changes. Update the migration path so
Command.push is either confirmed to enforce conflict detection for
Change.ofRemoval and Change.ofYamlUpsert against Revision.HEAD, or add an
explicit expected-old-value/patch-style guard like the create path uses in
XdsResourceManager. Keep the fix localized around the resolvedFileName branch
and the BatchUpdateTransformer-driven commit flow so concurrent updates fail
with a conflict instead of silently replacing content.

---

Nitpick comments:
In
`@xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java`:
- Around line 85-94: The alternativeFileName logic in XdsEndpointUpdateScheduler
duplicates the existing XdsResourceManager alternativeFileName implementation;
remove the local copy and reuse the shared method instead. Either make
XdsResourceManager.alternativeFileName accessible from this package or extract
the extension-swap helper into a shared utility, then update
XdsEndpointUpdateScheduler to call that shared symbol rather than reimplementing
the .json/.yaml conversion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 02eb782e-57e2-48df-b1b2-16a41823e562

📥 Commits

Reviewing files that changed from the base of the PR and between fdef095 and 2a27814.

📒 Files selected for processing (10)
  • xds/src/main/java/com/linecorp/centraldogma/xds/cluster/v1/XdsClusterService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/listener/v1/XdsListenerService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/route/v1/XdsRouteService.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadServiceTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (5)
  • xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/route/v1/XdsRouteService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java

@minwoox minwoox marked this pull request as ready for review July 7, 2026 08:27
@minwoox minwoox requested review from ikhoon and jrhee17 as code owners July 7, 2026 08:27

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
xds/src/test/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsRegisterEndpointTest.java (1)

259-309: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Consider asserting migrated content correctness.

The test verifies .yaml presence and .json absence post-migration but doesn't verify that the migrated .yaml file actually contains the correct pre-migration data (e.g., via checkEndpointsViaDiscoveryRequest or content assertion). Adding this would guard against silent data-loss regressions during migration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/test/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsRegisterEndpointTest.java`
around lines 259 - 309, The migration test currently only checks that the legacy
.json file disappears and the .yaml file exists, but it does not verify that the
migrated content matches the original endpoint data. In
registerAndDeregisterMigratesLegacyJsonFile, add an assertion using the existing
discovery/content verification helpers such as checkEndpointsViaDiscoveryRequest
or an equivalent repository content check to confirm the .yaml produced from the
legacy JSON preserves the pre-migration ClusterLoadAssignment and endpoints.
xds/src/test/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesServiceTest.java (1)

379-417: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Consider asserting migrated endpoint content correctness.

Similar to the endpoint-registration migration test, this only checks presence/absence of .yaml/.json files, not that the migrated content matches legacyEndpoints. A content-equality assertion (or a discovery-request check) would strengthen coverage of the migration path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/test/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesServiceTest.java`
around lines 379 - 417, The migration test in
XdsKubernetesServiceTest#createAggregator_migratesLegacyJsonEndpoint only
verifies that the .yaml file exists and the old .json file is removed, but it
does not confirm the migrated content is preserved. Update the test to also
assert that the migrated endpoint entry from
fooGroup.getOrNull(Query.ofYaml(K8S_ENDPOINTS_DIRECTORY + aggregatorId +
".yaml")) matches the original legacyEndpoints (or equivalent discovery output),
so the migration path is validated end-to-end.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java`:
- Around line 351-392: The ChangeConflictException fallback in
XdsKubernetesEndpointFetchingService’s migration handler is too broad and can
hide real YAML upsert conflicts. Update the Command.push(...).handle(...) logic
so legacyJsonMigrated is set to true only when the conflict specifically means
the legacy .json file is missing, and otherwise keep the removal+upsert cleanup
path and let the error surface; use the existing peeled exception handling
around RedundantChangeException and ChangeConflictException to narrow the
fallback.

---

Nitpick comments:
In
`@xds/src/test/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsRegisterEndpointTest.java`:
- Around line 259-309: The migration test currently only checks that the legacy
.json file disappears and the .yaml file exists, but it does not verify that the
migrated content matches the original endpoint data. In
registerAndDeregisterMigratesLegacyJsonFile, add an assertion using the existing
discovery/content verification helpers such as checkEndpointsViaDiscoveryRequest
or an equivalent repository content check to confirm the .yaml produced from the
legacy JSON preserves the pre-migration ClusterLoadAssignment and endpoints.

In
`@xds/src/test/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesServiceTest.java`:
- Around line 379-417: The migration test in
XdsKubernetesServiceTest#createAggregator_migratesLegacyJsonEndpoint only
verifies that the .yaml file exists and the old .json file is removed, but it
does not confirm the migrated content is preserved. Update the test to also
assert that the migrated endpoint entry from
fooGroup.getOrNull(Query.ofYaml(K8S_ENDPOINTS_DIRECTORY + aggregatorId +
".yaml")) matches the original legacyEndpoints (or equivalent discovery output),
so the migration path is validated end-to-end.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1e5f06ef-e9f1-47f4-9f7f-7d972ca40e02

📥 Commits

Reviewing files that changed from the base of the PR and between 2a27814 and 6840cd2.

📒 Files selected for processing (22)
  • it/xds-k8s-node-ip-extractor/src/test/java/com/linecorp/centraldogma/it/xds/k8s/XdsKubernetesNodeIpExtractorTest.java
  • webapp/src/dogma/features/xds/K8sAggregatorStatus.tsx
  • webapp/src/dogma/features/xds/XdsTypes.ts
  • webapp/src/dogma/features/xds/xdsApiSlice.ts
  • xds/src/main/java/com/linecorp/centraldogma/xds/cluster/v1/XdsClusterService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/listener/v1/XdsListenerService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/route/v1/XdsRouteService.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsRegisterEndpointTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadPermissionTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadServiceTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsLegacyJsonCompatibilityTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingServiceTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsWritePermissionTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/k8s/v1/AggregatingMultipleKubernetesTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesServiceTest.java
✅ Files skipped from review due to trivial changes (2)
  • xds/src/main/java/com/linecorp/centraldogma/xds/listener/v1/XdsListenerService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/route/v1/XdsRouteService.java
🚧 Files skipped from review as they are similar to previous changes (13)
  • webapp/src/dogma/features/xds/XdsTypes.ts
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsWritePermissionTest.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/cluster/v1/XdsClusterService.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadPermissionTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingServiceTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/k8s/v1/AggregatingMultipleKubernetesTest.java
  • it/xds-k8s-node-ip-extractor/src/test/java/com/linecorp/centraldogma/it/xds/k8s/XdsKubernetesNodeIpExtractorTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadServiceTest.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsLegacyJsonCompatibilityTest.java
  • webapp/src/dogma/features/xds/xdsApiSlice.ts
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingService.java

@jrhee17 jrhee17 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.

Question: It seems like migration is done lazily (on each push for a file)
Will there be any attempt to migrate at once? Or would it be helpful if we can at least visualize the number of json files vs yaml files that are used in the xds repo?

}
// If the change is redundant, we just ignore it and complete
// the stream observer without error.
if (resolvedFileName.endsWith(".json")) {

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.

Note) Understood the assumption is that only one of yaml or json had been stored

case REMOVE:
// Skip if this is an atomic .json → .yaml migration commit: the .json is being
// removed while the same resource is upserted as .yaml in the same diff.
if (path.endsWith(".json")) {

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.

👍 👍

@minwoox

minwoox commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Will there be any attempt to migrate at once?

Yeah, I'm preparing. 😉

Or would it be helpful if we can at least visualize the number of json files vs yaml files that are used in the xds repo?

I have a command for checking it. 😉

@ikhoon ikhoon 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.

👍 👍

@minwoox minwoox merged commit 9a65925 into line:main Jul 13, 2026
11 of 13 checks passed
@minwoox minwoox deleted the xds_yaml branch July 13, 2026 09:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants