Skip to content

Commit

Permalink
Merge pull request ceph#60829 from cbodley/wip-69042
Browse files Browse the repository at this point in the history
radosgw-admin: bucket link/unlink support accounts

Reviewed-by: Adam Emerson <[email protected]>
  • Loading branch information
cbodley authored Dec 6, 2024
2 parents 5695c38 + 0e73c9d commit a204f98
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 9 deletions.
35 changes: 35 additions & 0 deletions qa/tasks/radosgw_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import time
import datetime
import sys
import errno

from io import StringIO
from queue import Queue
Expand Down Expand Up @@ -725,6 +726,40 @@ def task(ctx, config):
(err, out) = rgwadmin(ctx, client, ['user', 'rm', '--tenant', tenant_name, '--uid', 'tenanteduser'],
check_status=True)

account_id = 'RGW12312312312312312'
account_name = 'testacct'
rgwadmin(ctx, client, [
'account', 'create',
'--account-id', account_id,
'--account-name', account_name,
], check_status=True)
rgwadmin(ctx, client, [
'user', 'create',
'--account-id', account_id,
'--uid', 'testacctuser',
'--display-name', 'accountuser',
'--gen-access-key',
'--gen-secret',
], check_status=True)

# TESTCASE 'bucket link', 'bucket', 'account user', 'fails'
(err, out) = rgwadmin(ctx, client, ['bucket', 'link', '--bucket', bucket_name, '--uid', 'testacctuser'])
assert err == errno.EINVAL

rgwadmin(ctx, client, ['user', 'rm', '--uid', 'testacctuser'], check_status=True)

# TESTCASE 'bucket link', 'bucket', 'account', 'succeeds'
rgwadmin(ctx, client,
['bucket', 'link', '--bucket', bucket_name, '--account-id', account_id],
check_status=True)

# relink the bucket to the first user and delete the account
rgwadmin(ctx, client,
['bucket', 'link', '--bucket', bucket_name, '--uid', user1],
check_status=True)
rgwadmin(ctx, client, ['account', 'rm', '--account-id', account_id],
check_status=True)

# TESTCASE 'object-rm', 'object', 'rm', 'remove object', 'succeeds, object is removed'

