Repository navigation
feat(rgw): make the member-side RGW apply safe to repeat - #884
Open
johnramsden wants to merge 1 commit into
Open
johnramsden wants to merge 1 commit into
johnramsden wants to merge 1 commit into
Conversation
johnramsden
added this pull request to stack #894
September 23, 2026 04:20
This was referenced Sep 23, 2026
johnramsden
marked this pull request as ready for review
September 23, 2026 04:29
johnramsden
force-pushed
the
rgw-stack/04-member-apply
branch
from
September 23, 2026 18:19
6451a55 to
71e3fa0
Compare
johnramsden
force-pushed
the
rgw-stack/04-member-apply
branch
from
September 24, 2026 19:32
71e3fa0 to
87d31cb
Compare
johnramsden
force-pushed
the
rgw-stack/04-member-apply
branch
from
September 29, 2026 18:43
87d31cb to
4aaf2d8
Compare
johnramsden
force-pushed
the
rgw-stack/04-member-apply
branch
from
September 29, 2026 19:50
4aaf2d8 to
783781a
Compare
EnableRGW in ceph/rgw.go was a one-shot. It wrote radosgw.conf, overwrote server.crt and server.key in place, returned as soon as the service start command succeeded, and RgwServicePlacement.HospitalityCheck refused a gateway that was already running. A caller that repeats a request until the cluster converges needs the opposite, and this is the commit the rest of the series exists to enable: EnableRGW is replaced by applyRGWFrontend, and both "microceph enable rgw" and "microceph certificate set rgw" go through it from here on, not later. applyRGWFrontend renders the wanted radosgw.conf in memory and compares only its "rgw frontends" line against the file on disk: matching line, matching pair on disk and a running service means nothing to do. Comparing only that one line, not the whole file, is deliberate: it is what lets an out-of-band "mon host" refresh made by the existing per-minute updateRadosGWMonHost loop survive an apply untouched instead of the two fighting over the file. The certificate and key move into rgw-tls/<hash of both>/, one directory per pair, because a pair rewritten in place cannot promise the certificate and key change together: a crash between two renames could leave a certificate beside the wrong key, which is exactly what the old flat writeSSLFiles could do. The config only ever names a generation once both files are staged, so switching pairs is one line in the config, and rolling back is pointing that line at the previous, still-intact directory. A journal, radosgw.conf.pending, is written before anything changes: a marker still present at the start of the next apply means an earlier attempt did not finish, so the next apply forces a restart rather than trusting whatever the process happens to be serving, and takes the marker's recorded state, not whatever is half-published on disk, as the rollback target. radosgwConfMu is released before the restart and the readiness wait, which can take minutes, so a slow apply never blocks the unrelated per-minute mon-host refresh, which needs the same lock for one line. In ceph/services_placement_rgw.go, the five-phase pipeline is what finally exercises two things this series built earlier and left unused: PopulateParams validates the request with types.RgwPlacement.Normalized, added inert in "feat(api): describe an RGW placement as an object with explicit TLS intent", and returns ErrRgwFrontendInvalid on a bad one, the sentinel added inert in "fix(services): keep error classes through the service enable path". DbUpdate upserts the rgw_frontends row, added inert in "feat(db): add a table for each member's last applied RGW frontend", in the same transaction as the services row, so presence and frontend can never disagree. HospitalityCheck becomes a deliberate no-op: an already-running gateway must be reconciled, not rejected, which is this branch's whole point. PostPlacementCheck and DbUpdate both call restore if the gateway stops or the database write fails. UpdateRGWCertificates now takes the restart flag itself, and cmdCertificatesRGWPut in api/certificates.go maps its errors with serviceErrorResponse. Three things here are deliberately simple, and each is replaced by name in one of the next three commits: checkRGWReady only checks that the service is active, not that it actually serves, replaced in "feat(rgw): wait until the gateway really serves the requested frontend"; ServiceInit refuses ssl=true without a supplied certificate and key instead of reusing the member's own pair, replaced in "feat(rgw): reuse the member's own pair when TLS is asked for without one"; and DisableRGW only removes the new files and keeps its old mock-runner test rather than converging on a repeat or interrupted call, replaced in "fix(rgw): make RGW disable converge when repeated or interrupted". No cluster pass dispatches RGW yet; a gateway is still placed only by a direct enable or certificate request, until "feat(placement): reconcile RGW across the cluster" wires this pipeline into the reconciler. Co-authored-by: Peter Sabaini <peter.sabaini@canonical.com> Assisted-by: claude-code:claude-fable-5-1 Assisted-by: pi:gpt-6-astra Signed-off-by: John Ramsden <john.ramsden@canonical.com>
johnramsden
force-pushed
the
rgw-stack/04-member-apply
branch
from
October 6, 2026 00:47
783781a to
15eb135
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.
Description
EnableRGWinceph/rgw.gowas a one-shot. It wroteradosgw.conf, overwroteserver.crtandserver.keyin place, returned as soon as the service start command succeeded, andRgwServicePlacement.HospitalityCheckrefused a gateway that was already running. A caller that repeats a request until the cluster converges needs the opposite, and this is the commit the rest of the series exists to enable:EnableRGWis replaced byapplyRGWFrontend, and bothmicroceph enable rgwandmicroceph certificate set rgwgo through it from here on.applyRGWFrontendrenders the wantedradosgw.confin memory and compares only itsrgw frontendsline against the file on disk: matching line, matching pair on disk and a running service means nothing to do. Comparing only that one line, not the whole file, is deliberate: it lets an out-of-bandmon hostrefresh made by the existing per-minuteupdateRadosGWMonHostloop survive an apply untouched instead of the two fighting over the file.The certificate and key move into
rgw-tls/<hash of both>/, one directory per pair, because a pair rewritten in place cannot promise the certificate and key change together: a crash between two renames could leave a certificate beside the wrong key, which the old flatwriteSSLFilescould do. The config only ever names a generation once both files are staged, so switching pairs is one line in the config, and rolling back is pointing that line at the previous, still-intact directory. A journal,radosgw.conf.pending, is written before anything changes: a marker still present at the start of the next apply means an earlier attempt did not finish, so the next apply forces a restart rather than trusting whatever the process happens to be serving, and takes the marker's recorded state, not whatever is half-published on disk, as the rollback target.radosgwConfMuis released before the restart and the readiness wait, which can take minutes, so a slow apply never blocks the unrelated per-minute mon-host refresh, which needs the same lock for one line.In
ceph/services_placement_rgw.go, the five-phase pipeline finally exercises two things this series built earlier and left unused:PopulateParamsvalidates withtypes.RgwPlacement.Normalizedand returnsErrRgwFrontendInvalidon a bad request;DbUpdateupserts thergw_frontendsrow in the same transaction as the services row, so presence and frontend can never disagree.HospitalityCheckbecomes a deliberate no-op: an already-running gateway must be reconciled, not rejected, which is this branch's whole point.Stack: PR 4 of 13. Merge in order. Each PR is one logical change on top of the one before it.
Reviewer note — three things here are deliberately simple, each replaced by name in one of the next three PRs in this stack:
checkRGWReadyonly checks that the service is active, not that it actually serves (replaced in05-readiness);ServiceInitrefusesssl=truewithout a supplied certificate and key instead of reusing the member's own pair (replaced in06-tls-reuse);DisableRGWonly removes the new files and keeps its old mock-runner test rather than converging on a repeat or interrupted call (replaced in07-disable). No cluster pass dispatches RGW yet — a gateway is still placed only by a direct enable or certificate request, until09-reconcilewires this pipeline into the reconciler.Type of change
How has this been tested?
Contributor checklist
Please check that you have: