pool: clean up erasure code profile on pool deletion

deleting an erasure coded CephBlockPool left the ec profile
orphaned. recreating with different settings failed because
the old profile could not be overridden.
- delete ec profile during CephBlockPool deletion
- disable --format json on ec profile set command
- fix ec profile name mismatch in CephObjectStore deletion

Signed-off-by: Oded Viner <oviner@redhat.com>
(cherry picked from commit b88648d10f)
This commit is contained in:
Oded Viner authored and Mergify committed 2026-03-19 16:05:04 +00:00
1 parent 59aced4f24
commit 7ec6cb6aef
5 files changed
+58 -5

No files matched your search

@@ -95,7 +95,9 @@ func CreateErasureCodeProfile(context *clusterd.Context, clusterInfo *ClusterInf
args := []string{"osd", "erasure-code-profile", "set", profileName, "--force"}
args = append(args, profilePairs...)
_, err = NewCephCommand(context, clusterInfo, args).Run()
cmd := NewCephCommand(context, clusterInfo, args)
cmd.JsonOutput = false
_, err = cmd.Run()
if err != nil {
return errors.Wrap(err, "failed to set ec-profile")
}
+3 -1
View File
@@ -725,7 +725,9 @@ func DeletePools(ctx *Context, lastStore bool, poolPrefix string) error {
return errors.Wrapf(err, "failed to list erasure code profiles for cluster %s", ctx.clusterInfo.Namespace)
}
// cleans up the EC profile for the data pool only. Metadata pools don't support EC (only replication is supported).
ecProfileName := cephclient.GetErasureCodeProfileForPool(ctx.Name)
// The profile name must match the full pool name used during creation (e.g., "<store>.rgw.buckets.data_ecprofile").
dataPool := poolName(poolPrefix, dataPoolName)
ecProfileName := cephclient.GetErasureCodeProfileForPool(dataPool)
for i := range erasureCodes {
if erasureCodes[i] == ecProfileName {
if err := cephclient.DeleteErasureCodeProfile(ctx.Context, ctx.clusterInfo, ecProfileName); err != nil {
+3 -3
View File
@@ -431,13 +431,13 @@ func deleteStore(t *testing.T, name string, existingStores string, expectedDelet
}
if args[1] == "erasure-code-profile" {
if args[2] == "ls" {
return `["default","myobj_ecprofile"]`, nil
return `["default","myobj.rgw.buckets.data_ecprofile"]`, nil
}
if args[2] == "rm" {
if args[3] == "myobj_ecprofile" {
if args[3] == "myobj.rgw.buckets.data_ecprofile" {
deletedErasureCodeProfile = true
} else {
assert.Fail(t, fmt.Sprintf("the erasure code profile to be deleted should be myobj_ecprofile. Actual: %s ", args[3]))
assert.Fail(t, fmt.Sprintf("the erasure code profile to be deleted should be myobj.rgw.buckets.data_ecprofile. Actual: %s ", args[3]))
}
return "", nil
}
+10
View File
@@ -589,6 +589,16 @@ func deletePool(context *clusterd.Context, clusterInfo *cephclient.ClusterInfo,
return errors.Wrapf(err, "failed to delete pool %q", p.Name)
}
}
// Clean up the erasure code profile for EC pools so that recreating with
// different settings does not fail
if p.IsErasureCoded() {
ecProfileName := cephclient.GetErasureCodeProfileForPool(p.Name)
if err := cephclient.DeleteErasureCodeProfile(context, clusterInfo, ecProfileName); err != nil {
logger.Warningf("failed to delete erasure code profile %q for pool %q: %v", ecProfileName, p.Name, err)
}
}
return nil
}
+39
View File
@@ -200,6 +200,45 @@ func TestDeletePool(t *testing.T) {
p = &cephv1.NamedPoolSpec{Name: "mypool"}
err = deletePool(context, clusterInfo, p)
assert.Error(t, err)
// delete an erasure coded pool should also delete the EC profile
ecProfileDeleted := false
failOnDelete = false
ecExecutor := &exectest.MockExecutor{
MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
emptyPool := "{\"images\":{\"count\":0,\"provisioned_bytes\":0,\"snap_count\":0},\"trash\":{\"count\":1,\"provisioned_bytes\":2048,\"snap_count\":0}}"
if command == "ceph" && args[1] == "lspools" {
return `[{"poolnum":1,"poolname":"ecpool"}]`, nil
} else if command == "ceph" && args[1] == "pool" && args[2] == "get" {
return `{"pool": "ecpool","pool_id": 1,"size":1}`, nil
} else if command == "ceph" && args[1] == "pool" && args[2] == "delete" {
return "", nil
} else if command == "ceph" && args[1] == "erasure-code-profile" && args[2] == "rm" {
assert.Equal(t, "ecpool_ecprofile", args[3])
ecProfileDeleted = true
return "", nil
} else if args[0] == "pool" {
if args[1] == "stats" {
return emptyPool, nil
}
return "", errors.Errorf("rbd: error opening pool %q: (2) No such file or directory", args[3])
}
return "", errors.Errorf("unexpected rbd command %q", args)
},
}
ecContext := &clusterd.Context{Executor: ecExecutor}
ecPool := &cephv1.NamedPoolSpec{
Name: "ecpool",
PoolSpec: cephv1.PoolSpec{
ErasureCoded: cephv1.ErasureCodedSpec{
DataChunks: 2,
CodingChunks: 1,
},
},
}
err = deletePool(ecContext, clusterInfo, ecPool)
assert.NoError(t, err)
assert.True(t, ecProfileDeleted)
}
// TestCephBlockPoolController runs ReconcileCephBlockPool.Reconcile() against a