Skip to content

Commit 83c9201

Browse files
authored
Merge pull request ceph#60227 from clwluvw/zonegroup-delbucket
rgw: skip empty check on non-owned buckets by zonegroup Reviewed-by: Casey Bodley <[email protected]> Reviewed-by: Anthony D'Atri <[email protected]>
2 parents efb9170 + c7694dd commit 83c9201

File tree

12 files changed

+125
-75
lines changed

12 files changed

+125
-75
lines changed

doc/radosgw/adminops.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,13 +1510,27 @@ Request Parameters
15101510
:Example: ``foo_bucket``
15111511
:Required: Yes
15121512

1513+
``tenant``
1514+
1515+
:Description: The tenant under which the bucket is to be removed.
1516+
:Type: String
1517+
:Example: ``tenant1``
1518+
:Required: No
1519+
15131520
``purge-objects``
15141521

15151522
:Description: Remove a buckets objects before deletion.
15161523
:Type: Boolean
15171524
:Example: True [False]
15181525
:Required: No
15191526

1527+
``bypass-gc``
1528+
1529+
:Description: Bypass garbage collection.
1530+
:Type: Boolean
1531+
:Example: True [False]
1532+
:Required: No
1533+
15201534
Response Entities
15211535
~~~~~~~~~~~~~~~~~
15221536

src/common/options/rgw.yaml.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,8 @@ options:
10251025
level: advanced
10261026
desc: Path prefix to be used for accessing RGW RESTful admin API.
10271027
fmt_desc: The entry point for an admin request URL.
1028+
long_desc: Note that multisite replication requires the value admin,
1029+
so this option must be left at the default in such deployments.
10281030
default: admin
10291031
services:
10301032
- rgw

src/rgw/driver/motr/rgw_sal_motr.cc

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -557,12 +557,15 @@ int MotrBucket::remove(const DoutPrefixProvider *dpp, bool delete_children, opti
557557
params.list_versions = true;
558558
params.allow_unordered = true;
559559

560+
const bool own_bucket = store->get_zone()->get_zonegroup().get_id() == info.zonegroup;
561+
560562
ListResults results;
563+
results.is_truncated = own_bucket; // if we don't have the index, we're done
561564

562565
// 1. Check if Bucket has objects.
563566
// If bucket contains objects and delete_children is true, delete all objects.
564567
// Else throw error that bucket is not empty.
565-
do {
568+
while (results.is_truncated) {
566569
results.objs.clear();
567570

568571
// Check if bucket has objects.
@@ -591,12 +594,14 @@ int MotrBucket::remove(const DoutPrefixProvider *dpp, bool delete_children, opti
591594
return ret;
592595
}
593596
}
594-
} while(results.is_truncated);
597+
}
595598

