Generate the Ceph fsid once per install instead of compiling it in - #1502
Draft
traviswu-bigstack wants to merge 1 commit into
Draft
traviswu-bigstack wants to merge 1 commit into
traviswu-bigstack wants to merge 1 commit into
Conversation
traviswu-bigstack
marked this pull request as draft
September 17, 2026 01:44
…iling it in Every CubeCOS cluster reported the same Ceph fsid, because it was a compile-time constant that the ceph.fsid tunable merely defaulted to. Two installs were indistinguishable to anything that asks "is this the same cluster", which is what cubecos#1490 is about. The fsid is now minted once, by the bootstrap node, and recorded at /etc/cube/cos/ceph/fsid -- inside a directory the ceph module already declares to CONFIG_MIGRATE, so it survives the partition switch an upgrade performs. Every later commit reads the record rather than recomputing, which matters because the fsid reaches monmaptool: a value that drifted between commits would build a monmap the mons reject. Generated, not derived. Deriving it from cubesys.seed would have matched what rbd_secret_uuid already does, but the seed also generates the cluster's ssh key, and the fsid is published in every ceph.conf -- a v5 UUID would hand anyone an offline oracle for a low-entropy secret. The seed is separately unsafe to derive from while cubecos#1500 stands. An existing cluster never moves. On a node that predates the record, ceph_fsid_current reads the fsid already in ceph.conf, else extracts it from this node's mon store -- /var/lib/ceph is migrated, and the extract works with ceph down, which an upgrade commit needs. Whatever it finds is recorded and wins over anything that would be generated, so an upgraded cluster keeps the fsid its mons and OSDs already carry, the old constant included; LEGACY_FSID is kept only to name it. A joining node takes the bootstrap node's fsid over ssh, inside the retry loop that already waits for the master's mon bootstrap -- the same wait, for the same reason, since neither answer exists until the master has made it. Only the bootstrap node may mint, so a cluster gets exactly one. Nothing falls back to a constant on failure: an unresolved fsid refuses the commit, and sync_ceph_config keeps the existing ceph.conf rather than rewriting it with a worse one. Every value is shape-checked as a UUID before use, because HexUtilPOpen discards exit status and the shape is the only signal a C++ caller gets (cubecos#1486). Validate() now rejects a malformed operator-pinned ceph.fsid, which ValidateRegex did not. Refs #1490 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cE5vKGkQQn3nAnn9TLKAU Signed-off-by: Travis Wu <travis.wu@bigstack.co>
traviswu-bigstack
force-pushed
the
travis.wu/ceph-fsid-per-install
branch
from
September 17, 2026 02:36
8e80546 to
19388f4
Compare
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 type of PR is this?
/kind bug
What this PR does / why we need it
Every CubeCOS cluster reports the same Ceph fsid. It was a compile-time constant that
ceph.fsidmerely defaulted to, so two installs are indistinguishable to anything that asks "is this the same cluster?".The fsid is now minted once, by the bootstrap node, and recorded at
/etc/cube/cos/ceph/fsid— inside a directory the ceph module already declares toCONFIG_MIGRATE, so it survives the partition switch an upgrade performs with no new migrate line. Every later commit reads the record rather than recomputing, which matters because the fsid reachesmonmaptool: a value that drifted between commits would build a monmap the mons reject.ceph_fsid_resolveowns the decision andconfig_ceph.cpponly asks. Resolution order:ceph.fsid, when an operator has pinned one. The tunable's default changes from the constant to"", so empty now means "not pinned" rather than "use the shared one".ceph.conf, else this node's own mon store viaceph_mon_map_create, which extracts with ceph down. That second source is the one that matters: an upgrade commit runs before ceph is necessarily up, and/var/lib/cephisCONFIG_MIGRATE'd.Generated, not derived. Deriving from
cubesys.seedwould have matched whatrbd_secret_uuidalready does (uuidgen --sha1 --namespace @dns), and it was the first thing I tried to justify. Two reasons not to: the seed also generates the cluster's SSH key (config_cubesys.cpp:368), and the fsid is published in everyceph.conf— a v5 UUID there hands anyone an offline oracle against a low-entropy secret. Independently, the seed is not unique today (#1500).An existing cluster never moves. Step 2 outranks step 3, so an upgraded cluster adopts and records the fsid its mons and OSDs already carry, the old constant included.
LEGACY_FSIDis kept only to name it.A joining node takes the bootstrap node's fsid over ssh, inside the retry loop that already waits for the master's mon bootstrap — the same wait for the same reason, since neither answer exists until the master has made it. Only the bootstrap node may mint, so a cluster gets exactly one.
Nothing falls back to a constant. An unresolved fsid refuses the commit, and
sync_ceph_configkeeps the existingceph.confrather than rewriting it with a worse one. Every value is shape-checked as a UUID before use, on both sides, becauseHexUtilPOpendiscards exit status and the shape is the only signal a C++ caller gets — same lesson as #1486.Validate()now also rejects a malformed operator-pinnedceph.fsid, whichValidateRegexdid not.Which issue(s) this PR fixes
Fixes #1490
Special notes for your reviewer
Not exercised on a cluster.
config_ceph.ocompiles in the jail (which caught one real bug —newValue()returnsstd::string, notconst char*), andcore/sdk_sh/tests/test_ceph_fsid.shis 16/16, mutation-tested two ways: lettingceph_fsid_recordoverwrite gives 1 failure, dropping the UUID shape check gives 10. That is the whole of the verification. The two runs I would want before this merges:c6e64c49-09cf-463b-9d1c-b6645b4b3b85, confirming it adopts and records rather than mints;Two things I would like a second opinion on:
ceph.confthat survives the partition switch nor a mon store, so on upgrade it resolves by ssh to the master. That is fine if control nodes roll first, and the loop waits, but it is a cross-node dependency where there was none — the old constant needed nobody.An earlier revision of this PR was larger. Dropped on review: a live
ceph fsidprobe (redundant — the CLI needsceph.confto find the mons, so it can never answer where readingceph.confcould not), andsync_ceph_configasking a peer for the fsid (it resyncs an already-bootstrapped node, so the record exists; andGetMasteron a single-node cluster would have ssh'd to self). I also considered doing the adoption in the module's migrate hook, usingprevRootDir— but no hook in this repo uses that argument as a path, and I did not want the design resting on an assumption about it.Related, not fixed here: #1500 — FTS accepts an empty
cubesys.seed, which makes SSH key material identical across installs. Same shape of defect (a cluster identity that is constant across installs), and the more serious of the two.Additional documentation