c1b3ba1c34
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
28 lines
871 B
Go
28 lines
871 B
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|