596599
// 2. Abort Mp uploads on the bucket.
597-
ret = abort_multiparts(dpp, store->ctx());
598-
if (ret < 0) {
599-
return ret;
600+
if (own_bucket) {
601+
ret = abort_multiparts(dpp, store->ctx());
602+
if (ret < 0) {
603+
return ret;
604+
}
600605
}
601606

602607
// 3. Remove mp index??
@@ -608,9 +613,11 @@ int MotrBucket::remove(const DoutPrefixProvider *dpp, bool delete_children, opti
608613
}
609614

610615
// 4. Sync user stats.
611-
ret = this->sync_owner_stats(dpp, y);
612-
if (ret < 0) {
613-
ldout(store->ctx(), 1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret << dendl;
616+
if (own_bucket) {
617+
ret = this->sync_owner_stats(dpp, y);
618+
if (ret < 0) {
619+
ldout(store->ctx(), 1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret << dendl;
620+
}
614621
}
615622

616623
// 5. Remove the bucket from user info index. (unlink user)

src/rgw/driver/rados/rgw_bucket.cc

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,9 +1440,10 @@ int RGWBucketAdminOp::check_index(rgw::sal::Driver* driver,
14401440
return 0;
14411441
}
14421442

1443-
int RGWBucketAdminOp::remove_bucket(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state,
1443+
int RGWBucketAdminOp::remove_bucket(rgw::sal::Driver* driver, const rgw::SiteConfig& site,
1444+
RGWBucketAdminOpState& op_state,
14441445
optional_yield y, const DoutPrefixProvider *dpp,
1445-
bool bypass_gc, bool keep_index_consistent)
1446+
bool bypass_gc, bool keep_index_consistent, bool forwarded_request)
14461447
{
14471448
std::unique_ptr<rgw::sal::Bucket> bucket;
14481449

@@ -1452,10 +1453,36 @@ int RGWBucketAdminOp::remove_bucket(rgw::sal::Driver* driver, RGWBucketAdminOpSt
14521453
if (ret < 0)
14531454
return ret;
14541455

1456+
// check if the bucket is owned by my zonegroup, if not, refuse to remove it
1457+
if (!forwarded_request && bucket->get_info().zonegroup != driver->get_zone()->get_zonegroup().get_id()) {
1458+
ldpp_dout(dpp, 0) << "ERROR: The bucket's zonegroup does not match. "
1459+
<< "Removal is not allowed. Please execute this operation "
1460+
<< "on the bucket's zonegroup: " << bucket->get_info().zonegroup << dendl;
1461+
return -ERR_PERMANENT_REDIRECT;
1462+
}
1463+
14551464
if (bypass_gc)
14561465
ret = bucket->remove_bypass_gc(op_state.get_max_aio(), keep_index_consistent, y, dpp);
14571466
else
14581467
ret = bucket->remove(dpp, op_state.will_delete_children(), y);
1468+
if (ret < 0)
1469+
return ret;
1470+
1471+
// forward to master zonegroup
1472+
const std::string delpath = "/admin/bucket";
1473+
RGWEnv env;
1474+
env.set("REQUEST_METHOD", "DELETE");
1475+
env.set("SCRIPT_URI", delpath);
1476+
env.set("REQUEST_URI", delpath);
1477+
env.set("QUERY_STRING", fmt::format("bucket={}&tenant={}", bucket->get_name(), bucket->get_tenant()));
1478+
req_info req(dpp->get_cct(), &env);
1479+
1480+
ret = rgw_forward_request_to_master(dpp, site, bucket->get_owner(), nullptr, nullptr, req, y);
1481+
if (ret < 0) {
1482+
ldpp_dout(dpp, 0) << "ERROR: failed to forward request to master zonegroup: "
1483+
<< ret << dendl;
1484+
return ret;
1485+
}
14591486

14601487
return ret;
14611488
}

src/rgw/driver/rados/rgw_bucket.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,8 @@ class RGWBucketAdminOp {
392392
static int check_index_unlinked(rgw::sal::RadosStore* driver, RGWBucketAdminOpState& op_state,
393393
RGWFormatterFlusher& flusher, const DoutPrefixProvider *dpp);
394394

395-
static int remove_bucket(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, optional_yield y,
396-
const DoutPrefixProvider *dpp, bool bypass_gc = false, bool keep_index_consistent = true);
395+
static int remove_bucket(rgw::sal::Driver* driver, const rgw::SiteConfig& site, RGWBucketAdminOpState& op_state, optional_yield y,
396+
const DoutPrefixProvider *dpp, bool bypass_gc = false, bool keep_index_consistent = true, bool forwarded_request = false);
397397
static int remove_object(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, optional_yield y);
398398
static int info(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, RGWFormatterFlusher& flusher, optional_yield y, const DoutPrefixProvider *dpp);
399399
static int limit_check(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state,

src/rgw/driver/rados/rgw_rados.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5512,6 +5512,12 @@ int RGWRados::restore_obj_from_cloud(RGWLCCloudTierCtx& tier_ctx,
55125512

55135513
int RGWRados::check_bucket_empty(const DoutPrefixProvider *dpp, RGWBucketInfo& bucket_info, optional_yield y)
55145514
{
5515+
const auto& zonegroup = svc.site->get_zonegroup();
5516+
if (bucket_info.zonegroup != zonegroup.id) {
5517+
// don't check on this zone, the bucket's data belongs to another zonegroup
5518+
return 0;
5519+
}
5520+
55155521
constexpr uint NUM_ENTRIES = 1000u;
55165522

55175523
rgw_obj_index_key marker;

src/rgw/driver/rados/rgw_rest_bucket.cc

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -216,36 +216,24 @@ class RGWOp_Bucket_Remove : public RGWRESTOp {
216216

217217
void RGWOp_Bucket_Remove::execute(optional_yield y)
218218
{
219-
std::string bucket_name;
220-
bool delete_children;
221-
std::unique_ptr<rgw::sal::Bucket> bucket;
219+
std::string bucket_name, tenant;
220+
bool delete_children, bypass_gc;
222221

223222
RESTArgs::get_string(s, "bucket", bucket_name, &bucket_name);
223+
RESTArgs::get_string(s, "tenant", tenant, &tenant);
224224
RESTArgs::get_bool(s, "purge-objects", false, &delete_children);
225+
RESTArgs::get_bool(s, "bypass-gc", false, &bypass_gc);
225226

226-
op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(),
227-
nullptr, nullptr, s->info, y);
228-
if (op_ret < 0) {
229-
ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl;
230-
if (op_ret == -ENOENT) {
231-
/* adjust error, we want to return with NoSuchBucket and not
232-
* NoSuchKey */
233-
op_ret = -ERR_NO_SUCH_BUCKET;
234-
}
235-
return;
236-
}
227+
RGWBucketAdminOpState op_state;
228+
op_state.set_bucket_name(bucket_name);
229+
op_state.set_tenant(tenant);
230+
op_state.set_delete_children(delete_children);
237231

238-
op_ret = driver->load_bucket(s, rgw_bucket("", bucket_name),
239-
&bucket, y);
240-
if (op_ret < 0) {
241-
ldpp_dout(this, 0) << "get_bucket returned ret=" << op_ret << dendl;
242-
if (op_ret == -ENOENT) {
243-
op_ret = -ERR_NO_SUCH_BUCKET;
244-
}
245-
return;
246-
}
232+
// Check if the request is being forwarded by looking for the "rgwx-zonegroup" argument
233+
// As this is an admin endpoint, checking by system_request is not sufficient
234+
const bool is_forwarded = s->info.args.exists(RGW_SYS_PARAM_PREFIX "zonegroup");
247235

248-
op_ret = bucket->remove(s, delete_children, s->yield);
236+
op_ret = RGWBucketAdminOp::remove_bucket(driver, *s->penv.site, op_state, y, s, bypass_gc, true, is_forwarded);
249237
}
250238

251239
class RGWOp_Set_Bucket_Quota : public RGWRESTOp {

src/rgw/driver/rados/rgw_sal_rados.cc

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,12 @@ int RadosBucket::remove(const DoutPrefixProvider* dpp,
375375
params.list_versions = true;
376376
params.allow_unordered = true;
377377

378+
const bool own_bucket = store->get_zone()->get_zonegroup().get_id() == info.zonegroup;
379+
378380
ListResults results;
381+
results.is_truncated = own_bucket; // if we don't have the index, we're done
379382

380-
do {
383+
while (results.is_truncated) {
381384
results.objs.clear();
382385

383386
ret = list(dpp, params, 1000, results, y);
@@ -399,11 +402,13 @@ int RadosBucket::remove(const DoutPrefixProvider* dpp,
399402
return ret;
400403
}
401404
}
402-
} while(results.is_truncated);
405+
}
403406

404-
ret = abort_multiparts(dpp, store->ctx(), y);
405-
if (ret < 0) {
406-
return ret;
407+
if (own_bucket) {
408+
ret = abort_multiparts(dpp, store->ctx(), y);
409+
if (ret < 0) {
410+
return ret;
411+
}
407412
}
408413

409414
// remove lifecycle config, if any (XXX note could be made generic)
@@ -438,9 +443,11 @@ int RadosBucket::remove(const DoutPrefixProvider* dpp,
438443
}
439444

440445
librados::Rados& rados = *store->getRados()->get_rados_handle();
441-
ret = store->ctl()->bucket->sync_owner_stats(dpp, rados, info.owner, info, y, nullptr);
442-
if (ret < 0) {
443-
ldout(store->ctx(), 1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret << dendl;
446+
if (own_bucket) {
447+
ret = store->ctl()->bucket->sync_owner_stats(dpp, rados, info.owner, info, y, nullptr);
448+
if (ret < 0) {
449+
ldout(store->ctx(), 1) << "WARNING: failed sync user stats before bucket delete. ret=" << ret << dendl;
450+
}
444451
}
445452

446453
RGWObjVersionTracker ot;

src/rgw/radosgw-admin/radosgw-admin.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6693,7 +6693,6 @@ int main(int argc, const char **argv)
66936693
OPT::USER_SUSPEND, OPT::SUBUSER_CREATE,
66946694
OPT::SUBUSER_MODIFY, OPT::SUBUSER_RM,
66956695
OPT::BUCKET_LINK, OPT::BUCKET_UNLINK,
6696-
OPT::BUCKET_RM,
66976696
OPT::BUCKET_CHOWN, OPT::METADATA_PUT,
66986697
OPT::METADATA_RM, OPT::MFA_CREATE,
66996698
OPT::MFA_REMOVE, OPT::MFA_RESYNC,
@@ -9143,14 +9142,14 @@ int main(int argc, const char **argv)
91439142

91449143
if (opt_cmd == OPT::BUCKET_RM) {
91459144
if (!inconsistent_index) {
9146-
RGWBucketAdminOp::remove_bucket(driver, bucket_op, null_yield, dpp(), bypass_gc, true);
9145+
RGWBucketAdminOp::remove_bucket(driver, *site, bucket_op, null_yield, dpp(), bypass_gc, true, false);
91479146
} else {
91489147
if (!yes_i_really_mean_it) {
91499148
cerr << "using --inconsistent_index can corrupt the bucket index " << std::endl
91509149
<< "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
91519150
return 1;
91529151
}
9153-
RGWBucketAdminOp::remove_bucket(driver, bucket_op, null_yield, dpp(), bypass_gc, false);
9152+
RGWBucketAdminOp::remove_bucket(driver, *site, bucket_op, null_yield, dpp(), bypass_gc, false, false);
91549153
}
91559154
}
91569155

src/rgw/rgw_auth.cc

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,6 @@ uint32_t rgw_perms_from_aclspec_default_strategy(
368368
}
369369

370370

371-
static inline const std::string make_spec_item(const std::string& tenant,
372-
const std::string& id)
373-
{
374-
return tenant + ":" + id;
375-
}
376-
377-
378371
static inline std::pair<bool, rgw::auth::Engine::result_t>
379372
strategy_handle_rejected(rgw::auth::Engine::result_t&& engine_result,
380373
const rgw::auth::Strategy::Control policy,

0 commit comments

Comments
 (0)