Add immutable placement-target selection to Bucket
Buckets could not choose which RGW placement target (and thus durability profile) backs them, so all data landed on the cluster default. The estate's radosgw exposes two targets - default-placement (3x replicated) and ec (4+1 erasure-coded) - and archival workloads want ec. - Validate spec.placementTarget: a DNS-ish pattern, 63-char cap, and a CEL self==oldSelf immutability rule (RGW fixes placement at bucket creation and cannot move a bucket between targets); make spec.zonegroup immutable too. - Thread the target into the S3 CreateBucket LocationConstraint via the existing helper; an empty zonegroup yields ":<target>", selecting the local zonegroup so callers need not name the zonegroup api-name. - Read the live placement_rule and zonegroup back from the Admin Ops bucket stats and surface them: status.placementTarget plus a Placement print column. - Guard the controller: if a live bucket's placement differs from spec, set an Error phase with a PlacementImmutable reason instead of deleting/recreating. - Cover locationConstraint construction, placement readback (httptest), and the placementConflict guard with tests; document targets and immutability in the README and add config/samples/06-bucket-ec.yaml. Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package controller
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPlacementConflict(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
specPlacement string
|
||||
livePlacement string
|
||||
want bool
|
||||
}{
|
||||
{"unset spec never conflicts", "", "default-placement", false},
|
||||
{"unset spec unset live", "", "", false},
|
||||
{"matching ec", "ec", "ec", false},
|
||||
{"matching default", "default-placement", "default-placement", false},
|
||||
{"ec requested but default live", "ec", "default-placement", true},
|
||||
{"default requested but ec live", "default-placement", "ec", true},
|
||||
{"spec set live empty", "ec", "", true},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := placementConflict(tc.specPlacement, tc.livePlacement); got != tc.want {
|
||||
t.Errorf("placementConflict(%q,%q)=%v want %v", tc.specPlacement, tc.livePlacement, got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user