Fixes #33572: scope search requests to the cluster alias instead of the whole cluster - #33574
Open
mohityadav766 wants to merge 2 commits into
Open
mohityadav766 wants to merge 2 commits into
mohityadav766 wants to merge 2 commits into
Conversation
…he whole cluster
Search indexing died before its first record on every deployment whose search
role is confined to its own <clusterAlias>* prefix:
RuntimeException: Cannot determine the live chunk target for
<clusterAlias>_data_asset_embeddings_chunks
Caused by: java.io.IOException: Forbidden access
resolveLiveChunkTargetStrict probed the chunk read alias with
existsAlias(name), which builds HEAD /_alias/{name} — no index in the path.
OpenSearch resolves that against _all, so it needs cluster-wide
indices:admin/aliases/get and a prefix-scoped role is denied. The 403 cannot
degrade to "no alias" either: RestClientTransport raises TransportException
("Forbidden access") on 403 before the BooleanEndpoint status mapping runs.
requireResolvedLiveChunkTarget then threw, and RecreateWithEmbeddings stages
the chunk recreate before super.reCreateIndexes, so the whole run aborted —
the "failed, 0 records" signature.
Introduced by #30364, which both un-gated the staged recreate (previously dead
code) and swapped a swallowed GET /_alias/{base} for this strict probe. Before
it, the same 403 was caught at debug and resolution fell through to the
index-scoped HEAD /{base}, which the role does allow.
Replace it with GET /{base}/_alias. Naming the index in the path is authorized
by the same prefix-scoped role, and one call covers both layouts because the
response is keyed by physical index: the staged generation when base is the
read alias, base itself when it is still the legacy physical index. 404 means
neither exists yet.
Also make beginStagedChunkRecreate degrade to "not staged" on an indeterminate
probe rather than throw. Skipping the stage deletes nothing — the orphan sweep
below it never runs — so an unanswerable probe is a reason to leave the chunk
index alone, not to fail an entity reindex that does not need it. The promote
path stays strict: that swap does remove the previous target.
Two more requests that resolved past the cluster alias:
- getIndicesByAlias (OpenSearch and Elasticsearch) used the same cluster-wide
form for both the existsAlias pre-probe and GetAliasRequest.name(). Its 403
was swallowed, so it silently returned an empty index set. Now index-scoped,
with the pre-probe dropped (the 404 branch already covers "no such alias")
and the result filtered back to indices that actually carry the alias, since
GET /{name}/_alias resolves the name as index-or-alias.
- indexTemplatesMatch read om_*, returning every co-tenant's templates on a
shared cluster. Scoped to om_<clusterAlias>_*.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
❌ PR checklist incompleteThis PR cannot be merged until the following are addressed on its linked issue:
The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically. Maintainers can bypass this check by adding the |
|
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.



