Skip to content

Commit 29e71f9

Browse files
authored
Merge pull request #559 from parth-gr/objectstore-4.14
Bug 2254547: object: improve the error handling for multisite objs
2 parents 8dad108 + 0b34fd0 commit 29e71f9

File tree

4 files changed

+121
-38
lines changed

4 files changed

+121
-38
lines changed

pkg/operator/ceph/object/objectstore.go

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -392,55 +392,65 @@ func getZoneEndpoints(objContext *Context, serviceEndpoint string) ([]string, bo
392392
return zoneEndpointsList, isEndpointAlreadyExists, nil
393393
}
394394

395+
func createMultisiteConfigurations(objContext *Context, configType, configTypeArg string, args ...string) error {
396+
args = append([]string{configType}, args...)
397+
args = append(args, configTypeArg)
398+
// get the multisite config before creating
399+
configTypeArgs := []string{configType, "get", configTypeArg}
400+
if configType == "zonegroup" {
401+
configTypeArgs = append(configTypeArgs, fmt.Sprintf("--rgw-realm=%s", objContext.Realm))
402+
}
403+
output, getConfigErr := RunAdminCommandNoMultisite(objContext, true, configTypeArgs...)
404+
if getConfigErr == nil {
405+
return nil
406+
}
407+
408+
if kerrors.IsNotFound(getConfigErr) {
409+
// the pod used to exec command (act as a proxy) is not found/ready yet
410+
// caller can nicely handle error and not overflow logs with misleading error messages
411+
return getConfigErr
412+
}
413+
414+
code, err := exec.ExtractExitCode(getConfigErr)
415+
if err != nil {
416+
return errorOrIsNotFound(getConfigErr, "'radosgw-admin %q get' failed with code %q, for reason %q, error: (%v)", configType, strconv.Itoa(code), output, string(kerrors.ReasonForError(err)))
417+
}
418+
// ENOENT means "No such file or directory"
419+
if code != int(syscall.ENOENT) {
420+
code := strconv.Itoa(code)
421+
return errors.Wrapf(getConfigErr, "'radosgw-admin %q get' failed with code %q, for reason %q", configType, code, output)
422+
}
423+
424+
// create the object if it doesn't exist yet
425+
output, err = RunAdminCommandNoMultisite(objContext, false, args...)
426+
if err != nil {
427+
return errorOrIsNotFound(err, "failed to create ceph %q %q, for reason %q", configType, configTypeArg, output)
428+
}
429+
logger.Debugf("created %q %q", configType, configTypeArg)
430+
431+
return nil
432+
}
433+
395434
func createMultisite(objContext *Context, endpointArg string) error {
396435
logger.Debugf("creating realm, zone group, zone for object-store %v", objContext.Name)
397436

398437
realmArg := fmt.Sprintf("--rgw-realm=%s", objContext.Realm)
399438
zoneGroupArg := fmt.Sprintf("--rgw-zonegroup=%s", objContext.ZoneGroup)
439+
zoneArg := fmt.Sprintf("--rgw-zone=%s", objContext.Zone)
400440

401-
// create the realm if it doesn't exist yet
402-
output, err := RunAdminCommandNoMultisite(objContext, true, "realm", "get", realmArg)
441+
err := createMultisiteConfigurations(objContext, "realm", realmArg, "create")
403442
if err != nil {
404-
// ENOENT means "No such file or directory"
405-
if code, err := exec.ExtractExitCode(err); err == nil && code == int(syscall.ENOENT) {
406-
output, err = RunAdminCommandNoMultisite(objContext, false, "realm", "create", realmArg)
407-
if err != nil {
408-
return errorOrIsNotFound(err, "failed to create ceph realm %q, for reason %q", objContext.ZoneGroup, output)
409-
}
410-
logger.Debugf("created realm %q", objContext.Realm)
411-
} else {
412-
return errorOrIsNotFound(err, "'radosgw-admin realm get' failed with code %d, for reason %q. %v", strconv.Itoa(code), output, string(kerrors.ReasonForError(err)))
413-
}
443+
return err
414444
}
415445

416-
// create the zonegroup if it doesn't exist yet
417-
output, err = RunAdminCommandNoMultisite(objContext, true, "zonegroup", "get", realmArg, zoneGroupArg)
446+
err = createMultisiteConfigurations(objContext, "zonegroup", zoneGroupArg, "create", "--master", realmArg, endpointArg)
418447
if err != nil {
419-
// ENOENT means "No such file or directory"
420-
if code, err := exec.ExtractExitCode(err); err == nil && code == int(syscall.ENOENT) {
421-
output, err = RunAdminCommandNoMultisite(objContext, false, "zonegroup", "create", "--master", realmArg, zoneGroupArg, endpointArg)
422-
if err != nil {
423-
return errorOrIsNotFound(err, "failed to create ceph zone group %q, for reason %q", objContext.ZoneGroup, output)
424-
}
425-
logger.Debugf("created zone group %q", objContext.ZoneGroup)
426-
} else {
427-
return errorOrIsNotFound(err, "'radosgw-admin zonegroup get' failed with code %d, for reason %q", strconv.Itoa(code), output)
428-
}
448+
return err
429449
}
430450

431-
// create the zone if it doesn't exist yet
432-
output, err = runAdminCommand(objContext, true, "zone", "get")
451+
err = createMultisiteConfigurations(objContext, "zone", zoneArg, "create", "--master", endpointArg, realmArg, zoneGroupArg)
433452
if err != nil {
434-
// ENOENT means "No such file or directory"
435-
if code, err := exec.ExtractExitCode(err); err == nil && code == int(syscall.ENOENT) {
436-
output, err = runAdminCommand(objContext, false, "zone", "create", "--master", endpointArg)
437-
if err != nil {
438-
return errorOrIsNotFound(err, "failed to create ceph zone %q, for reason %q", objContext.Zone, output)
439-
}
440-
logger.Debugf("created zone %q", objContext.Zone)
441-
} else {
442-
return errorOrIsNotFound(err, "'radosgw-admin zone get' failed with code %d, for reason %q", strconv.Itoa(code), output)
443-
}
453+
return err
444454
}
445455

446456
if err := commitConfigChanges(objContext); err != nil {

pkg/operator/ceph/object/objectstore_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ import (
2929
"github.com/rook/rook/pkg/daemon/ceph/client"
3030
cephver "github.com/rook/rook/pkg/operator/ceph/version"
3131
"github.com/rook/rook/pkg/operator/k8sutil"
32+
"github.com/rook/rook/pkg/util/exec"
3233
exectest "github.com/rook/rook/pkg/util/exec/test"
3334
"github.com/stretchr/testify/assert"
3435
v1 "k8s.io/api/core/v1"
3536
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3637
"k8s.io/apimachinery/pkg/types"
3738
k8sfake "k8s.io/client-go/kubernetes/fake"
39+
kexec "k8s.io/utils/exec"
3840
)
3941

4042
const (
@@ -669,6 +671,77 @@ func Test_createMultisite(t *testing.T) {
669671
}
670672
}
671673

674+
func getExecutor() []exec.Executor {
675+
executor := []exec.Executor{&exectest.MockExecutor{
676+
MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
677+
if args[0] == "realm" {
678+
return `{
679+
"id": "237e6250-5f7d-4b85-9359-8cb2b1848507",
680+
"name": "realm-a",
681+
"current_period": "df665ecb-1762-47a9-9c66-f938d251c02a",
682+
"epoch": 2
683+
}`, nil
684+
}
685+
return "", nil
686+
},
687+
},
688+
&exectest.MockExecutor{
689+
MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
690+
if args[0] == "realm" {
691+
return `{}`, errors.Errorf("Error from server (NotFound): pods not found")
692+
}
693+
return "", nil
694+
},
695+
},
696+
&exectest.MockExecutor{
697+
MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
698+
if args[0] == "realm" {
699+
return `{}`, &kexec.CodeExitError{Err: errors.New("some error"), Code: 4}
700+
}
701+
return "", nil
702+
},
703+
},
704+
&exectest.MockExecutor{
705+
MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
706+
if args[0] == "realm" {
707+
return `{}`, &kexec.CodeExitError{Err: errors.New("some other error"), Code: 2}
708+
}
709+
return "", nil
710+
},
711+
},
712+
}
713+
return executor
714+
}
715+
716+
func getreturnErrString() []string {
717+
returnErr := []string{
718+
"",
719+
"'radosgw-admin [\"realm\" \"-1\" \"{}. \" \"\"] get' failed with code %!q(MISSING), for reason %!q(MISSING), error: (%!v(MISSING)): Error from server (NotFound): pods not found",
720+
"'radosgw-admin \"realm\" get' failed with code \"4\", for reason \"{}. \": some error",
721+
"failed to create ceph [\"realm\" \"--rgw-realm=\" \"{}. \"] %!q(MISSING), for reason %!q(MISSING): some other error",
722+
}
723+
return returnErr
724+
}
725+
726+
func Test_createMultisiteConfigurations(t *testing.T) {
727+
executor := getExecutor()
728+
returnErrString := getreturnErrString()
729+
for i := 0; i < 4; i++ {
730+
ctx := &clusterd.Context{
731+
Executor: executor[i],
732+
}
733+
objContext := NewContext(ctx, &client.ClusterInfo{Namespace: "my-cluster"}, "my-store")
734+
realmArg := fmt.Sprintf("--rgw-realm=%s", objContext.Realm)
735+
736+
err := createMultisiteConfigurations(objContext, "realm", realmArg, "create")
737+
if i == 0 {
738+
assert.NoError(t, err)
739+
} else {
740+
assert.Contains(t, err.Error(), returnErrString[i])
741+
}
742+
}
743+
}
744+
672745
func TestGetRealmKeySecret(t *testing.T) {
673746
ns := "my-ns"
674747
realmName := "my-realm"

tests/framework/clients/object.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (o *ObjectOperation) Create(namespace, storeName string, replicaCount int32
4848
}
4949

5050
// Starting an object store takes longer than the average operation, so add more retries
51-
err := o.k8sh.WaitForLabeledPodsToRunWithRetries(fmt.Sprintf("rook_object_store=%s", storeName), namespace, 40)
51+
err := o.k8sh.WaitForLabeledPodsToRunWithRetries(fmt.Sprintf("rook_object_store=%s", storeName), namespace, 80)
5252
if err != nil {
5353
return fmt.Errorf("rgw did not start via crd. %+v", err)
5454
}

tests/integration/ceph_base_object_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func createCephObjectStore(t *testing.T, helper *clients.TestClient, k8sh *utils
114114

115115
// Check object store status
116116
t.Run("verify object store status", func(t *testing.T) {
117-
retryCount := 30
117+
retryCount := 40
118118
i := 0
119119
for i = 0; i < retryCount; i++ {
120120
objectStore, err := k8sh.RookClientset.CephV1().CephObjectStores(namespace).Get(ctx, storeName, metav1.GetOptions{})

0 commit comments

Comments
 (0)