diff --git a/bootstrap/site-join.js b/bootstrap/site-join.js index 7218b35..bb6bbef 100644 --- a/bootstrap/site-join.js +++ b/bootstrap/site-join.js @@ -5,7 +5,13 @@ * setup.env sets CFG_MASTER_DIRECTORY_URL + CFG_MASTER_DIRECTORY_JOIN_KEY: * * docker compose exec sso-manager node /bootstrap/site-join.js \ - * https://sso.master.example.com stj_9f2e... + * https://sso.master.example.com stj_9f2e... https://sso.this-site.example.com + * + * The third argument (selfUrl, optional) is this site's own public SSO host + * (setup.sh passes https://$CFG_SSO_HOST) -- without it the join still + * succeeds, it just registers for one-time adoption only: the master has no + * way to reach this spoke to push live replication resync pings at it (see + * theta-directory's docs/site-join.md and utils/site_replicate.js). * * Self-contained (Node built-ins + global fetch), same rule as bootstrap.js — * it does NOT require the SSO's internal models. It logs in as the bootstrap @@ -26,6 +32,7 @@ const SSO_INTERNAL = 'http://localhost:3001'; const masterUrl = process.argv[2]; const joinKey = process.argv[3]; +const selfUrl = process.argv[4] || ''; function log(msg) { console.error('[site-join] ' + msg); } @@ -52,7 +59,7 @@ async function main() { const res = await fetch(`${SSO_INTERNAL}/api/site/join`, { method: 'POST', headers: { 'auth-token': token, 'Content-Type': 'application/json' }, - body: JSON.stringify({ masterUrl, joinKey }), + body: JSON.stringify({ masterUrl, joinKey, ...(selfUrl ? { selfUrl } : {}) }), }); const text = await res.text().catch(() => ''); let data = null; @@ -68,11 +75,13 @@ async function main() { } log(`Joined master site ${masterUrl} as ${data.siteSlug || '?'}`); + log(`Live replication: ${(data.replication && data.replication.note) || 'unknown'}`); console.log([ `JOINED=yes`, `SITE_SLUG=${data.siteSlug || ''}`, `RESOURCES=${(data.resources && data.resources.created) || 0}`, - `LDAP=${(data.ldap && data.ldap.note) || ''}` + `LDAP=${(data.ldap && data.ldap.note) || ''}`, + `LIVE_REPLICATION=${(data.replication && data.replication.live) ? 'yes' : 'no'}` ].join(' ')); } diff --git a/setup.env.example b/setup.env.example index ab3422c..401f4e8 100644 --- a/setup.env.example +++ b/setup.env.example @@ -55,7 +55,12 @@ CFG_DOMAIN=example.com # -> Mint key). Honored ONLY on a first-run bring-up (before ./config/ exists), # so it can never merge an already-populated directory; re-runs ignore it. # The spoke adopts the master's users/groups/resources and persists its spoke -# role in ./config/site.json (isMaster=false, masterUrl, siteSlug). +# role in ./config/site.json (isMaster=false, masterUrl, siteSlug). It also +# registers itself with the master (using this site's own CFG_SSO_HOST) so +# future catalog changes on the master get pushed here live instead of this +# being a one-time snapshot -- the master must be able to reach THIS site's +# CFG_SSO_HOST for that part to work; if it can't (this site has no inbound +# path), the join still succeeds, it just never receives live updates. #CFG_MASTER_DIRECTORY_URL=https://sso.master.example.com #CFG_MASTER_DIRECTORY_JOIN_KEY=stj_9f2e... diff --git a/setup.sh b/setup.sh index 50fdeed..786444d 100755 --- a/setup.sh +++ b/setup.sh @@ -1161,8 +1161,12 @@ fi # joined reports "already a spoke" and setup continues. if [[ -n "${CFG_MASTER_DIRECTORY_URL:-}" && -n "${CFG_MASTER_DIRECTORY_JOIN_KEY:-}" ]]; then info "Joining master site ${CFG_MASTER_DIRECTORY_URL} (CFG_MASTER_DIRECTORY_*)..." + # selfUrl (https://$CFG_SSO_HOST, already derived above) registers this + # spoke for LIVE replication -- without it the join still succeeds, but + # the master has no way to reach this spoke to push resync pings, so it + # only ever gets the one-time snapshot from the moment it joined. if ! "${COMPOSE[@]}" exec -T sso-manager node /bootstrap/site-join.js \ - "$CFG_MASTER_DIRECTORY_URL" "$CFG_MASTER_DIRECTORY_JOIN_KEY"; then + "$CFG_MASTER_DIRECTORY_URL" "$CFG_MASTER_DIRECTORY_JOIN_KEY" "https://$CFG_SSO_HOST"; then die "site join failed — check the master URL + site join key (mint one on the master's Site Join Keys card)." fi else