fix(opensearch): enforce ES/OS endpoint separation at the OS index-creation chokepoint (#36419)#36421
Open
swicken wants to merge 4 commits into
Open
fix(opensearch): enforce ES/OS endpoint separation at the OS index-creation chokepoint (#36419)#36421swicken wants to merge 4 commits into
swicken wants to merge 4 commits into
Conversation
…eation chokepoint (#36419) The endpoint-separation guard only ran in InitServlet -> checkAndInitializeIndex, which executes after the empty-DB starter-load path (Task00004LoadStarter -> bootstrapAndPoint -> bootstrapAndPointOS) has already created the .os shadow indices. With ES==OS configured, the guard correctly halted the migration but too late: the .os indices and their `indicies` rows already existed (fails TC-037). Move the separation check to the single OS index-creation chokepoint (bootstrapAndPointOS), alongside the existing connection gate: - IndexStartupValidator: extract the overlap logic into a shared assertEndpointsSeparate(config) and add a config-only, network-free endpointsAreSeparate() gate reused by both startup validation and the chokepoint. - bootstrapAndPointOS: refuse OS bootstrap and haltMigration() on ES==OS overlap, before the connection gate, so no .os artifacts are created on any startup path. Verified e2e: with ES==OS, 0 .os rows / 0 .os cluster indices, migration halts to Phase 0, dotCMS serves on ES. Adds IndexStartupValidatorTest.
3 tasks
Contributor
Contributor
🤖 dotBot Review (Bedrock)Reviewed 3 file(s); 4 candidate(s) → 3 confirmed, 0 uncertain (unverified, kept for review). Confirmed findings
us.deepseek.r1-v1:0 · Run: #28676689037 · tokens: in: 50825 · out: 21399 · total: 72224 · calls: 9 · est. ~$0.184 |
…nt overlap (#36419) Review follow-up: endpointsAreSeparate() caught all exceptions and returned false, so a configFromProperties() parse failure looked identical to an ES==OS overlap. The caller then logged a hardcoded "OS endpoints overlap ES (same cluster)", misdirecting the operator to a same-endpoint problem that may not exist. - endpointsAreSeparate(): resolve config and run the overlap check in separate try blocks, each with a distinct ERROR (config-resolution failure vs overlap). - bootstrapAndPointOS: soften the WARN to defer to the preceding error for the cause instead of asserting an overlap.
…ets; add tests (#36419) Address review on PR #36421: - Phase 3 (isMigrationComplete): the gate threw away the codebase's "never silently fall back to stale ES" invariant by calling haltMigration() unconditionally. Now it throws in Phase 3 (matching checkAndInitializeIndex and the connection gate); the non-Phase-3 path still halts to ES-only. Bites initOSCatchup Case 1 (Phase-3 DR). - Restore the resolved ES/OS sets in the "Endpoint separation check passed" log line (dropped in the extraction); it now lives in the shared assertEndpointsSeparate. - Add tests: multi-endpoint partial overlap, and config-resolution failure (fail-closed). - Soften the "single chokepoint" comment — it covers working/live bootstrap, not reindex-slot creation (initAndPointReindex).
| /** | ||
| * Unit tests for {@link IndexStartupValidator} endpoint-separation logic. | ||
| * | ||
| * <p>Covers the config-only separation gate ({@link IndexStartupValidator#endpointsAreSeparate()}) |
Member
There was a problem hiding this comment.
This validation must be phase-aware and consider that during Phase 3, ES_ENDPOINTS isn't required
Member
There was a problem hiding this comment.
Then I guess that if we're on phase 3, we shouldn't run this check at all
fabrizzio-dotCMS
requested changes
Jul 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed Changes
Fixes the endpoint-separation guard so it actually prevents OpenSearch
.osshadow indices from being created when the ES and OS clients point at the same cluster.Root cause: the separation check only ran in
InitServlet → checkAndInitializeIndex, which executes after the empty-DB starter-load path (Task00004LoadStarter → bootstrapAndPoint → bootstrapAndPointOS) has already created the.osindices. WithES==OSthe guard halted the migration but too late — the.osindices and theirindiciesrows already existed.ContentletIndexAPIImpl.bootstrapAndPointOS— add a config-only endpoint-separation gate at the single OS index-creation chokepoint, before the existing connection gate. OnES==OSoverlap it logs, callshaltMigration()(ES-only fallback), and skips OS bootstrap — so no.osartifacts are created on any startup path (starter-load or InitServlet).IndexStartupValidator— extract the overlap logic into a sharedassertEndpointsSeparate(config)and add a network-freeendpointsAreSeparate()gate reused by both startup validation and the chokepoint (no duplicated comparison logic).IndexStartupValidatorTest— new unit tests for the separation gate (same-address → false, different → true, scheme-normalized overlap → false, assert throws with the overlap message).Closes #36419
Verification
Unit:
IndexStartupValidatorTest4/4 pass.E2E (
single-node-os-migrationrig, branch image,DOT_ES_ENDPOINTS == DOT_OS_ENDPOINTS == https://opensearch3:9200, Phase 1):.osrows inindicies.oscluster indices.oscreateIndex attemptsLog confirms the gate fires at the chokepoint before any OS creation:
Checklist
Additional Info
Found during QA of #36218 (TC-037), part of the OpenSearch migration QA epic #35476. The existing halt behavior (reset to Phase 0, ES-only fallback, "same endpoint(s)" log) is preserved; this only closes the ordering window on the fresh-install/starter-load path.
Known limitations / follow-ups (from review)
FEATURE_FLAG_OPEN_SEARCH_PHASE0→1+ at runtime without a restart and then running a full reindex creates.osreindex slots viainitAndPointReindex → createContentIndexfan-out, which does not pass through this bootstrap gate. Startup validation remains the primary guard.MigrationPhase.reset()javadoc). If the phase flag lives in the DB system table, the reset is a no-op fromcurrent()'s perspective and dual-writes could continue.