feat(directory): LDAP replication status + per-spoke detail on the Multi-Site modal
The modal previously showed zero LDAP replication status -- no ServerID, no MMR active/inactive indicator, nothing -- and only aggregate counts, never per-spoke detail (no-inbound flag, relay note, assigned ldapServerId). An operator had no way to tell whether replication was actually configured/working without SSHing in. Added utils/ldap_replication.js's currentSlapdServerId(), which reads the ACTUAL running ServerID straight from this node's own slapd.conf -- distinct from what GET /ldap-peers / /ldap-replication-config currently ADVERTISE for it, which can genuinely disagree right after a promotion or a new spoke joining (OpenLDAP's static config only reloads at process start). GET /directory-admin/site-status now surfaces both plus a `stale` flag, and a full spokes list (not just a count) with each one's endpoint, LDAP ServerID, and relay path. directory.ejs renders this as an "LDAP Replication (MMR)" status row (ServerID, peer count, a "needs setup.sh re-run" warning when stale) and a Registered Spokes table. Verified two ways: real running containers via docker-compose.multisite-e2e.yml (new site-status assertions), and an actual browser session against the promoted node -- screenshotted the rendered modal showing the real registered spoke with its assigned ldapServerId and the correctly-surfaced "not configured (standalone)" MMR state (this test node never ran site-ldap-register.js against it, so the mismatch itself is the expected, documented behavior).
This commit is contained in:
@@ -229,6 +229,19 @@ async function main() {
|
||||
const selfInOwnPeerList = (spokeLdapCfg.peers || []).some(p => p.ldapServerId === spokeLdapCfg.ldapServerId);
|
||||
if (selfInOwnPeerList) fail(`spoke's own peer list should not include itself, got ${JSON.stringify(spokeLdapCfg.peers)}`);
|
||||
|
||||
step('Verifying the master\'s own site-status surfaces LDAP status + per-spoke detail (Multi-Site modal data)');
|
||||
const { body: masterStatus } = await api(MASTER_URL, '/api/directory-admin/site-status', { token: masterToken });
|
||||
if (!masterStatus.ldap || masterStatus.ldap.advertisedServerId !== 1) {
|
||||
fail(`master's site-status should report ldap.advertisedServerId 1, got ${JSON.stringify(masterStatus.ldap)}`);
|
||||
}
|
||||
if (masterStatus.ldap.peersCount !== 1) {
|
||||
fail(`master's site-status should report exactly 1 LDAP peer (the spoke), got ${JSON.stringify(masterStatus.ldap)}`);
|
||||
}
|
||||
const statusSpokeEntry = (masterStatus.spokes || []).find(s => s.endpoint === 'http://spoke:3001');
|
||||
if (!statusSpokeEntry || typeof statusSpokeEntry.ldapServerId !== 'number') {
|
||||
fail(`master's site-status spokes list should include the spoke with an ldapServerId, got ${JSON.stringify(masterStatus.spokes)}`);
|
||||
}
|
||||
|
||||
step('Verifying the spoke adopted the master\'s pre-join catalog');
|
||||
const spokeResources = await api(SPOKE_URL, '/api/directory-admin/resources', { token: spokeToken });
|
||||
const adopted = (spokeResources.body.results || spokeResources.body.resources || spokeResources.body || []);
|
||||
|
||||
Reference in New Issue
Block a user