Describe your changes:
Fixes #33572
Search indexing died before its first record on every deployment whose search role is confined to its own
<clusterAlias>*prefix — every shared-tenancy Collate Cloud cluster:resolveLiveChunkTargetStrictprobed the chunk read alias withexistsAlias(name), which buildsHEAD /_alias/{name}— no index in the path. OpenSearch resolves that against_all, so it needs cluster-wideindices:admin/aliases/get, and a prefix-scoped role is denied. The 403 cannot degrade to "no alias" either:RestClientTransport.getHighLevelResponseraisesTransportException("Forbidden access")on status 403 before theBooleanEndpointstatus→boolean mapping runs.requireResolvedLiveChunkTargetthen threw, andRecreateWithEmbeddingsstages the chunk recreate beforesuper.reCreateIndexes— so the whole run aborted, producing thefailed · 0 recordssignature.Introduced by #30364, which both un-gated the staged recreate (previously dead code behind a flag that could never be true) and swapped a swallowed
GET /_alias/{base}for this strict probe. Before it, the same 403 was caught at debug level and resolution fell through to the index-scopedHEAD /{base}, which the role does allow.The rule this PR enforces: every request names a concrete index or pattern beginning with the cluster alias; nothing resolves to
_all.What changed
OpenSearchVectorService.resolveLiveChunkTargetStrict—GET /{base}/_aliasinstead ofHEAD /_alias/{base}+HEAD /{base}. Naming the index in the path is authorized by the same prefix-scoped role, and one call covers both layouts because the response is keyed by physical index: the staged generation whenbaseis the read alias,baseitself when it is still the legacy physical index. A 404 means neither exists yet.beginStagedChunkRecreate— degrades to "not staged" on an indeterminate probe instead of throwing. Skipping the stage deletes nothing (the orphan sweep below it never runs), so an unanswerable probe is a reason to leave the chunk index alone, not to fail an entity reindex that does not need it. The promote path stays strict — that swap does remove the previous target.getIndicesByAlias(OpenSearch + Elasticsearch) — used the same cluster-wide form for both theexistsAliaspre-probe andGetAliasRequest.name(). Its 403 was swallowed, so it silently returned an empty index set. Now index-scoped, pre-probe dropped (the 404 branch already covers "no such alias"), and the result filtered back to indices that actually carry the alias sinceGET /{name}/_aliasresolves the name as index-or-alias.SearchRepository.indexTemplatesMatch— readom_*, returning every co-tenant's templates on a shared cluster. Scoped toom_<clusterAlias>_*.No new cluster-wide grant is required. Notably, granting
indices:admin/aliases/geton*would have "fixed" (1) at the cost of letting any tenant enumerate the others' indices, which is why the fix belongs in the request rather than the role.Type of change:
High-level design:
N/A — small change.
Tests:
Use cases covered
getIndicesByAliasreturns only indices that actually carry the aliasUnit tests
Files updated:
OpenSearchVectorServiceChunkStagingTest—resolveLiveChunkTarget_asksForTheChunkIndexByName_notForAClusterWideAliasLookupasserts the capturedGetAliasRequestcarriesindexand an emptyname;..._treatsA404AsFreshInstallRatherThanAnIndeterminateProbe;beginStagedChunkRecreate_skipsStagingWhenTheLiveTargetProbeIsIndeterminatereplaces the old abort-on-probe-failure test and verifies nothing in the cluster is touchedOpenSearchIndexManagerTest/ElasticSearchIndexManagerTest—testGetIndicesByAlias_NamesTheIndexInThePathNotTheAlias, plusSuccessfulRetrievalextended with a decoy index that does not carry the aliasIndexTemplateManagerTest—liveTemplateLookupIsScopedToThisDeploymentsClusterAliasResult:
Tests run: 2435, Failures: 0, Errors: 0acrossorg.openmetadata.service.search.**.Backend integration tests
Ingestion integration tests
Playwright (UI) tests
Manual testing performed
Verified against the upstream client and server sources rather than a live restricted cluster:
ExistsAliasRequest's endpoint emits/_alias/{name}when no index is set, and/{index}/_alias/{name}when one is — confirming the old probe named no indexRestClientTransport.getHighLevelResponsethrowsTransportException("Forbidden access")on 403 before the boolean-endpoint mapping, confirming the 403 could never read asfalseGetAliasRequest'sSimpleEndpointtreats 404 as an error, so the fresh-install branch arrives asOpenSearchException(404)— the same contract the pre-existinggetIndicesByAlias404 handling already relies onUI screen recording / screenshots:
Not applicable.
Follow-ups (not in this PR)
PUT /_search/pipeline/hybrid-rrfneedscluster:admin/search/pipeline/put, which a prefix-scoped role does not have. It is caught and warned, so it does not fail the reindex — but the pipeline is then never created and hybrid search silently degrades. The clean fix is an inline (ad-hoc) search pipeline in the request body, which needs no cluster permission and lets per-tenant weights actually differ; that change spans the query side too, so it is separate.SearchClusterFitnessAnalyzer's/_cat/indicesand/_cat/aliasesprobes could be scoped to{clusterAlias}*. They already degrade gracefully via the analyzer'sinaccessibleset, so this is cleanup rather than a fix.cluster_manage_index_templatesremains cluster-wide — index-template actions cannot be pattern-scoped by the security plugin. Item 4 above narrows what we read, but closing the write side needs a change outside OpenMetadata.Checklist:
Fixes <issue-number>: <short explanation>Fixes #<issue-number>above.🤖 Generated with Claude Code
The PR is not yet safe to merge because prefix-scoped deployments still cannot apply the hybrid RRF pipeline or saved ranking weights.
Findings
Summary
This PR scopes alias and template discovery to deployment-specific index patterns, makes an indeterminate chunk probe non-fatal, and begins replacing the cluster-global hybrid pipeline with per-query pipeline definitions.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Save hybrid search weights] --> B[Attempt named pipeline PUT] B -->|Prefix-scoped role rejects PUT| C[Log warning and continue] C --> D[Build hybrid search request] D -. no caller of inline definition .-> E[Request sent without RRF pipeline] E --> F[Saved keyword and semantic weights are not applied]Reviews (2) · Last reviewed commit: "Fixes #33587: let hybrid ranking ride al..."