# upload an object
Expand Down
51 changes: 42 additions & 9 deletions src/rgw/driver/rados/rgw_bucket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,16 @@ int RGWBucketAdminOp::dump_s3_policy(rgw::sal::Driver* driver, RGWBucketAdminOpS

int RGWBucketAdminOp::unlink(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, optional_yield y, string *err)
{
rgw_owner owner;
if (op_state.is_account_op()) {
owner = op_state.get_account_id();
} else if (op_state.is_user_op()) {
owner = op_state.get_user_id();
} else {
set_err_msg(err, "requires user or account id");
return -EINVAL;
}

auto radosdriver = dynamic_cast<rgw::sal::RadosStore*>(driver);
if (!radosdriver) {
set_err_msg(err, "rados store only");
Expand All @@ -1152,13 +1162,18 @@ int RGWBucketAdminOp::unlink(rgw::sal::Driver* driver, RGWBucketAdminOpState& op
return ret;

auto* rados = radosdriver->getRados()->get_rados_handle();
return radosdriver->ctl()->bucket->unlink_bucket(*rados, op_state.get_user_id(), op_state.get_bucket()->get_info().bucket, y, dpp, true);
return radosdriver->ctl()->bucket->unlink_bucket(*rados, owner, op_state.get_bucket()->get_info().bucket, y, dpp, true);
}

int RGWBucketAdminOp::link(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, optional_yield y, string *err)
{
if (!op_state.is_user_op()) {
set_err_msg(err, "empty user id");
rgw_owner new_owner;
if (op_state.is_account_op()) {
new_owner = op_state.get_account_id();
} else if (op_state.is_user_op()) {
new_owner = op_state.get_user_id();
} else {
set_err_msg(err, "requires user or account id");
return -EINVAL;
}
auto radosdriver = dynamic_cast<rgw::sal::RadosStore*>(driver);
Expand All @@ -1172,8 +1187,26 @@ int RGWBucketAdminOp::link(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_s
if (ret < 0)
return ret;

std::string display_name;
if (op_state.is_account_op()) {
RGWAccountInfo info;
rgw::sal::Attrs attrs;
RGWObjVersionTracker objv;
ret = driver->load_account_by_id(dpp, y, op_state.get_account_id(),
info, attrs, objv);
if (ret < 0) {
set_err_msg(err, "failed to load account");
return ret;
}
display_name = std::move(info.name);
} else if (!bucket.get_user()->get_info().account_id.empty()) {
set_err_msg(err, "account users cannot own buckets. use --account-id instead");
return -EINVAL;
} else {
display_name = bucket.get_user()->get_display_name();
}

string bucket_id = op_state.get_bucket_id();
std::string display_name = op_state.get_user_display_name();
std::unique_ptr<rgw::sal::Bucket> loc_bucket;
std::unique_ptr<rgw::sal::Bucket> old_bucket;

Expand All @@ -1187,7 +1220,7 @@ int RGWBucketAdminOp::link(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_s

old_bucket = loc_bucket->clone();

loc_bucket->get_key().tenant = op_state.get_user_id().tenant;
loc_bucket->get_key().tenant = op_state.get_tenant();

if (!op_state.new_bucket_name.empty()) {
auto pos = op_state.new_bucket_name.find('/');
Expand Down Expand Up @@ -1236,14 +1269,14 @@ int RGWBucketAdminOp::link(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_s
}

RGWAccessControlPolicy policy_instance;
policy_instance.create_default(op_state.get_user_id(), display_name);
policy_instance.create_default(new_owner, display_name);
owner = policy_instance.get_owner();

aclbl.clear();
policy_instance.encode(aclbl);

bool exclusive = false;
loc_bucket->get_info().owner = op_state.get_user_id();
loc_bucket->get_info().owner = new_owner;
if (*loc_bucket != *old_bucket) {
loc_bucket->get_info().bucket = loc_bucket->get_key();
loc_bucket->get_info().objv_tracker.version_for_read()->ver = 0;
Expand All @@ -1259,13 +1292,13 @@ int RGWBucketAdminOp::link(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_s
/* link to user */
RGWBucketEntryPoint ep;
ep.bucket = loc_bucket->get_info().bucket;
ep.owner = op_state.get_user_id();
ep.owner = new_owner;
ep.creation_time = loc_bucket->get_info().creation_time;
ep.linked = true;
rgw::sal::Attrs ep_attrs;
rgw_ep_info ep_data{ep, ep_attrs};

r = radosdriver->ctl()->bucket->link_bucket(*rados, op_state.get_user_id(), loc_bucket->get_info().bucket, loc_bucket->get_info().creation_time, y, dpp, true, &ep_data);
r = radosdriver->ctl()->bucket->link_bucket(*rados, new_owner, loc_bucket->get_info().bucket, loc_bucket->get_info().creation_time, y, dpp, true, &ep_data);
if (r < 0) {
set_err_msg(err, "failed to relink bucket");
return r;
Expand Down
1 change: 1 addition & 0 deletions src/rgw/driver/rados/rgw_bucket.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ class RGWBucket {
void clear_failure() { failure = false; }

const RGWBucketInfo& get_bucket_info() const { return bucket->get_info(); }
rgw::sal::User* get_user() { return user.get(); }
};

class RGWBucketAdminOp {
Expand Down
2 changes: 2 additions & 0 deletions src/rgw/driver/rados/rgw_rest_bucket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ void RGWOp_Bucket_Link::execute(optional_yield y)
RGWBucketAdminOpState op_state;

RESTArgs::get_string(s, "uid", uid_str, &uid_str);
RESTArgs::get_string(s, "account-id", op_state.account_id, &op_state.account_id);
RESTArgs::get_string(s, "bucket", bucket, &bucket);
RESTArgs::get_string(s, "bucket-id", bucket_id, &bucket_id);
RESTArgs::get_string(s, "new-bucket-name", new_bucket_name, &new_bucket_name);
Expand Down Expand Up @@ -184,6 +185,7 @@ void RGWOp_Bucket_Unlink::execute(optional_yield y)
RESTArgs::get_string(s, "uid", uid_str, &uid_str);
rgw_user uid(uid_str);

RESTArgs::get_string(s, "account-id", op_state.account_id, &op_state.account_id);
RESTArgs::get_string(s, "bucket", bucket, &bucket);

op_state.set_user_id(uid);
Expand Down

0 comments on commit a204f98

Please sign in to comment.