feat(domain-config): Dispatch identity ops per domain - #1202
Merged
Merged
Conversation
This was referenced Sep 4, 2026
|
🦢 Load Test Results Goose Attack ReportPlan Overview
Request Metrics
Response Time Metrics
Status Code Metrics
Transaction Metrics
Scenario Metrics
Error Metrics
|
|
🧪 Tempest Identity Compatibility Results (advisory, non-blocking) rust Failed test IDs |
|
| Project | keystone |
| Branch | feat/domain-config-identity-dispatch |
| Testbed | ubuntu-latest |
🚨 1 Alert
| Benchmark | Measure Units | View | Benchmark Result (Result Δ%) | Upper Boundary (Limit %) |
|---|---|---|---|---|
| get_keyspace | Latency nanoseconds (ns) | 📈 plot 🚷 threshold 🚨 alert (🔔) | 14.13 ns(+139.50%)Baseline: 5.90 ns | 13.79 ns (102.44%) |
Click to view all benchmark results
| Benchmark | Latency | Benchmark Result nanoseconds (ns) (Result Δ%) | Upper Boundary nanoseconds (ns) (Limit %) |
|---|---|---|---|
| Command_Serde/apply/remove | 📈 view plot 🚷 view threshold | 177,180.00 ns(-34.78%)Baseline: 271,649.41 ns | 1,352,235.71 ns (13.10%) |
| Command_Serde/apply/set | 📈 view plot 🚷 view threshold | 181,780.00 ns(-58.77%)Baseline: 440,879.09 ns | 3,265,227.85 ns (5.57%) |
| Command_Serde/pack/delete | 📈 view plot 🚷 view threshold | 108.75 ns(-7.79%)Baseline: 117.93 ns | 155.56 ns (69.91%) |
| Command_Serde/pack/delete_index | 📈 view plot 🚷 view threshold | 95.79 ns(-8.98%)Baseline: 105.24 ns | 138.79 ns (69.02%) |
| Command_Serde/pack/set | 📈 view plot 🚷 view threshold | 194.84 ns(+2.88%)Baseline: 189.39 ns | 244.34 ns (79.74%) |
| Command_Serde/pack/set_index | 📈 view plot 🚷 view threshold | 96.64 ns(-8.07%)Baseline: 105.13 ns | 139.18 ns (69.44%) |
| Command_Serde/unpack/delete | 📈 view plot 🚷 view threshold | 142.06 ns(-23.86%)Baseline: 186.57 ns | 268.44 ns (52.92%) |
| Command_Serde/unpack/delete_index | 📈 view plot 🚷 view threshold | 126.44 ns(-18.67%)Baseline: 155.47 ns | 217.62 ns (58.10%) |
| Command_Serde/unpack/set | 📈 view plot 🚷 view threshold | 236.21 ns(-9.15%)Baseline: 259.99 ns | 354.12 ns (66.70%) |
| Command_Serde/unpack/set_index | 📈 view plot 🚷 view threshold | 125.92 ns(-17.66%)Baseline: 152.93 ns | 211.64 ns (59.50%) |
| Payload_encryption/pack/remove_cmd | 📈 view plot 🚷 view threshold | 100.77 ns(-10.53%)Baseline: 112.63 ns | 150.08 ns (67.14%) |
| Payload_encryption/pack/set_cmd | 📈 view plot 🚷 view threshold | 189.91 ns(-3.64%)Baseline: 197.08 ns | 262.85 ns (72.25%) |
| Payload_encryption/unpack/remove_cmd | 📈 view plot 🚷 view threshold | 144.12 ns(-26.28%)Baseline: 195.49 ns | 283.62 ns (50.82%) |
| Payload_encryption/unpack/set_cmd | 📈 view plot 🚷 view threshold | 247.42 ns(-8.42%)Baseline: 270.18 ns | 373.90 ns (66.17%) |
| Raft_1Node_Latency/prefix/1node | 📈 view plot 🚷 view threshold | 2,450,000.00 ns(-19.22%)Baseline: 3,033,010.30 ns | 7,933,607.76 ns (30.88%) |
| Raft_1Node_Latency/read/1node | 📈 view plot 🚷 view threshold | 34,007.00 ns(-8.64%)Baseline: 37,223.14 ns | 51,541.26 ns (65.98%) |
| Raft_1Node_Latency/remove/1node | 📈 view plot 🚷 view threshold | 543,330.00 ns(-55.53%)Baseline: 1,221,918.44 ns | 11,600,946.69 ns (4.68%) |
| Raft_1Node_Latency/write/1node | 📈 view plot 🚷 view threshold | 516,090.00 ns(-48.26%)Baseline: 997,425.62 ns | 7,588,253.69 ns (6.80%) |
| build_snapshot/default | 📈 view plot 🚷 view threshold | 86,493.00 ns(-31.04%)Baseline: 125,420.52 ns | 277,176.62 ns (31.21%) |
| fernet token/project | 📈 view plot 🚷 view threshold | 1,341.80 ns(-5.84%)Baseline: 1,425.05 ns | 1,798.82 ns (74.59%) |
| get_data_keyspace | 📈 view plot 🚷 view threshold | 0.33 ns(+4.48%)Baseline: 0.32 ns | 0.39 ns (85.01%) |
| get_db | 📈 view plot 🚷 view threshold | 0.33 ns(+5.16%)Baseline: 0.32 ns | 0.39 ns (85.70%) |
| get_fernet_token_timestamp/project | 📈 view plot 🚷 view threshold | 147.30 ns(+5.56%)Baseline: 139.54 ns | 179.15 ns (82.22%) |
| get_keyspace | 📈 view plot 🚷 view threshold 🚨 view alert (🔔) | 14.13 ns(+139.50%)Baseline: 5.90 ns | 13.79 ns (102.44%) |
gtema
force-pushed
the
feat/domain-config-identity-dispatch
branch
from
September 4, 2026 10:37
797db07 to
e9144b0
Compare
Wire the domain configuration resolution layer into identity backend selection (issue #960). Until now `DomainConfigResolver` was built on the provider but nothing consulted it: `IdentityService` held one global `backend_driver` chosen from `[identity] driver` and used it for every domain. `IdentityService` now keeps the full registered-backend map plus an optional `DomainConfigResolver` (present only when `domain_specific_drivers_enabled`). Every backend call site routes through `driver_for` / `driver_for_user` / `driver_for_group`, which resolve the domain's stored `identity/driver` and dispatch to the named backend, falling back to the global driver when per-domain drivers are off, the domain is unknown, no `identity/driver` is stored, or resolution fails. Resolution is cached per domain with no invalidation (a follow-up); a change to a domain's driver through the config API is picked up on restart. `from_driver` keeps a `None` resolver, so existing single-mock unit tests are unaffected. `driver_for_user` / `driver_for_group` mirror python-keystone: while per-domain drivers are on, the public id is looked up in the id mapping and a hit dispatches to that domain's driver, a miss falls back to the global driver. The LDAP identity backend now registers whenever per-domain drivers are enabled, not only when it is the global driver, so a domain config may select `ldap`. Writes to an LDAP-backed domain surface the existing read-only error. Port two python-keystone guards that per-domain dispatch reintroduces: - `_select_identity_driver`: `IdentityBackend::is_domain_aware` (LDAP is not) gates a foreign domain on a non-domain-aware global driver with `DomainNotFound`, keyed on `[identity] default_domain_id`. - `_assert_user_and_group_in_same_backend`: group membership across two identity backends is rejected with a new `IdentityProviderError::CrossBackendNotAllowed` (403), wired into add/remove user-to-group and their expiring variants. Also lands the single-domain SQL identity-driver registration lock deferred from #959: while `domain_configurations_from_database` is on, `DomainConfigService` claims the `SQL` registration before storing an `identity/driver = sql` configuration and releases it when the driver changes away or the configuration is deleted; a second domain claiming it gets HTTP 409. Tests: a `per_domain_dispatch` unit suite covering resolution, per-domain caching, the id-mapping lookup, both ported guards, and password-auth dispatch; a SQL-only `test_integration` suite exercising the resolver and the registration lock end to end through the provider stack. Assisted-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
gtema
force-pushed
the
feat/domain-config-identity-dispatch
branch
from
September 4, 2026 11:14
e9144b0 to
4e14873
Compare
Open
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.
What
Phase 5 of #954 (issue #960): wire the domain configuration resolution
layer into identity backend selection. Until now
DomainConfigResolverwasconstructed on the provider but nothing consulted it —
IdentityServiceheld asingle global
backend_driverchosen once from[identity] driver.Changes
IdentityServicecarries the full registered-backend map and an optionalDomainConfigResolver(Someonly whendomain_specific_drivers_enabled).Every backend call site (~50 — user/group CRUD, auth, list, password,
membership) now routes through
driver_for/driver_for_user/driver_for_group, which resolve a domain's storedidentity/driveranddispatch to the named backend. Fallback to the global driver when per-domain
drivers are off, the domain is unknown, no
identity/driveris stored, orresolution errors.
through the config API takes effect on restart (follow-up issue to be filed).
IdentityService::from_driverkeeps aNoneresolver, so the existingsingle-mock unit tests are unchanged.
not only when it is the global driver. Writes to an LDAP-backed domain surface
the existing read-only error.
DomainConfigServiceclaims theSQLregistration before storing anidentity/driver = sqlconfiguration and releases it when the driver changesaway or the config is deleted, while
domain_configurations_from_databaseison. A second domain claiming it gets HTTP 409.
Out of scope
keystone-manage domain_config_upload/mapping_purgeCLI (follow-up).Tests
identity/service.rs: per-domain dispatch — resolver absent → global driverregression; stored
identity/driverselects the named backend; empty config →global; resolution cached per domain; resolver error → global fallback.
domain_config/service.rs: registration lock — skipped without databaseconfigs;
sqlclaims a free registration then writes; held by another domain→ 409, no write; held by self → write proceeds; switch to non-
sqlreleasesafter the write; delete releases.
openstack-keystone-core(757),openstack-keystone(991),
openstack-keystone-core-typesdomain_config (79), ldap crate;cargo build -p openstack-keystone;opa test policy/domain_config15/15;cargo fmt --all -- --check.🤖 Generated with Claude Code