Merge pull request #5058 from travisn/object-no-pools
Allow creation of object store with pre-existing pools
This commit is contained in:
5 files changed
+84
-22
No files matched your search
@@ -236,25 +236,26 @@ func (r *ReconcileCephObjectStore) reconcile(request reconcile.Request) (reconci
|
||||
return r.setFailedStatus(cephObjectStore, "failed to reconcile service", err)
|
||||
}
|
||||
|
||||
// RECONCILE POOLS
|
||||
logger.Debug("reconciling object store pools")
|
||||
objContext := NewContext(r.context, cephObjectStore.Name, cephObjectStore.Namespace)
|
||||
|
||||
// RECONCILE POOLS
|
||||
logger.Info("reconciling object store pools")
|
||||
metadataPoolToModel := *cephObjectStore.Spec.MetadataPool.ToModel("")
|
||||
dataPoolToModel := *cephObjectStore.Spec.DataPool.ToModel("")
|
||||
err = createPools(objContext, metadataPoolToModel, dataPoolToModel)
|
||||
err = createPools(objContext, cephObjectStore.Spec, metadataPoolToModel, dataPoolToModel)
|
||||
if err != nil {
|
||||
return r.setFailedStatus(cephObjectStore, "failed to create object pools", err)
|
||||
}
|
||||
|
||||
// RECONCILE REALM
|
||||
logger.Debug("reconciling object store realms")
|
||||
logger.Info("reconciling object store realms")
|
||||
err = reconcileRealm(objContext, serviceIP, cephObjectStore.Spec.Gateway.Port)
|
||||
if err != nil {
|
||||
return r.setFailedStatus(cephObjectStore, "failed to create object store realm", err)
|
||||
}
|
||||
|
||||
// CREATE/UPDATE
|
||||
logger.Debug("reconciling object store deployments")
|
||||
logger.Info("reconciling object store deployments")
|
||||
reconcileResponse, err = r.reconcileCreateObjectStore(cephObjectStore)
|
||||
if err != nil {
|
||||
return r.setFailedStatus(cephObjectStore, "failed to create object store deployments", err)
|
||||
@@ -270,7 +271,6 @@ func (r *ReconcileCephObjectStore) reconcile(request reconcile.Request) (reconci
|
||||
// Return and do not requeue
|
||||
logger.Debug("done reconciling")
|
||||
return reconcile.Result{}, nil
|
||||
|
||||
}
|
||||
|
||||
func (r *ReconcileCephObjectStore) reconcileCreateObjectStore(cephObjectStore *cephv1.CephObjectStore) (reconcile.Result, error) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
|
||||
ceph "github.com/rook/rook/pkg/daemon/ceph/client"
|
||||
"github.com/rook/rook/pkg/daemon/ceph/model"
|
||||
)
|
||||
@@ -56,7 +57,7 @@ type realmType struct {
|
||||
Realms []string `json:"realms"`
|
||||
}
|
||||
|
||||
func deleteRealmAndPools(context *Context, preservePoolsOnDelete bool) error {
|
||||
func deleteRealmAndPools(context *Context, spec cephv1.ObjectStoreSpec) error {
|
||||
stores, err := getObjectStores(context)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to detect object stores during deletion")
|
||||
@@ -73,8 +74,8 @@ func deleteRealmAndPools(context *Context, preservePoolsOnDelete bool) error {
|
||||
lastStore = true
|
||||
}
|
||||
|
||||
if !preservePoolsOnDelete {
|
||||
err = deletePools(context, lastStore)
|
||||
if !spec.PreservePoolsOnDelete {
|
||||
err = deletePools(context, spec, lastStore)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to delete object store pools")
|
||||
}
|
||||
@@ -203,7 +204,12 @@ func getObjectStores(context *Context) ([]string, error) {
|
||||
return r.Realms, nil
|
||||
}
|
||||
|
||||
func deletePools(context *Context, lastStore bool) error {
|
||||
func deletePools(context *Context, spec cephv1.ObjectStoreSpec, lastStore bool) error {
|
||||
if emptyPool(spec.DataPool) && emptyPool(spec.MetadataPool) {
|
||||
logger.Info("skipping removal of pools since not specified in the object store")
|
||||
return nil
|
||||
}
|
||||
|
||||
pools := append(metadataPools, dataPools...)
|
||||
if lastStore {
|
||||
pools = append(pools, rootPool)
|
||||
@@ -235,7 +241,25 @@ func deletePools(context *Context, lastStore bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func createPools(context *Context, metadataSpec, dataSpec model.Pool) error {
|
||||
func createPools(context *Context, spec cephv1.ObjectStoreSpec, metadataSpec, dataSpec model.Pool) error {
|
||||
if emptyPool(spec.DataPool) && emptyPool(spec.MetadataPool) {
|
||||
logger.Info("no pools specified for the object store, checking for their existence...")
|
||||
pools := append(metadataPools, dataPools...)
|
||||
pools = append(pools, rootPool)
|
||||
var missingPools []string
|
||||
for _, pool := range pools {
|
||||
poolName := poolName(context.Name, pool)
|
||||
_, err := ceph.GetPoolDetails(context.Context, context.ClusterName, poolName)
|
||||
if err != nil {
|
||||
logger.Debugf("failed to find pool %q. %v", poolName, err)
|
||||
missingPools = append(missingPools, poolName)
|
||||
}
|
||||
}
|
||||
if len(missingPools) > 0 {
|
||||
return fmt.Errorf("object store pools are missing: %v", missingPools)
|
||||
}
|
||||
}
|
||||
|
||||
if err := createSimilarPools(context, append(metadataPools, rootPool), metadataSpec); err != nil {
|
||||
return errors.Wrapf(err, "failed to create metadata pools")
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
|
||||
"github.com/rook/rook/pkg/clusterd"
|
||||
exectest "github.com/rook/rook/pkg/util/exec/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -152,18 +153,30 @@ func deleteStore(t *testing.T, name string, existingStores string, expectedDelet
|
||||
executor.MockExecuteCommandWithCombinedOutput = executorFunc
|
||||
context := &Context{Context: &clusterd.Context{Executor: executor}, Name: "myobj", ClusterName: "ns"}
|
||||
|
||||
// Delete an object store
|
||||
err := deleteRealmAndPools(context, false)
|
||||
// Delete an object store without deleting the pools
|
||||
spec := cephv1.ObjectStoreSpec{}
|
||||
err := deleteRealmAndPools(context, spec)
|
||||
assert.Nil(t, err)
|
||||
expectedPoolsDeleted := 6
|
||||
if expectedDeleteRootPool {
|
||||
expectedPoolsDeleted++
|
||||
}
|
||||
expectedPoolsDeleted := 0
|
||||
assert.Equal(t, expectedPoolsDeleted, poolsDeleted)
|
||||
assert.Equal(t, expectedPoolsDeleted, rulesDeleted)
|
||||
assert.True(t, realmDeleted)
|
||||
assert.True(t, zoneGroupDeleted)
|
||||
assert.True(t, zoneDeleted)
|
||||
assert.Equal(t, false, deletedErasureCodeProfile)
|
||||
|
||||
// Delete an object store with the pools
|
||||
spec = cephv1.ObjectStoreSpec{
|
||||
MetadataPool: cephv1.PoolSpec{Replicated: cephv1.ReplicatedSpec{Size: 1}},
|
||||
DataPool: cephv1.PoolSpec{Replicated: cephv1.ReplicatedSpec{Size: 1}},
|
||||
}
|
||||
err = deleteRealmAndPools(context, spec)
|
||||
assert.Nil(t, err)
|
||||
expectedPoolsDeleted = 6
|
||||
if expectedDeleteRootPool {
|
||||
expectedPoolsDeleted++
|
||||
}
|
||||
assert.Equal(t, expectedPoolsDeleted, poolsDeleted)
|
||||
assert.Equal(t, expectedDeleteRootPool, deletedRootPool)
|
||||
assert.Equal(t, true, deletedErasureCodeProfile)
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/banzaicloud/k8s-objectmatcher/patch"
|
||||
@@ -281,7 +282,7 @@ func (c *clusterConfig) deleteStore() error {
|
||||
|
||||
// Delete the realm and pools
|
||||
objContext := NewContext(c.context, c.store.Name, c.store.Namespace)
|
||||
err := deleteRealmAndPools(objContext, c.store.Spec.PreservePoolsOnDelete)
|
||||
err := deleteRealmAndPools(objContext, c.store.Spec)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to delete the realm and pools")
|
||||
}
|
||||
@@ -310,11 +311,18 @@ func validateStore(context *clusterd.Context, s *cephv1.CephObjectStore) error {
|
||||
if securePort < 0 || securePort > 65535 {
|
||||
return errors.Errorf("securePort value of %d must be between 0 and 65535", securePort)
|
||||
}
|
||||
if err := pool.ValidatePoolSpec(context, s.Namespace, &s.Spec.MetadataPool); err != nil {
|
||||
return errors.Wrapf(err, "invalid metadata pool spec")
|
||||
|
||||
// Validate the pool settings, but allow for empty pools specs in case they have already been created
|
||||
// such as by the ceph mgr
|
||||
if !emptyPool(s.Spec.MetadataPool) {
|
||||
if err := pool.ValidatePoolSpec(context, s.Namespace, &s.Spec.MetadataPool); err != nil {
|
||||
return errors.Wrap(err, "invalid metadata pool spec")
|
||||
}
|
||||
}
|
||||
if err := pool.ValidatePoolSpec(context, s.Namespace, &s.Spec.DataPool); err != nil {
|
||||
return errors.Wrapf(err, "invalid data pool spec")
|
||||
if !emptyPool(s.Spec.DataPool) {
|
||||
if err := pool.ValidatePoolSpec(context, s.Namespace, &s.Spec.DataPool); err != nil {
|
||||
return errors.Wrap(err, "invalid data pool spec")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -323,3 +331,7 @@ func validateStore(context *clusterd.Context, s *cephv1.CephObjectStore) error {
|
||||
func (c *clusterConfig) generateSecretName(id string) string {
|
||||
return fmt.Sprintf("%s-%s-%s-keyring", AppName, c.store.Name, id)
|
||||
}
|
||||
|
||||
func emptyPool(pool cephv1.PoolSpec) bool {
|
||||
return reflect.DeepEqual(pool, cephv1.PoolSpec{})
|
||||
}
|
||||
@@ -140,3 +140,16 @@ func TestGenerateSecretName(t *testing.T) {
|
||||
secret := c.generateSecretName("a")
|
||||
assert.Equal(t, "rook-ceph-rgw-default-a-keyring", secret)
|
||||
}
|
||||
|
||||
func TestEmptyPoolSpec(t *testing.T) {
|
||||
assert.True(t, emptyPool(cephv1.PoolSpec{}))
|
||||
|
||||
p := cephv1.PoolSpec{FailureDomain: "foo"}
|
||||
assert.False(t, emptyPool(p))
|
||||
|
||||
p = cephv1.PoolSpec{Replicated: cephv1.ReplicatedSpec{Size: 1}}
|
||||
assert.False(t, emptyPool(p))
|
||||
|
||||
p = cephv1.PoolSpec{ErasureCoded: cephv1.ErasureCodedSpec{CodingChunks: 1}}
|
||||
assert.False(t, emptyPool(p))
|
||||
}
|
||||
Reference in new issue
Block a user