diff --git a/pkg/operator/ceph/object/bucket/provisioner.go b/pkg/operator/ceph/object/bucket/provisioner.go index aa902fde6..17d8efca5 100644 --- a/pkg/operator/ceph/object/bucket/provisioner.go +++ b/pkg/operator/ceph/object/bucket/provisioner.go @@ -94,11 +94,13 @@ func (p Provisioner) Provision(options *apibkt.BucketOptions) (*bktv1alpha1.Obje if err != nil { err = errors.Wrapf(err, "error creating bucket %q", p.bucketName) logger.Errorf(err.Error()) + p.deleteOBCResource("") return nil, err } _, errCode, err := cephObject.SetQuotaUserBucketMax(p.objectContext, p.cephUserName, maxBuckets) if errCode > 0 { + p.deleteOBCResource(p.bucketName) return nil, err } logger.Infof("set user %q bucket max to %d", p.cephUserName, maxBuckets) @@ -131,21 +133,25 @@ func (p Provisioner) Grant(options *apibkt.BucketOptions) (*bktv1alpha1.ObjectBu // need to quota into -1 for restricting creation of new buckets in rgw _, _, err = cephObject.SetQuotaUserBucketMax(p.objectContext, p.cephUserName, -1) if err != nil { + p.deleteOBCResource("") return nil, err } // get the bucket's owner via the bucket metadata stats, _, err := cephObject.GetBucket(p.objectContext, p.bucketName) if err != nil { + p.deleteOBCResource("") return nil, errors.Wrapf(err, "could not get bucket stats (bucket: %s)", p.bucketName) } objectUser, _, err := cephObject.GetUser(p.objectContext, stats.Owner) if err != nil { + p.deleteOBCResource("") return nil, errors.Wrapf(err, "could not get user (user: %s)", stats.Owner) } s3svc, err := NewS3Agent(*objectUser.AccessKey, *objectUser.SecretKey, p.getObjectStoreEndpoint()) if err != nil { + p.deleteOBCResource("") return nil, err } @@ -154,6 +160,7 @@ func (p Provisioner) Grant(options *apibkt.BucketOptions) (*bktv1alpha1.ObjectBu if err != nil { if aerr, ok := err.(awserr.Error); ok { if aerr.Code() != "NoSuchBucketPolicy" { + p.deleteOBCResource("") return nil, err } } @@ -175,6 +182,7 @@ func (p Provisioner) Grant(options *apibkt.BucketOptions) (*bktv1alpha1.ObjectBu logger.Infof("PutBucketPolicy output: %v", out) if err != nil { + p.deleteOBCResource("") return nil, err } // returned ob with connection info @@ -197,11 +205,7 @@ func (p Provisioner) Delete(ob *bktv1alpha1.ObjectBucket) error { return err } - err = p.deleteCephUser(p.cephUserName) - if err != nil { - return err - } - err = p.deleteBucket(p.bucketName) + err = p.deleteOBCResource(p.bucketName) if err != nil { return err } @@ -288,16 +292,8 @@ func (p Provisioner) Revoke(ob *bktv1alpha1.ObjectBucket) error { } } - _, _, err = cephObject.UnlinkUser(p.objectContext, p.cephUserName, p.bucketName) - if err != nil { - return err - } - - // finally, delete unlinked user - err = p.deleteCephUser(p.cephUserName) - if err != nil { - return err - } + // finally, delete the user + p.deleteOBCResource("") return nil } diff --git a/pkg/operator/ceph/object/bucket/rgw-handlers.go b/pkg/operator/ceph/object/bucket/rgw-handlers.go index 63a756359..edda8bd17 100644 --- a/pkg/operator/ceph/object/bucket/rgw-handlers.go +++ b/pkg/operator/ceph/object/bucket/rgw-handlers.go @@ -7,26 +7,6 @@ import ( cephObject "github.com/rook/rook/pkg/operator/ceph/object" ) -// The bucket (and objects) could be deleted via an s3 iterator, but since radosgw -// supports the `buket rm` command, this is the approch we'll use. -func (p *Provisioner) deleteBucket(bktName string) error { - - // delete bucket with purge option to remove all objects - errCode, err := cephObject.DeleteBucket(p.objectContext, p.bucketName, true) - if errCode == cephObject.RGWErrorNone { - logger.Infof("Bucket %s successfully deleted", bktName) - return nil - } - - // opinion: "not found" is not an error - if errCode == cephObject.RGWErrorNotFound { - logger.Infof("Bucket %s does not exist", bktName) - return nil - } - - return errors.Wrapf(err, "failed to delete bucket %q: errCode: %d", bktName, errCode) -} - func (p *Provisioner) bucketExists(name string) (bool, error) { _, errCode, err := cephObject.GetBucket(p.objectContext, name) if errCode != 0 { @@ -83,26 +63,6 @@ func (p *Provisioner) createCephUser(username string) (accKey string, secKey str return *u.AccessKey, *u.SecretKey, nil } -// Delete the Ceph user associated to the passed-in bucket. -func (p *Provisioner) deleteCephUser(username string) error { - - logger.Infof("deleting Ceph user %s for bucket %q", username, p.bucketName) - _, errCode, err := cephObject.DeleteUser(p.objectContext, username) - - if errCode == cephObject.RGWErrorNone { - logger.Infof("User %s successfully deleted", username) - return nil - } - - // opinion: "not found" is not an error - if errCode == cephObject.RGWErrorNotFound { - logger.Infof("User %s does not exist", username) - return nil - } - - return errors.Wrapf(err, "failed to delete user %q: errCode: %d", username, errCode) -} - // returns "" if unable to generate a unique name. func (p *Provisioner) genUserName() (genName string, err error) { const ( @@ -122,3 +82,38 @@ func (p *Provisioner) genUserName() (genName string, err error) { } return genName, nil } + +// Delete the user and bucket created by OBC with help of radosgw-admin commands +// If delete user failed, error is no longer returned since its permission is +// already revoked and hence user is no longer able to access the bucket +// Empty string is passed for bucketName only if user needs to be removed, ex Revoke() +func (p *Provisioner) deleteOBCResource(bucketName string) error { + + logger.Infof("deleting Ceph user %s and bucket %q", p.cephUserName, bucketName) + if len(p.cephUserName) > 0 { + _, errCode, _ := cephObject.DeleteUser(p.objectContext, p.cephUserName) + + if errCode == cephObject.RGWErrorNone { + logger.Infof("user %q successfully deleted", p.cephUserName) + } else if errCode == cephObject.RGWErrorNotFound { + // opinion: "not found" is not an error + logger.Infof("user %q does not exist", p.cephUserName) + } else { + logger.Warningf("failed to delete user %q: errCode: %d", p.cephUserName, errCode) + } + } + if len(bucketName) > 0 { + // delete bucket with purge option to remove all objects + errCode, err := cephObject.DeleteBucket(p.objectContext, bucketName, true) + + if errCode == cephObject.RGWErrorNone { + logger.Infof("bucket %q successfully deleted", p.bucketName) + } else if errCode == cephObject.RGWErrorNotFound { + // opinion: "not found" is not an error + logger.Infof("bucket %q does not exist", p.bucketName) + } else { + return errors.Wrapf(err, "failed to delete bucket %q: errCode: %d", bucketName, errCode) + } + } + return nil +}