]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/driver/rados/rgw_bucket.cc
70e5581b1f122ba1a5414edda7fc3af7cdccf7fa
[ceph.git] / ceph / src / rgw / driver / rados / rgw_bucket.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4 #include "rgw_acl_s3.h"
5 #include "rgw_tag_s3.h"
6
7 #include "rgw_bucket.h"
8 #include "rgw_op.h"
9 #include "rgw_bucket_sync.h"
10
11 #include "services/svc_zone.h"
12 #include "services/svc_bucket.h"
13 #include "services/svc_user.h"
14
15 #include "rgw_reshard.h"
16
17 // stolen from src/cls/version/cls_version.cc
18 #define VERSION_ATTR "ceph.objclass.version"
19
20 #include "cls/user/cls_user_types.h"
21
22 #include "rgw_sal_rados.h"
23
24 #define dout_subsys ceph_subsys_rgw
25
26 // seconds for timeout during RGWBucket::check_object_index
27 constexpr uint64_t BUCKET_TAG_QUICK_TIMEOUT = 30;
28
29 using namespace std;
30
31 // default number of entries to list with each bucket listing call
32 // (use marker to bridge between calls)
33 static constexpr size_t listing_max_entries = 1000;
34
35 /*
36 * The tenant_name is always returned on purpose. May be empty, of course.
37 */
38 static void parse_bucket(const string& bucket,
39 string *tenant_name,
40 string *bucket_name,
41 string *bucket_instance = nullptr /* optional */)
42 {
43 /*
44 * expected format: [tenant/]bucket:bucket_instance
45 */
46 int pos = bucket.find('/');
47 if (pos >= 0) {
48 *tenant_name = bucket.substr(0, pos);
49 } else {
50 tenant_name->clear();
51 }
52 string bn = bucket.substr(pos + 1);
53 pos = bn.find (':');
54 if (pos < 0) {
55 *bucket_name = std::move(bn);
56 return;
57 }
58 *bucket_name = bn.substr(0, pos);
59 if (bucket_instance) {
60 *bucket_instance = bn.substr(pos + 1);
61 }
62
63 /*
64 * deal with the possible tenant:bucket:bucket_instance case
65 */
66 if (tenant_name->empty()) {
67 pos = bucket_instance->find(':');
68 if (pos >= 0) {
69 *tenant_name = *bucket_name;
70 *bucket_name = bucket_instance->substr(0, pos);
71 *bucket_instance = bucket_instance->substr(pos + 1);
72 }
73 }
74 }
75
76 static void dump_mulipart_index_results(list<rgw_obj_index_key>& objs_to_unlink,
77 Formatter *f)
78 {
79 for (const auto& o : objs_to_unlink) {
80 f->dump_string("object", o.name);
81 }
82 }
83
84 void check_bad_user_bucket_mapping(rgw::sal::Driver* driver, rgw::sal::User& user,
85 bool fix,
86 optional_yield y,
87 const DoutPrefixProvider *dpp)
88 {
89 rgw::sal::BucketList user_buckets;
90 string marker;
91
92 CephContext *cct = driver->ctx();
93
94 size_t max_entries = cct->_conf->rgw_list_buckets_max_chunk;
95
96 do {
97 int ret = user.list_buckets(dpp, marker, string(), max_entries, false, user_buckets, y);
98 if (ret < 0) {
99 ldout(driver->ctx(), 0) << "failed to read user buckets: "
100 << cpp_strerror(-ret) << dendl;
101 return;
102 }
103
104 map<string, std::unique_ptr<rgw::sal::Bucket>>& buckets = user_buckets.get_buckets();
105 for (auto i = buckets.begin();
106 i != buckets.end();
107 ++i) {
108 marker = i->first;
109
110 auto& bucket = i->second;
111
112 std::unique_ptr<rgw::sal::Bucket> actual_bucket;
113 int r = driver->get_bucket(dpp, &user, user.get_tenant(), bucket->get_name(), &actual_bucket, y);
114 if (r < 0) {
115 ldout(driver->ctx(), 0) << "could not get bucket info for bucket=" << bucket << dendl;
116 continue;
117 }
118
119 if (actual_bucket->get_name().compare(bucket->get_name()) != 0 ||
120 actual_bucket->get_tenant().compare(bucket->get_tenant()) != 0 ||
121 actual_bucket->get_marker().compare(bucket->get_marker()) != 0 ||
122 actual_bucket->get_bucket_id().compare(bucket->get_bucket_id()) != 0) {
123 cout << "bucket info mismatch: expected " << actual_bucket << " got " << bucket << std::endl;
124 if (fix) {
125 cout << "fixing" << std::endl;
126 r = actual_bucket->chown(dpp, user, y);
127 if (r < 0) {
128 cerr << "failed to fix bucket: " << cpp_strerror(-r) << std::endl;
129 }
130 }
131 }
132 }
133 } while (user_buckets.is_truncated());
134 }
135
136 // returns true if entry is in the empty namespace. note: function
137 // type conforms to type RGWBucketListNameFilter
138 bool rgw_bucket_object_check_filter(const std::string& oid)
139 {
140 const static std::string empty_ns;
141 rgw_obj_key key; // thrown away but needed for parsing
142 return rgw_obj_key::oid_to_key_in_ns(oid, &key, empty_ns);
143 }
144
145 int rgw_remove_object(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, rgw::sal::Bucket* bucket, rgw_obj_key& key)
146 {
147 if (key.instance.empty()) {
148 key.instance = "null";
149 }
150
151 std::unique_ptr<rgw::sal::Object> object = bucket->get_object(key);
152
153 return object->delete_object(dpp, null_yield);
154 }
155
156 static void set_err_msg(std::string *sink, std::string msg)
157 {
158 if (sink && !msg.empty())
159 *sink = msg;
160 }
161
162 int RGWBucket::init(rgw::sal::Driver* _driver, RGWBucketAdminOpState& op_state,
163 optional_yield y, const DoutPrefixProvider *dpp, std::string *err_msg)
164 {
165 if (!_driver) {
166 set_err_msg(err_msg, "no storage!");
167 return -EINVAL;
168 }
169
170 driver = _driver;
171
172 std::string bucket_name = op_state.get_bucket_name();
173
174 if (bucket_name.empty() && op_state.get_user_id().empty())
175 return -EINVAL;
176
177 user = driver->get_user(op_state.get_user_id());
178 std::string tenant = user->get_tenant();
179
180 // split possible tenant/name
181 auto pos = bucket_name.find('/');
182 if (pos != string::npos) {
183 tenant = bucket_name.substr(0, pos);
184 bucket_name = bucket_name.substr(pos + 1);
185 }
186
187 int r = driver->get_bucket(dpp, user.get(), tenant, bucket_name, &bucket, y);
188 if (r < 0) {
189 set_err_msg(err_msg, "failed to fetch bucket info for bucket=" + bucket_name);
190 return r;
191 }
192
193 op_state.set_bucket(bucket->clone());
194
195 if (!rgw::sal::User::empty(user.get())) {
196 r = user->load_user(dpp, y);
197 if (r < 0) {
198 set_err_msg(err_msg, "failed to fetch user info");
199 return r;
200 }
201 }
202
203 op_state.display_name = user->get_display_name();
204
205 clear_failure();
206 return 0;
207 }
208
209 bool rgw_find_bucket_by_id(const DoutPrefixProvider *dpp, CephContext *cct, rgw::sal::Driver* driver,
210 const string& marker, const string& bucket_id, rgw_bucket* bucket_out)
211 {
212 void *handle = NULL;
213 bool truncated = false;
214 string s;
215
216 int ret = driver->meta_list_keys_init(dpp, "bucket.instance", marker, &handle);
217 if (ret < 0) {
218 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
219 driver->meta_list_keys_complete(handle);
220 return -ret;
221 }
222 do {
223 list<string> keys;
224 ret = driver->meta_list_keys_next(dpp, handle, 1000, keys, &truncated);
225 if (ret < 0) {
226 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
227 driver->meta_list_keys_complete(handle);
228 return -ret;
229 }
230 for (list<string>::iterator iter = keys.begin(); iter != keys.end(); ++iter) {
231 s = *iter;
232 ret = rgw_bucket_parse_bucket_key(cct, s, bucket_out, nullptr);
233 if (ret < 0) {
234 continue;
235 }
236 if (bucket_id == bucket_out->bucket_id) {
237 driver->meta_list_keys_complete(handle);
238 return true;
239 }
240 }
241 } while (truncated);
242 driver->meta_list_keys_complete(handle);
243 return false;
244 }
245
246 int RGWBucket::chown(RGWBucketAdminOpState& op_state, const string& marker,
247 optional_yield y, const DoutPrefixProvider *dpp, std::string *err_msg)
248 {
249 /* User passed in by rgw_admin is the new user; get the current user and set it in
250 * the bucket */
251 std::unique_ptr<rgw::sal::User> old_user = driver->get_user(bucket->get_info().owner);
252 bucket->set_owner(old_user.get());
253
254 return rgw_chown_bucket_and_objects(driver, bucket.get(), user.get(), marker, err_msg, dpp, y);
255 }
256
257 int RGWBucket::set_quota(RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, std::string *err_msg)
258 {
259 bucket = op_state.get_bucket()->clone();
260
261 bucket->get_info().quota = op_state.quota;
262 int r = bucket->put_info(dpp, false, real_time());
263 if (r < 0) {
264 set_err_msg(err_msg, "ERROR: failed writing bucket instance info: " + cpp_strerror(-r));
265 return r;
266 }
267 return r;
268 }
269
270 int RGWBucket::remove_object(const DoutPrefixProvider *dpp, RGWBucketAdminOpState& op_state, std::string *err_msg)
271 {
272 std::string object_name = op_state.get_object_name();
273
274 rgw_obj_key key(object_name);
275
276 bucket = op_state.get_bucket()->clone();
277
278 int ret = rgw_remove_object(dpp, driver, bucket.get(), key);
279 if (ret < 0) {
280 set_err_msg(err_msg, "unable to remove object" + cpp_strerror(-ret));
281 return ret;
282 }
283
284 return 0;
285 }
286
287 static void dump_bucket_index(const vector<rgw_bucket_dir_entry>& objs, Formatter *f)
288 {
289 for (auto iter = objs.begin(); iter != objs.end(); ++iter) {
290 f->dump_string("object", iter->key.name);
291 }
292 }
293
294 static void dump_bucket_usage(map<RGWObjCategory, RGWStorageStats>& stats, Formatter *formatter)
295 {
296 map<RGWObjCategory, RGWStorageStats>::iterator iter;
297
298 formatter->open_object_section("usage");
299 for (iter = stats.begin(); iter != stats.end(); ++iter) {
300 RGWStorageStats& s = iter->second;
301 formatter->open_object_section(to_string(iter->first));
302 s.dump(formatter);
303 formatter->close_section();
304 }
305 formatter->close_section();
306 }
307
308 static void dump_index_check(map<RGWObjCategory, RGWStorageStats> existing_stats,
309 map<RGWObjCategory, RGWStorageStats> calculated_stats,
310 Formatter *formatter)
311 {
312 formatter->open_object_section("check_result");
313 formatter->open_object_section("existing_header");
314 dump_bucket_usage(existing_stats, formatter);
315 formatter->close_section();
316 formatter->open_object_section("calculated_header");
317 dump_bucket_usage(calculated_stats, formatter);
318 formatter->close_section();
319 formatter->close_section();
320 }
321
322 int RGWBucket::check_bad_index_multipart(RGWBucketAdminOpState& op_state,
323 RGWFormatterFlusher& flusher,
324 const DoutPrefixProvider *dpp,
325 std::string *err_msg)
326 {
327 const bool fix_index = op_state.will_fix_index();
328
329 bucket = op_state.get_bucket()->clone();
330
331 rgw::sal::Bucket::ListParams params;
332 params.list_versions = true;
333 params.ns = RGW_OBJ_NS_MULTIPART;
334
335 std::map<std::string, bool> meta_objs;
336 std::map<rgw_obj_index_key, std::string> all_objs;
337 bool is_truncated;
338 do {
339 rgw::sal::Bucket::ListResults results;
340 int r = bucket->list(dpp, params, listing_max_entries, results, null_yield);
341 if (r < 0) {
342 set_err_msg(err_msg, "failed to list objects in bucket=" + bucket->get_name() +
343 " err=" + cpp_strerror(-r));
344
345 return r;
346 }
347 is_truncated = results.is_truncated;
348
349 for (const auto& o : results.objs) {
350 rgw_obj_index_key key = o.key;
351 rgw_obj obj(bucket->get_key(), key);
352 std::string oid = obj.get_oid();
353
354 int pos = oid.find_last_of('.');
355 if (pos < 0) {
356 /* obj has no suffix */
357 all_objs[key] = oid;
358 } else {
359 /* obj has suffix */
360 std::string name = oid.substr(0, pos);
361 std::string suffix = oid.substr(pos + 1);
362
363 if (suffix.compare("meta") == 0) {
364 meta_objs[name] = true;
365 } else {
366 all_objs[key] = name;
367 }
368 }
369 }
370 } while (is_truncated);
371
372 std::list<rgw_obj_index_key> objs_to_unlink;
373 Formatter *f = flusher.get_formatter();
374
375 f->open_array_section("invalid_multipart_entries");
376
377 for (const auto& o : all_objs) {
378 const std::string& name = o.second;
379 if (meta_objs.find(name) == meta_objs.end()) {
380 objs_to_unlink.push_back(o.first);
381 }
382
383 if (objs_to_unlink.size() > listing_max_entries) {
384 if (fix_index) {
385 // note: under rados this removes directly from rados index objects
386 int r = bucket->remove_objs_from_index(dpp, objs_to_unlink);
387 if (r < 0) {
388 set_err_msg(err_msg, "ERROR: remove_obj_from_index() returned error: " +
389 cpp_strerror(-r));
390 return r;
391 }
392 }
393
394 dump_mulipart_index_results(objs_to_unlink, f);
395 flusher.flush();
396 objs_to_unlink.clear();
397 }
398 }
399
400 if (fix_index) {
401 // note: under rados this removes directly from rados index objects
402 int r = bucket->remove_objs_from_index(dpp, objs_to_unlink);
403 if (r < 0) {
404 set_err_msg(err_msg, "ERROR: remove_obj_from_index() returned error: " +
405 cpp_strerror(-r));
406
407 return r;
408 }
409 }
410
411 dump_mulipart_index_results(objs_to_unlink, f);
412 f->close_section();
413 flusher.flush();
414
415 return 0;
416 }
417
418 int RGWBucket::check_object_index(const DoutPrefixProvider *dpp,
419 RGWBucketAdminOpState& op_state,
420 RGWFormatterFlusher& flusher,
421 optional_yield y,
422 std::string *err_msg)
423 {
424
425 bool fix_index = op_state.will_fix_index();
426
427 if (!fix_index) {
428 set_err_msg(err_msg, "check-objects flag requires fix index enabled");
429 return -EINVAL;
430 }
431
432 // use a quicker/shorter tag timeout during this process
433 bucket->set_tag_timeout(dpp, BUCKET_TAG_QUICK_TIMEOUT);
434
435 rgw::sal::Bucket::ListResults results;
436 results.is_truncated = true;
437
438 Formatter *formatter = flusher.get_formatter();
439 formatter->open_object_section("objects");
440
441 while (results.is_truncated) {
442 rgw::sal::Bucket::ListParams params;
443 params.marker = results.next_marker;
444 params.force_check_filter = rgw_bucket_object_check_filter;
445
446 int r = bucket->list(dpp, params, listing_max_entries, results, y);
447
448 if (r == -ENOENT) {
449 break;
450 } else if (r < 0) {
451 set_err_msg(err_msg, "ERROR: failed operation r=" + cpp_strerror(-r));
452 }
453
454 dump_bucket_index(results.objs, formatter);
455 flusher.flush();
456 }
457
458 formatter->close_section();
459
460 // restore normal tag timeout for bucket
461 bucket->set_tag_timeout(dpp, 0);
462
463 return 0;
464 }
465
466
467 int RGWBucket::check_index(const DoutPrefixProvider *dpp,
468 RGWBucketAdminOpState& op_state,
469 map<RGWObjCategory, RGWStorageStats>& existing_stats,
470 map<RGWObjCategory, RGWStorageStats>& calculated_stats,
471 std::string *err_msg)
472 {
473 bool fix_index = op_state.will_fix_index();
474
475 int r = bucket->check_index(dpp, existing_stats, calculated_stats);
476 if (r < 0) {
477 set_err_msg(err_msg, "failed to check index error=" + cpp_strerror(-r));
478 return r;
479 }
480
481 if (fix_index) {
482 r = bucket->rebuild_index(dpp);
483 if (r < 0) {
484 set_err_msg(err_msg, "failed to rebuild index err=" + cpp_strerror(-r));
485 return r;
486 }
487 }
488
489 return 0;
490 }
491
492 int RGWBucket::sync(RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, std::string *err_msg)
493 {
494 if (!driver->is_meta_master()) {
495 set_err_msg(err_msg, "ERROR: failed to update bucket sync: only allowed on meta master zone");
496 return -EINVAL;
497 }
498 bool sync = op_state.will_sync_bucket();
499 if (sync) {
500 bucket->get_info().flags &= ~BUCKET_DATASYNC_DISABLED;
501 } else {
502 bucket->get_info().flags |= BUCKET_DATASYNC_DISABLED;
503 }
504
505 // when writing this metadata, RGWSI_BucketIndex_RADOS::handle_overwrite()
506 // will write the corresponding datalog and bilog entries
507 int r = bucket->put_info(dpp, false, real_time());
508 if (r < 0) {
509 set_err_msg(err_msg, "ERROR: failed writing bucket instance info:" + cpp_strerror(-r));
510 return r;
511 }
512
513 return 0;
514 }
515
516
517 int RGWBucket::policy_bl_to_stream(bufferlist& bl, ostream& o)
518 {
519 RGWAccessControlPolicy_S3 policy(g_ceph_context);
520 int ret = decode_bl(bl, policy);
521 if (ret < 0) {
522 ldout(driver->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl;
523 }
524 policy.to_xml(o);
525 return 0;
526 }
527
528 int rgw_object_get_attr(const DoutPrefixProvider *dpp,
529 rgw::sal::Driver* driver, rgw::sal::Object* obj,
530 const char* attr_name, bufferlist& out_bl, optional_yield y)
531 {
532 std::unique_ptr<rgw::sal::Object::ReadOp> rop = obj->get_read_op();
533
534 return rop->get_attr(dpp, attr_name, out_bl, y);
535 }
536
537 int RGWBucket::get_policy(RGWBucketAdminOpState& op_state, RGWAccessControlPolicy& policy, optional_yield y, const DoutPrefixProvider *dpp)
538 {
539 int ret;
540 std::string object_name = op_state.get_object_name();
541
542 bucket = op_state.get_bucket()->clone();
543
544 if (!object_name.empty()) {
545 bufferlist bl;
546 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(rgw_obj_key(object_name));
547
548 ret = rgw_object_get_attr(dpp, driver, obj.get(), RGW_ATTR_ACL, bl, y);
549 if (ret < 0){
550 return ret;
551 }
552
553 ret = decode_bl(bl, policy);
554 if (ret < 0) {
555 ldout(driver->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl;
556 }
557 return ret;
558 }
559
560 map<string, bufferlist>::iterator aiter = bucket->get_attrs().find(RGW_ATTR_ACL);
561 if (aiter == bucket->get_attrs().end()) {
562 return -ENOENT;
563 }
564
565 ret = decode_bl(aiter->second, policy);
566 if (ret < 0) {
567 ldout(driver->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl;
568 }
569
570 return ret;
571 }
572
573
574 int RGWBucketAdminOp::get_policy(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state,
575 RGWAccessControlPolicy& policy, const DoutPrefixProvider *dpp)
576 {
577 RGWBucket bucket;
578
579 int ret = bucket.init(driver, op_state, null_yield, dpp);
580 if (ret < 0)
581 return ret;
582
583 ret = bucket.get_policy(op_state, policy, null_yield, dpp);
584 if (ret < 0)
585 return ret;
586
587 return 0;
588 }
589
590 /* Wrappers to facilitate RESTful interface */
591
592
593 int RGWBucketAdminOp::get_policy(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state,
594 RGWFormatterFlusher& flusher, const DoutPrefixProvider *dpp)
595 {
596 RGWAccessControlPolicy policy(driver->ctx());
597
598 int ret = get_policy(driver, op_state, policy, dpp);
599 if (ret < 0)
600 return ret;
601
602 Formatter *formatter = flusher.get_formatter();
603
604 flusher.start(0);
605
606 formatter->open_object_section("policy");
607 policy.dump(formatter);
608 formatter->close_section();
609
610 flusher.flush();
611
612 return 0;
613 }
614
615 int RGWBucketAdminOp::dump_s3_policy(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state,
616 ostream& os, const DoutPrefixProvider *dpp)
617 {
618 RGWAccessControlPolicy_S3 policy(driver->ctx());
619
620 int ret = get_policy(driver, op_state, policy, dpp);
621 if (ret < 0)
622 return ret;
623
624 policy.to_xml(os);
625
626 return 0;
627 }
628
629 int RGWBucketAdminOp::unlink(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp)
630 {
631 RGWBucket bucket;
632
633 int ret = bucket.init(driver, op_state, null_yield, dpp);
634 if (ret < 0)
635 return ret;
636
637 return static_cast<rgw::sal::RadosStore*>(driver)->ctl()->bucket->unlink_bucket(op_state.get_user_id(), op_state.get_bucket()->get_info().bucket, null_yield, dpp, true);
638 }
639
640 int RGWBucketAdminOp::link(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, string *err)
641 {
642 if (!op_state.is_user_op()) {
643 set_err_msg(err, "empty user id");
644 return -EINVAL;
645 }
646
647 RGWBucket bucket;
648 int ret = bucket.init(driver, op_state, null_yield, dpp, err);
649 if (ret < 0)
650 return ret;
651
652 string bucket_id = op_state.get_bucket_id();
653 std::string display_name = op_state.get_user_display_name();
654 std::unique_ptr<rgw::sal::Bucket> loc_bucket;
655 std::unique_ptr<rgw::sal::Bucket> old_bucket;
656
657 loc_bucket = op_state.get_bucket()->clone();
658
659 if (!bucket_id.empty() && bucket_id != loc_bucket->get_bucket_id()) {
660 set_err_msg(err,
661 "specified bucket id does not match " + loc_bucket->get_bucket_id());
662 return -EINVAL;
663 }
664
665 old_bucket = loc_bucket->clone();
666
667 loc_bucket->get_key().tenant = op_state.get_user_id().tenant;
668
669 if (!op_state.new_bucket_name.empty()) {
670 auto pos = op_state.new_bucket_name.find('/');
671 if (pos != string::npos) {
672 loc_bucket->get_key().tenant = op_state.new_bucket_name.substr(0, pos);
673 loc_bucket->get_key().name = op_state.new_bucket_name.substr(pos + 1);
674 } else {
675 loc_bucket->get_key().name = op_state.new_bucket_name;
676 }
677 }
678
679 RGWObjVersionTracker objv_tracker;
680 RGWObjVersionTracker old_version = loc_bucket->get_info().objv_tracker;
681
682 map<string, bufferlist>::iterator aiter = loc_bucket->get_attrs().find(RGW_ATTR_ACL);
683 if (aiter == loc_bucket->get_attrs().end()) {
684 // should never happen; only pre-argonaut buckets lacked this.
685 ldpp_dout(dpp, 0) << "WARNING: can't bucket link because no acl on bucket=" << old_bucket << dendl;
686 set_err_msg(err,
687 "While crossing the Anavros you have displeased the goddess Hera."
688 " You must sacrifice your ancient bucket " + loc_bucket->get_bucket_id());
689 return -EINVAL;
690 }
691 bufferlist& aclbl = aiter->second;
692 RGWAccessControlPolicy policy;
693 ACLOwner owner;
694 try {
695 auto iter = aclbl.cbegin();
696 decode(policy, iter);
697 owner = policy.get_owner();
698 } catch (buffer::error& e) {
699 set_err_msg(err, "couldn't decode policy");
700 return -EIO;
701 }
702
703 int r = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->bucket->unlink_bucket(owner.get_id(), old_bucket->get_info().bucket, null_yield, dpp, false);
704 if (r < 0) {
705 set_err_msg(err, "could not unlink policy from user " + owner.get_id().to_str());
706 return r;
707 }
708
709 // now update the user for the bucket...
710 if (display_name.empty()) {
711 ldpp_dout(dpp, 0) << "WARNING: user " << op_state.get_user_id() << " has no display name set" << dendl;
712 }
713
714 RGWAccessControlPolicy policy_instance;
715 policy_instance.create_default(op_state.get_user_id(), display_name);
716 owner = policy_instance.get_owner();
717
718 aclbl.clear();
719 policy_instance.encode(aclbl);
720
721 bool exclusive = false;
722 loc_bucket->get_info().owner = op_state.get_user_id();
723 if (*loc_bucket != *old_bucket) {
724 loc_bucket->get_info().bucket = loc_bucket->get_key();
725 loc_bucket->get_info().objv_tracker.version_for_read()->ver = 0;
726 exclusive = true;
727 }
728
729 r = loc_bucket->put_info(dpp, exclusive, ceph::real_time());
730 if (r < 0) {
731 set_err_msg(err, "ERROR: failed writing bucket instance info: " + cpp_strerror(-r));
732 return r;
733 }
734
735 /* link to user */
736 RGWBucketEntryPoint ep;
737 ep.bucket = loc_bucket->get_info().bucket;
738 ep.owner = op_state.get_user_id();
739 ep.creation_time = loc_bucket->get_info().creation_time;
740 ep.linked = true;
741 rgw::sal::Attrs ep_attrs;
742 rgw_ep_info ep_data{ep, ep_attrs};
743
744 r = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->bucket->link_bucket(op_state.get_user_id(), loc_bucket->get_info().bucket, loc_bucket->get_info().creation_time, null_yield, dpp, true, &ep_data);
745 if (r < 0) {
746 set_err_msg(err, "failed to relink bucket");
747 return r;
748 }
749
750 if (*loc_bucket != *old_bucket) {
751 // like RGWRados::delete_bucket -- excepting no bucket_index work.
752 r = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->bucket->remove_bucket_entrypoint_info(
753 old_bucket->get_key(), null_yield, dpp,
754 RGWBucketCtl::Bucket::RemoveParams()
755 .set_objv_tracker(&ep_data.ep_objv));
756 if (r < 0) {
757 set_err_msg(err, "failed to unlink old bucket " + old_bucket->get_tenant() + "/" + old_bucket->get_name());
758 return r;
759 }
760 r = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->bucket->remove_bucket_instance_info(
761 old_bucket->get_key(), old_bucket->get_info(),
762 null_yield, dpp,
763 RGWBucketCtl::BucketInstance::RemoveParams()
764 .set_objv_tracker(&ep_data.ep_objv));
765 if (r < 0) {
766 set_err_msg(err, "failed to unlink old bucket " + old_bucket->get_tenant() + "/" + old_bucket->get_name());
767 return r;
768 }
769 }
770
771 return 0;
772 }
773
774 int RGWBucketAdminOp::chown(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, const string& marker, const DoutPrefixProvider *dpp, string *err)
775 {
776 RGWBucket bucket;
777
778 int ret = bucket.init(driver, op_state, null_yield, dpp, err);
779 if (ret < 0)
780 return ret;
781
782 return bucket.chown(op_state, marker, null_yield, dpp, err);
783
784 }
785
786 int RGWBucketAdminOp::check_index(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state,
787 RGWFormatterFlusher& flusher, optional_yield y, const DoutPrefixProvider *dpp)
788 {
789 int ret;
790 map<RGWObjCategory, RGWStorageStats> existing_stats;
791 map<RGWObjCategory, RGWStorageStats> calculated_stats;
792
793
794 RGWBucket bucket;
795
796 ret = bucket.init(driver, op_state, null_yield, dpp);
797 if (ret < 0)
798 return ret;
799
800 Formatter *formatter = flusher.get_formatter();
801 flusher.start(0);
802
803 ret = bucket.check_bad_index_multipart(op_state, flusher, dpp);
804 if (ret < 0)
805 return ret;
806
807 ret = bucket.check_object_index(dpp, op_state, flusher, y);
808 if (ret < 0)
809 return ret;
810
811 ret = bucket.check_index(dpp, op_state, existing_stats, calculated_stats);
812 if (ret < 0)
813 return ret;
814
815 dump_index_check(existing_stats, calculated_stats, formatter);
816 flusher.flush();
817
818 return 0;
819 }
820
821 int RGWBucketAdminOp::remove_bucket(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state,
822 optional_yield y, const DoutPrefixProvider *dpp,
823 bool bypass_gc, bool keep_index_consistent)
824 {
825 std::unique_ptr<rgw::sal::Bucket> bucket;
826 std::unique_ptr<rgw::sal::User> user = driver->get_user(op_state.get_user_id());
827
828 int ret = driver->get_bucket(dpp, user.get(), user->get_tenant(), op_state.get_bucket_name(),
829 &bucket, y);
830 if (ret < 0)
831 return ret;
832
833 if (bypass_gc)
834 ret = bucket->remove_bucket_bypass_gc(op_state.get_max_aio(), keep_index_consistent, y, dpp);
835 else
836 ret = bucket->remove_bucket(dpp, op_state.will_delete_children(),
837 false, nullptr, y);
838
839 return ret;
840 }
841
842 int RGWBucketAdminOp::remove_object(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp)
843 {
844 RGWBucket bucket;
845
846 int ret = bucket.init(driver, op_state, null_yield, dpp);
847 if (ret < 0)
848 return ret;
849
850 return bucket.remove_object(dpp, op_state);
851 }
852
853 int RGWBucketAdminOp::sync_bucket(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp, string *err_msg)
854 {
855 RGWBucket bucket;
856 int ret = bucket.init(driver, op_state, null_yield, dpp, err_msg);
857 if (ret < 0)
858 {
859 return ret;
860 }
861 return bucket.sync(op_state, dpp, err_msg);
862 }
863
864 static int bucket_stats(rgw::sal::Driver* driver,
865 const std::string& tenant_name,
866 const std::string& bucket_name,
867 Formatter *formatter,
868 const DoutPrefixProvider *dpp)
869 {
870 std::unique_ptr<rgw::sal::Bucket> bucket;
871 map<RGWObjCategory, RGWStorageStats> stats;
872
873 int ret = driver->get_bucket(dpp, nullptr, tenant_name, bucket_name, &bucket, null_yield);
874 if (ret < 0) {
875 return ret;
876 }
877
878 const auto& index = bucket->get_info().get_current_index();
879 if (is_layout_indexless(index)) {
880 cerr << "error, indexless buckets do not maintain stats; bucket=" <<
881 bucket->get_name() << std::endl;
882 return -EINVAL;
883 }
884
885 std::string bucket_ver, master_ver;
886 std::string max_marker;
887 ret = bucket->read_stats(dpp, index, RGW_NO_SHARD, &bucket_ver, &master_ver, stats, &max_marker);
888 if (ret < 0) {
889 cerr << "error getting bucket stats bucket=" << bucket->get_name() << " ret=" << ret << std::endl;
890 return ret;
891 }
892
893 utime_t ut(bucket->get_modification_time());
894 utime_t ctime_ut(bucket->get_creation_time());
895
896 formatter->open_object_section("stats");
897 formatter->dump_string("bucket", bucket->get_name());
898 formatter->dump_int("num_shards",
899 bucket->get_info().layout.current_index.layout.normal.num_shards);
900 formatter->dump_string("tenant", bucket->get_tenant());
901 formatter->dump_string("zonegroup", bucket->get_info().zonegroup);
902 formatter->dump_string("placement_rule", bucket->get_info().placement_rule.to_str());
903 ::encode_json("explicit_placement", bucket->get_key().explicit_placement, formatter);
904 formatter->dump_string("id", bucket->get_bucket_id());
905 formatter->dump_string("marker", bucket->get_marker());
906 formatter->dump_stream("index_type") << bucket->get_info().layout.current_index.layout.type;
907 ::encode_json("owner", bucket->get_info().owner, formatter);
908 formatter->dump_string("ver", bucket_ver);
909 formatter->dump_string("master_ver", master_ver);
910 ut.gmtime(formatter->dump_stream("mtime"));
911 ctime_ut.gmtime(formatter->dump_stream("creation_time"));
912 formatter->dump_string("max_marker", max_marker);
913 dump_bucket_usage(stats, formatter);
914 encode_json("bucket_quota", bucket->get_info().quota, formatter);
915
916 // bucket tags
917 auto iter = bucket->get_attrs().find(RGW_ATTR_TAGS);
918 if (iter != bucket->get_attrs().end()) {
919 RGWObjTagSet_S3 tagset;
920 bufferlist::const_iterator piter{&iter->second};
921 try {
922 tagset.decode(piter);
923 tagset.dump(formatter);
924 } catch (buffer::error& err) {
925 cerr << "ERROR: caught buffer:error, couldn't decode TagSet" << std::endl;
926 }
927 }
928
929 // TODO: bucket CORS
930 // TODO: bucket LC
931 formatter->close_section();
932
933 return 0;
934 }
935
936 int RGWBucketAdminOp::limit_check(rgw::sal::Driver* driver,
937 RGWBucketAdminOpState& op_state,
938 const std::list<std::string>& user_ids,
939 RGWFormatterFlusher& flusher, optional_yield y,
940 const DoutPrefixProvider *dpp,
941 bool warnings_only)
942 {
943 int ret = 0;
944 const size_t max_entries =
945 driver->ctx()->_conf->rgw_list_buckets_max_chunk;
946
947 const size_t safe_max_objs_per_shard =
948 driver->ctx()->_conf->rgw_safe_max_objects_per_shard;
949
950 uint16_t shard_warn_pct =
951 driver->ctx()->_conf->rgw_shard_warning_threshold;
952 if (shard_warn_pct > 100)
953 shard_warn_pct = 90;
954
955 Formatter *formatter = flusher.get_formatter();
956 flusher.start(0);
957
958 formatter->open_array_section("users");
959
960 for (const auto& user_id : user_ids) {
961
962 formatter->open_object_section("user");
963 formatter->dump_string("user_id", user_id);
964 formatter->open_array_section("buckets");
965
966 string marker;
967 rgw::sal::BucketList buckets;
968 do {
969 std::unique_ptr<rgw::sal::User> user = driver->get_user(rgw_user(user_id));
970
971 ret = user->list_buckets(dpp, marker, string(), max_entries, false, buckets, y);
972
973 if (ret < 0)
974 return ret;
975
976 map<string, std::unique_ptr<rgw::sal::Bucket>>& m_buckets = buckets.get_buckets();
977
978 for (const auto& iter : m_buckets) {
979 auto& bucket = iter.second;
980 uint64_t num_objects = 0;
981
982 marker = bucket->get_name(); /* Casey's location for marker update,
983 * as we may now not reach the end of
984 * the loop body */
985
986 ret = bucket->load_bucket(dpp, y);
987 if (ret < 0)
988 continue;
989
990 const auto& index = bucket->get_info().get_current_index();
991 if (is_layout_indexless(index)) {
992 continue; // indexless buckets don't have stats
993 }
994
995 /* need stats for num_entries */
996 string bucket_ver, master_ver;
997 std::map<RGWObjCategory, RGWStorageStats> stats;
998 ret = bucket->read_stats(dpp, index, RGW_NO_SHARD, &bucket_ver, &master_ver, stats, nullptr);
999
1000 if (ret < 0)
1001 continue;
1002
1003 for (const auto& s : stats) {
1004 num_objects += s.second.num_objects;
1005 }
1006
1007 const uint32_t num_shards = rgw::num_shards(index.layout.normal);
1008 uint64_t objs_per_shard =
1009 (num_shards) ? num_objects/num_shards : num_objects;
1010 {
1011 bool warn;
1012 stringstream ss;
1013 uint64_t fill_pct = objs_per_shard * 100 / safe_max_objs_per_shard;
1014 if (fill_pct > 100) {
1015 ss << "OVER " << fill_pct << "%";
1016 warn = true;
1017 } else if (fill_pct >= shard_warn_pct) {
1018 ss << "WARN " << fill_pct << "%";
1019 warn = true;
1020 } else {
1021 ss << "OK";
1022 warn = false;
1023 }
1024
1025 if (warn || !warnings_only) {
1026 formatter->open_object_section("bucket");
1027 formatter->dump_string("bucket", bucket->get_name());
1028 formatter->dump_string("tenant", bucket->get_tenant());
1029 formatter->dump_int("num_objects", num_objects);
1030 formatter->dump_int("num_shards", num_shards);
1031 formatter->dump_int("objects_per_shard", objs_per_shard);
1032 formatter->dump_string("fill_status", ss.str());
1033 formatter->close_section();
1034 }
1035 }
1036 }
1037 formatter->flush(cout);
1038 } while (buckets.is_truncated()); /* foreach: bucket */
1039
1040 formatter->close_section();
1041 formatter->close_section();
1042 formatter->flush(cout);
1043
1044 } /* foreach: user_id */
1045
1046 formatter->close_section();
1047 formatter->flush(cout);
1048
1049 return ret;
1050 } /* RGWBucketAdminOp::limit_check */
1051
1052 int RGWBucketAdminOp::info(rgw::sal::Driver* driver,
1053 RGWBucketAdminOpState& op_state,
1054 RGWFormatterFlusher& flusher,
1055 optional_yield y,
1056 const DoutPrefixProvider *dpp)
1057 {
1058 RGWBucket bucket;
1059 int ret = 0;
1060 const std::string& bucket_name = op_state.get_bucket_name();
1061 if (!bucket_name.empty()) {
1062 ret = bucket.init(driver, op_state, y, dpp);
1063 if (-ENOENT == ret)
1064 return -ERR_NO_SUCH_BUCKET;
1065 else if (ret < 0)
1066 return ret;
1067 }
1068
1069 Formatter *formatter = flusher.get_formatter();
1070 flusher.start(0);
1071
1072 CephContext *cct = driver->ctx();
1073
1074 const size_t max_entries = cct->_conf->rgw_list_buckets_max_chunk;
1075
1076 const bool show_stats = op_state.will_fetch_stats();
1077 const rgw_user& user_id = op_state.get_user_id();
1078 if (op_state.is_user_op()) {
1079 formatter->open_array_section("buckets");
1080
1081 rgw::sal::BucketList buckets;
1082 std::unique_ptr<rgw::sal::User> user = driver->get_user(op_state.get_user_id());
1083 std::string marker;
1084 const std::string empty_end_marker;
1085 constexpr bool no_need_stats = false; // set need_stats to false
1086
1087 do {
1088 ret = user->list_buckets(dpp, marker, empty_end_marker, max_entries,
1089 no_need_stats, buckets, y);
1090 if (ret < 0) {
1091 return ret;
1092 }
1093
1094 const std::string* marker_cursor = nullptr;
1095 map<string, std::unique_ptr<rgw::sal::Bucket>>& m = buckets.get_buckets();
1096
1097 for (const auto& i : m) {
1098 const std::string& obj_name = i.first;
1099 if (!bucket_name.empty() && bucket_name != obj_name) {
1100 continue;
1101 }
1102
1103 if (show_stats) {
1104 bucket_stats(driver, user_id.tenant, obj_name, formatter, dpp);
1105 } else {
1106 formatter->dump_string("bucket", obj_name);
1107 }
1108
1109 marker_cursor = &obj_name;
1110 } // for loop
1111 if (marker_cursor) {
1112 marker = *marker_cursor;
1113 }
1114
1115 flusher.flush();
1116 } while (buckets.is_truncated());
1117
1118 formatter->close_section();
1119 } else if (!bucket_name.empty()) {
1120 ret = bucket_stats(driver, user_id.tenant, bucket_name, formatter, dpp);
1121 if (ret < 0) {
1122 return ret;
1123 }
1124 } else {
1125 void *handle = nullptr;
1126 bool truncated = true;
1127
1128 formatter->open_array_section("buckets");
1129 ret = driver->meta_list_keys_init(dpp, "bucket", string(), &handle);
1130 while (ret == 0 && truncated) {
1131 std::list<std::string> buckets;
1132 constexpr int max_keys = 1000;
1133 ret = driver->meta_list_keys_next(dpp, handle, max_keys, buckets,
1134 &truncated);
1135 for (auto& bucket_name : buckets) {
1136 if (show_stats) {
1137 bucket_stats(driver, user_id.tenant, bucket_name, formatter, dpp);
1138 } else {
1139 formatter->dump_string("bucket", bucket_name);
1140 }
1141 }
1142 }
1143 driver->meta_list_keys_complete(handle);
1144
1145 formatter->close_section();
1146 }
1147
1148 flusher.flush();
1149
1150 return 0;
1151 }
1152
1153 int RGWBucketAdminOp::set_quota(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state, const DoutPrefixProvider *dpp)
1154 {
1155 RGWBucket bucket;
1156
1157 int ret = bucket.init(driver, op_state, null_yield, dpp);
1158 if (ret < 0)
1159 return ret;
1160 return bucket.set_quota(op_state, dpp);
1161 }
1162
1163 inline auto split_tenant(const std::string& bucket_name){
1164 auto p = bucket_name.find('/');
1165 if(p != std::string::npos) {
1166 return std::make_pair(bucket_name.substr(0,p), bucket_name.substr(p+1));
1167 }
1168 return std::make_pair(std::string(), bucket_name);
1169 }
1170
1171 using bucket_instance_ls = std::vector<RGWBucketInfo>;
1172 void get_stale_instances(rgw::sal::Driver* driver, const std::string& bucket_name,
1173 const vector<std::string>& lst,
1174 bucket_instance_ls& stale_instances,
1175 const DoutPrefixProvider *dpp)
1176 {
1177
1178 bucket_instance_ls other_instances;
1179 // first iterate over the entries, and pick up the done buckets; these
1180 // are guaranteed to be stale
1181 for (const auto& bucket_instance : lst){
1182 RGWBucketInfo binfo;
1183 std::unique_ptr<rgw::sal::Bucket> bucket;
1184 rgw_bucket rbucket;
1185 rgw_bucket_parse_bucket_key(driver->ctx(), bucket_instance, &rbucket, nullptr);
1186 int r = driver->get_bucket(dpp, nullptr, rbucket, &bucket, null_yield);
1187 if (r < 0){
1188 // this can only happen if someone deletes us right when we're processing
1189 ldpp_dout(dpp, -1) << "Bucket instance is invalid: " << bucket_instance
1190 << cpp_strerror(-r) << dendl;
1191 continue;
1192 }
1193 binfo = bucket->get_info();
1194 if (binfo.reshard_status == cls_rgw_reshard_status::DONE)
1195 stale_instances.emplace_back(std::move(binfo));
1196 else {
1197 other_instances.emplace_back(std::move(binfo));
1198 }
1199 }
1200
1201 // Read the cur bucket info, if the bucket doesn't exist we can simply return
1202 // all the instances
1203 auto [tenant, bname] = split_tenant(bucket_name);
1204 RGWBucketInfo cur_bucket_info;
1205 std::unique_ptr<rgw::sal::Bucket> cur_bucket;
1206 int r = driver->get_bucket(dpp, nullptr, tenant, bname, &cur_bucket, null_yield);
1207 if (r < 0) {
1208 if (r == -ENOENT) {
1209 // bucket doesn't exist, everything is stale then
1210 stale_instances.insert(std::end(stale_instances),
1211 std::make_move_iterator(other_instances.begin()),
1212 std::make_move_iterator(other_instances.end()));
1213 } else {
1214 // all bets are off if we can't read the bucket, just return the sureshot stale instances
1215 ldpp_dout(dpp, -1) << "error: reading bucket info for bucket: "
1216 << bname << cpp_strerror(-r) << dendl;
1217 }
1218 return;
1219 }
1220
1221 // Don't process further in this round if bucket is resharding
1222 cur_bucket_info = cur_bucket->get_info();
1223 if (cur_bucket_info.reshard_status == cls_rgw_reshard_status::IN_PROGRESS)
1224 return;
1225
1226 other_instances.erase(std::remove_if(other_instances.begin(), other_instances.end(),
1227 [&cur_bucket_info](const RGWBucketInfo& b){
1228 return (b.bucket.bucket_id == cur_bucket_info.bucket.bucket_id ||
1229 b.bucket.bucket_id == cur_bucket_info.new_bucket_instance_id);
1230 }),
1231 other_instances.end());
1232
1233 // check if there are still instances left
1234 if (other_instances.empty()) {
1235 return;
1236 }
1237
1238 // Now we have a bucket with instances where the reshard status is none, this
1239 // usually happens when the reshard process couldn't complete, lockdown the
1240 // bucket and walk through these instances to make sure no one else interferes
1241 // with these
1242 {
1243 RGWBucketReshardLock reshard_lock(static_cast<rgw::sal::RadosStore*>(driver), cur_bucket->get_info(), true);
1244 r = reshard_lock.lock(dpp);
1245 if (r < 0) {
1246 // most likely bucket is under reshard, return the sureshot stale instances
1247 ldpp_dout(dpp, 5) << __func__
1248 << "failed to take reshard lock; reshard underway likey" << dendl;
1249 return;
1250 }
1251 auto sg = make_scope_guard([&reshard_lock](){ reshard_lock.unlock();} );
1252 // this should be fast enough that we may not need to renew locks and check
1253 // exit status?, should we read the values of the instances again?
1254 stale_instances.insert(std::end(stale_instances),
1255 std::make_move_iterator(other_instances.begin()),
1256 std::make_move_iterator(other_instances.end()));
1257 }
1258
1259 return;
1260 }
1261
1262 static int process_stale_instances(rgw::sal::Driver* driver, RGWBucketAdminOpState& op_state,
1263 RGWFormatterFlusher& flusher,
1264 const DoutPrefixProvider *dpp,
1265 std::function<void(const bucket_instance_ls&,
1266 Formatter *,
1267 rgw::sal::Driver*)> process_f)
1268 {
1269 std::string marker;
1270 void *handle;
1271 Formatter *formatter = flusher.get_formatter();
1272 static constexpr auto default_max_keys = 1000;
1273
1274 int ret = driver->meta_list_keys_init(dpp, "bucket.instance", marker, &handle);
1275 if (ret < 0) {
1276 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
1277 return ret;
1278 }
1279
1280 bool truncated;
1281
1282 formatter->open_array_section("keys");
1283 auto g = make_scope_guard([&driver, &handle, &formatter]() {
1284 driver->meta_list_keys_complete(handle);
1285 formatter->close_section(); // keys
1286 formatter->flush(cout);
1287 });
1288
1289 do {
1290 list<std::string> keys;
1291
1292 ret = driver->meta_list_keys_next(dpp, handle, default_max_keys, keys, &truncated);
1293 if (ret < 0 && ret != -ENOENT) {
1294 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
1295 return ret;
1296 } if (ret != -ENOENT) {
1297 // partition the list of buckets by buckets as the listing is un sorted,
1298 // since it would minimize the reads to bucket_info
1299 std::unordered_map<std::string, std::vector<std::string>> bucket_instance_map;
1300 for (auto &key: keys) {
1301 auto pos = key.find(':');
1302 if(pos != std::string::npos)
1303 bucket_instance_map[key.substr(0,pos)].emplace_back(std::move(key));
1304 }
1305 for (const auto& kv: bucket_instance_map) {
1306 bucket_instance_ls stale_lst;
1307 get_stale_instances(driver, kv.first, kv.second, stale_lst, dpp);
1308 process_f(stale_lst, formatter, driver);
1309 }
1310 }
1311 } while (truncated);
1312
1313 return 0;
1314 }
1315
1316 int RGWBucketAdminOp::list_stale_instances(rgw::sal::Driver* driver,
1317 RGWBucketAdminOpState& op_state,
1318 RGWFormatterFlusher& flusher,
1319 const DoutPrefixProvider *dpp)
1320 {
1321 auto process_f = [](const bucket_instance_ls& lst,
1322 Formatter *formatter,
1323 rgw::sal::Driver*){
1324 for (const auto& binfo: lst)
1325 formatter->dump_string("key", binfo.bucket.get_key());
1326 };
1327 return process_stale_instances(driver, op_state, flusher, dpp, process_f);
1328 }
1329
1330
1331 int RGWBucketAdminOp::clear_stale_instances(rgw::sal::Driver* driver,
1332 RGWBucketAdminOpState& op_state,
1333 RGWFormatterFlusher& flusher,
1334 const DoutPrefixProvider *dpp)
1335 {
1336 auto process_f = [dpp](const bucket_instance_ls& lst,
1337 Formatter *formatter,
1338 rgw::sal::Driver* driver){
1339 for (const auto &binfo: lst) {
1340 std::unique_ptr<rgw::sal::Bucket> bucket;
1341 driver->get_bucket(nullptr, binfo, &bucket);
1342 int ret = bucket->purge_instance(dpp);
1343 if (ret == 0){
1344 auto md_key = "bucket.instance:" + binfo.bucket.get_key();
1345 ret = driver->meta_remove(dpp, md_key, null_yield);
1346 }
1347 formatter->open_object_section("delete_status");
1348 formatter->dump_string("bucket_instance", binfo.bucket.get_key());
1349 formatter->dump_int("status", -ret);
1350 formatter->close_section();
1351 }
1352 };
1353
1354 return process_stale_instances(driver, op_state, flusher, dpp, process_f);
1355 }
1356
1357 static int fix_single_bucket_lc(rgw::sal::Driver* driver,
1358 const std::string& tenant_name,
1359 const std::string& bucket_name,
1360 const DoutPrefixProvider *dpp)
1361 {
1362 std::unique_ptr<rgw::sal::Bucket> bucket;
1363 int ret = driver->get_bucket(dpp, nullptr, tenant_name, bucket_name, &bucket, null_yield);
1364 if (ret < 0) {
1365 // TODO: Should we handle the case where the bucket could've been removed between
1366 // listing and fetching?
1367 return ret;
1368 }
1369
1370 return rgw::lc::fix_lc_shard_entry(dpp, driver, driver->get_rgwlc()->get_lc(), bucket.get());
1371 }
1372
1373 static void format_lc_status(Formatter* formatter,
1374 const std::string& tenant_name,
1375 const std::string& bucket_name,
1376 int status)
1377 {
1378 formatter->open_object_section("bucket_entry");
1379 std::string entry = tenant_name.empty() ? bucket_name : tenant_name + "/" + bucket_name;
1380 formatter->dump_string("bucket", entry);
1381 formatter->dump_int("status", status);
1382 formatter->close_section(); // bucket_entry
1383 }
1384
1385 static void process_single_lc_entry(rgw::sal::Driver* driver,
1386 Formatter *formatter,
1387 const std::string& tenant_name,
1388 const std::string& bucket_name,
1389 const DoutPrefixProvider *dpp)
1390 {
1391 int ret = fix_single_bucket_lc(driver, tenant_name, bucket_name, dpp);
1392 format_lc_status(formatter, tenant_name, bucket_name, -ret);
1393 }
1394
1395 int RGWBucketAdminOp::fix_lc_shards(rgw::sal::Driver* driver,
1396 RGWBucketAdminOpState& op_state,
1397 RGWFormatterFlusher& flusher,
1398 const DoutPrefixProvider *dpp)
1399 {
1400 std::string marker;
1401 void *handle;
1402 Formatter *formatter = flusher.get_formatter();
1403 static constexpr auto default_max_keys = 1000;
1404
1405 bool truncated;
1406 if (const std::string& bucket_name = op_state.get_bucket_name();
1407 ! bucket_name.empty()) {
1408 const rgw_user user_id = op_state.get_user_id();
1409 process_single_lc_entry(driver, formatter, user_id.tenant, bucket_name, dpp);
1410 formatter->flush(cout);
1411 } else {
1412 int ret = driver->meta_list_keys_init(dpp, "bucket", marker, &handle);
1413 if (ret < 0) {
1414 std::cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
1415 return ret;
1416 }
1417
1418 {
1419 formatter->open_array_section("lc_fix_status");
1420 auto sg = make_scope_guard([&driver, &handle, &formatter](){
1421 driver->meta_list_keys_complete(handle);
1422 formatter->close_section(); // lc_fix_status
1423 formatter->flush(cout);
1424 });
1425 do {
1426 list<std::string> keys;
1427 ret = driver->meta_list_keys_next(dpp, handle, default_max_keys, keys, &truncated);
1428 if (ret < 0 && ret != -ENOENT) {
1429 std::cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
1430 return ret;
1431 } if (ret != -ENOENT) {
1432 for (const auto &key:keys) {
1433 auto [tenant_name, bucket_name] = split_tenant(key);
1434 process_single_lc_entry(driver, formatter, tenant_name, bucket_name, dpp);
1435 }
1436 }
1437 formatter->flush(cout); // regularly flush every 1k entries
1438 } while (truncated);
1439 }
1440
1441 }
1442 return 0;
1443
1444 }
1445
1446 static bool has_object_expired(const DoutPrefixProvider *dpp,
1447 rgw::sal::Driver* driver,
1448 rgw::sal::Bucket* bucket,
1449 const rgw_obj_key& key, utime_t& delete_at)
1450 {
1451 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(key);
1452 bufferlist delete_at_bl;
1453
1454 int ret = rgw_object_get_attr(dpp, driver, obj.get(), RGW_ATTR_DELETE_AT, delete_at_bl, null_yield);
1455 if (ret < 0) {
1456 return false; // no delete at attr, proceed
1457 }
1458
1459 ret = decode_bl(delete_at_bl, delete_at);
1460 if (ret < 0) {
1461 return false; // failed to parse
1462 }
1463
1464 if (delete_at <= ceph_clock_now() && !delete_at.is_zero()) {
1465 return true;
1466 }
1467
1468 return false;
1469 }
1470
1471 static int fix_bucket_obj_expiry(const DoutPrefixProvider *dpp,
1472 rgw::sal::Driver* driver,
1473 rgw::sal::Bucket* bucket,
1474 RGWFormatterFlusher& flusher, bool dry_run)
1475 {
1476 if (bucket->get_key().bucket_id == bucket->get_key().marker) {
1477 ldpp_dout(dpp, -1) << "Not a resharded bucket skipping" << dendl;
1478 return 0; // not a resharded bucket, move along
1479 }
1480
1481 Formatter *formatter = flusher.get_formatter();
1482 formatter->open_array_section("expired_deletion_status");
1483 auto sg = make_scope_guard([&formatter] {
1484 formatter->close_section();
1485 formatter->flush(std::cout);
1486 });
1487
1488 rgw::sal::Bucket::ListParams params;
1489 rgw::sal::Bucket::ListResults results;
1490
1491 params.list_versions = bucket->versioned();
1492 params.allow_unordered = true;
1493
1494 do {
1495 int ret = bucket->list(dpp, params, listing_max_entries, results, null_yield);
1496 if (ret < 0) {
1497 ldpp_dout(dpp, -1) << "ERROR failed to list objects in the bucket" << dendl;
1498 return ret;
1499 }
1500 for (const auto& obj : results.objs) {
1501 rgw_obj_key key(obj.key);
1502 utime_t delete_at;
1503 if (has_object_expired(dpp, driver, bucket, key, delete_at)) {
1504 formatter->open_object_section("object_status");
1505 formatter->dump_string("object", key.name);
1506 formatter->dump_stream("delete_at") << delete_at;
1507
1508 if (!dry_run) {
1509 ret = rgw_remove_object(dpp, driver, bucket, key);
1510 formatter->dump_int("status", ret);
1511 }
1512
1513 formatter->close_section(); // object_status
1514 }
1515 }
1516 formatter->flush(cout); // regularly flush every 1k entries
1517 } while (results.is_truncated);
1518
1519 return 0;
1520 }
1521
1522 int RGWBucketAdminOp::fix_obj_expiry(rgw::sal::Driver* driver,
1523 RGWBucketAdminOpState& op_state,
1524 RGWFormatterFlusher& flusher,
1525 const DoutPrefixProvider *dpp, bool dry_run)
1526 {
1527 RGWBucket admin_bucket;
1528 int ret = admin_bucket.init(driver, op_state, null_yield, dpp);
1529 if (ret < 0) {
1530 ldpp_dout(dpp, -1) << "failed to initialize bucket" << dendl;
1531 return ret;
1532 }
1533 std::unique_ptr<rgw::sal::Bucket> bucket;
1534 ret = driver->get_bucket(nullptr, admin_bucket.get_bucket_info(), &bucket);
1535 if (ret < 0) {
1536 return ret;
1537 }
1538
1539 return fix_bucket_obj_expiry(dpp, driver, bucket.get(), flusher, dry_run);
1540 }
1541
1542 void RGWBucketCompleteInfo::dump(Formatter *f) const {
1543 encode_json("bucket_info", info, f);
1544 encode_json("attrs", attrs, f);
1545 }
1546
1547 void RGWBucketCompleteInfo::decode_json(JSONObj *obj) {
1548 JSONDecoder::decode_json("bucket_info", info, obj);
1549 JSONDecoder::decode_json("attrs", attrs, obj);
1550 }
1551
1552 class RGWBucketMetadataHandler : public RGWBucketMetadataHandlerBase {
1553 public:
1554 struct Svc {
1555 RGWSI_Bucket *bucket{nullptr};
1556 } svc;
1557
1558 struct Ctl {
1559 RGWBucketCtl *bucket{nullptr};
1560 } ctl;
1561
1562 RGWBucketMetadataHandler() {}
1563
1564 void init(RGWSI_Bucket *bucket_svc,
1565 RGWBucketCtl *bucket_ctl) override {
1566 base_init(bucket_svc->ctx(),
1567 bucket_svc->get_ep_be_handler().get());
1568 svc.bucket = bucket_svc;
1569 ctl.bucket = bucket_ctl;
1570 }
1571
1572 string get_type() override { return "bucket"; }
1573
1574 RGWMetadataObject *get_meta_obj(JSONObj *jo, const obj_version& objv, const ceph::real_time& mtime) override {
1575 RGWBucketEntryPoint be;
1576
1577 try {
1578 decode_json_obj(be, jo);
1579 } catch (JSONDecoder::err& e) {
1580 return nullptr;
1581 }
1582
1583 return new RGWBucketEntryMetadataObject(be, objv, mtime);
1584 }
1585
1586 int do_get(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWMetadataObject **obj, optional_yield y, const DoutPrefixProvider *dpp) override {
1587 RGWObjVersionTracker ot;
1588 RGWBucketEntryPoint be;
1589
1590 real_time mtime;
1591 map<string, bufferlist> attrs;
1592
1593 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
1594
1595 int ret = svc.bucket->read_bucket_entrypoint_info(ctx, entry, &be, &ot, &mtime, &attrs, y, dpp);
1596 if (ret < 0)
1597 return ret;
1598
1599 RGWBucketEntryMetadataObject *mdo = new RGWBucketEntryMetadataObject(be, ot.read_version, mtime, std::move(attrs));
1600
1601 *obj = mdo;
1602
1603 return 0;
1604 }
1605
1606 int do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
1607 RGWMetadataObject *obj,
1608 RGWObjVersionTracker& objv_tracker,
1609 optional_yield y,
1610 const DoutPrefixProvider *dpp,
1611 RGWMDLogSyncType type, bool from_remote_zone) override;
1612
1613 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker,
1614 optional_yield y, const DoutPrefixProvider *dpp) override {
1615 RGWBucketEntryPoint be;
1616
1617 real_time orig_mtime;
1618
1619 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
1620
1621 int ret = svc.bucket->read_bucket_entrypoint_info(ctx, entry, &be, &objv_tracker, &orig_mtime, nullptr, y, dpp);
1622 if (ret < 0)
1623 return ret;
1624
1625 /*
1626 * We're unlinking the bucket but we don't want to update the entrypoint here - we're removing
1627 * it immediately and don't want to invalidate our cached objv_version or the bucket obj removal
1628 * will incorrectly fail.
1629 */
1630 ret = ctl.bucket->unlink_bucket(be.owner, be.bucket, y, dpp, false);
1631 if (ret < 0) {
1632 ldpp_dout(dpp, -1) << "could not unlink bucket=" << entry << " owner=" << be.owner << dendl;
1633 }
1634
1635 ret = svc.bucket->remove_bucket_entrypoint_info(ctx, entry, &objv_tracker, y, dpp);
1636 if (ret < 0) {
1637 ldpp_dout(dpp, -1) << "could not delete bucket=" << entry << dendl;
1638 }
1639 /* idempotent */
1640 return 0;
1641 }
1642
1643 int call(std::function<int(RGWSI_Bucket_EP_Ctx& ctx)> f) {
1644 return call(nullopt, f);
1645 }
1646
1647 int call(std::optional<RGWSI_MetaBackend_CtxParams> bectx_params,
1648 std::function<int(RGWSI_Bucket_EP_Ctx& ctx)> f) {
1649 return be_handler->call(bectx_params, [&](RGWSI_MetaBackend_Handler::Op *op) {
1650 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
1651 return f(ctx);
1652 });
1653 }
1654 };
1655
1656 class RGWMetadataHandlerPut_Bucket : public RGWMetadataHandlerPut_SObj
1657 {
1658 RGWBucketMetadataHandler *bhandler;
1659 RGWBucketEntryMetadataObject *obj;
1660 public:
1661 RGWMetadataHandlerPut_Bucket(RGWBucketMetadataHandler *_handler,
1662 RGWSI_MetaBackend_Handler::Op *op, string& entry,
1663 RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker,
1664 optional_yield y,
1665 RGWMDLogSyncType type, bool from_remote_zone) : RGWMetadataHandlerPut_SObj(_handler, op, entry, obj, objv_tracker, y, type, from_remote_zone),
1666 bhandler(_handler) {
1667 obj = static_cast<RGWBucketEntryMetadataObject *>(_obj);
1668 }
1669 ~RGWMetadataHandlerPut_Bucket() {}
1670
1671 void encode_obj(bufferlist *bl) override {
1672 obj->get_ep().encode(*bl);
1673 }
1674
1675 int put_checked(const DoutPrefixProvider *dpp) override;
1676 int put_post(const DoutPrefixProvider *dpp) override;
1677 };
1678
1679 int RGWBucketMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
1680 RGWMetadataObject *obj,
1681 RGWObjVersionTracker& objv_tracker,
1682 optional_yield y,
1683 const DoutPrefixProvider *dpp,
1684 RGWMDLogSyncType type, bool from_remote_zone)
1685 {
1686 RGWMetadataHandlerPut_Bucket put_op(this, op, entry, obj, objv_tracker, y, type, from_remote_zone);
1687 return do_put_operate(&put_op, dpp);
1688 }
1689
1690 int RGWMetadataHandlerPut_Bucket::put_checked(const DoutPrefixProvider *dpp)
1691 {
1692 RGWBucketEntryMetadataObject *orig_obj = static_cast<RGWBucketEntryMetadataObject *>(old_obj);
1693
1694 if (orig_obj) {
1695 obj->set_pattrs(&orig_obj->get_attrs());
1696 }
1697
1698 auto& be = obj->get_ep();
1699 auto mtime = obj->get_mtime();
1700 auto pattrs = obj->get_pattrs();
1701
1702 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
1703
1704 return bhandler->svc.bucket->store_bucket_entrypoint_info(ctx, entry,
1705 be,
1706 false,
1707 mtime,
1708 pattrs,
1709 &objv_tracker,
1710 y,
1711 dpp);
1712 }
1713
1714 int RGWMetadataHandlerPut_Bucket::put_post(const DoutPrefixProvider *dpp)
1715 {
1716 auto& be = obj->get_ep();
1717
1718 int ret;
1719
1720 /* link bucket */
1721 if (be.linked) {
1722 ret = bhandler->ctl.bucket->link_bucket(be.owner, be.bucket, be.creation_time, y, dpp, false);
1723 } else {
1724 ret = bhandler->ctl.bucket->unlink_bucket(be.owner, be.bucket, y, dpp, false);
1725 }
1726
1727 return ret;
1728 }
1729
1730 static void get_md5_digest(const RGWBucketEntryPoint *be, string& md5_digest) {
1731
1732 char md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
1733 unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE];
1734 bufferlist bl;
1735
1736 Formatter *f = new JSONFormatter(false);
1737 be->dump(f);
1738 f->flush(bl);
1739
1740 MD5 hash;
1741 // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes
1742 hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
1743 hash.Update((const unsigned char *)bl.c_str(), bl.length());
1744 hash.Final(m);
1745
1746 buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, md5);
1747
1748 delete f;
1749
1750 md5_digest = md5;
1751 }
1752
1753 #define ARCHIVE_META_ATTR RGW_ATTR_PREFIX "zone.archive.info"
1754
1755 struct archive_meta_info {
1756 rgw_bucket orig_bucket;
1757
1758 bool from_attrs(CephContext *cct, map<string, bufferlist>& attrs) {
1759 auto iter = attrs.find(ARCHIVE_META_ATTR);
1760 if (iter == attrs.end()) {
1761 return false;
1762 }
1763
1764 auto bliter = iter->second.cbegin();
1765 try {
1766 decode(bliter);
1767 } catch (buffer::error& err) {
1768 ldout(cct, 0) << "ERROR: failed to decode archive meta info" << dendl;
1769 return false;
1770 }
1771
1772 return true;
1773 }
1774
1775 void store_in_attrs(map<string, bufferlist>& attrs) const {
1776 encode(attrs[ARCHIVE_META_ATTR]);
1777 }
1778
1779 void encode(bufferlist& bl) const {
1780 ENCODE_START(1, 1, bl);
1781 encode(orig_bucket, bl);
1782 ENCODE_FINISH(bl);
1783 }
1784
1785 void decode(bufferlist::const_iterator& bl) {
1786 DECODE_START(1, bl);
1787 decode(orig_bucket, bl);
1788 DECODE_FINISH(bl);
1789 }
1790 };
1791 WRITE_CLASS_ENCODER(archive_meta_info)
1792
1793 class RGWArchiveBucketMetadataHandler : public RGWBucketMetadataHandler {
1794 public:
1795 RGWArchiveBucketMetadataHandler() {}
1796
1797 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker,
1798 optional_yield y, const DoutPrefixProvider *dpp) override {
1799 auto cct = svc.bucket->ctx();
1800
1801 RGWSI_Bucket_EP_Ctx ctx(op->ctx());
1802
1803 ldpp_dout(dpp, 5) << "SKIP: bucket removal is not allowed on archive zone: bucket:" << entry << " ... proceeding to rename" << dendl;
1804
1805 string tenant_name, bucket_name;
1806 parse_bucket(entry, &tenant_name, &bucket_name);
1807 rgw_bucket entry_bucket;
1808 entry_bucket.tenant = tenant_name;
1809 entry_bucket.name = bucket_name;
1810
1811 real_time mtime;
1812
1813 /* read original entrypoint */
1814
1815 RGWBucketEntryPoint be;
1816 map<string, bufferlist> attrs;
1817 int ret = svc.bucket->read_bucket_entrypoint_info(ctx, entry, &be, &objv_tracker, &mtime, &attrs, y, dpp);
1818 if (ret < 0) {
1819 return ret;
1820 }
1821
1822 string bi_meta_name = RGWSI_Bucket::get_bi_meta_key(be.bucket);
1823
1824 /* read original bucket instance info */
1825
1826 map<string, bufferlist> attrs_m;
1827 ceph::real_time orig_mtime;
1828 RGWBucketInfo old_bi;
1829
1830 ret = ctl.bucket->read_bucket_instance_info(be.bucket, &old_bi, y, dpp, RGWBucketCtl::BucketInstance::GetParams()
1831 .set_mtime(&orig_mtime)
1832 .set_attrs(&attrs_m));
1833 if (ret < 0) {
1834 return ret;
1835 }
1836
1837 archive_meta_info ami;
1838
1839 if (!ami.from_attrs(svc.bucket->ctx(), attrs_m)) {
1840 ami.orig_bucket = old_bi.bucket;
1841 ami.store_in_attrs(attrs_m);
1842 }
1843
1844 /* generate a new bucket instance. We could have avoided this if we could just point a new
1845 * bucket entry point to the old bucket instance, however, due to limitation in the way
1846 * we index buckets under the user, bucket entrypoint and bucket instance of the same
1847 * bucket need to have the same name, so we need to copy the old bucket instance into
1848 * to a new entry with the new name
1849 */
1850
1851 string new_bucket_name;
1852
1853 RGWBucketInfo new_bi = old_bi;
1854 RGWBucketEntryPoint new_be = be;
1855
1856 string md5_digest;
1857
1858 get_md5_digest(&new_be, md5_digest);
1859 new_bucket_name = ami.orig_bucket.name + "-deleted-" + md5_digest;
1860
1861 new_bi.bucket.name = new_bucket_name;
1862 new_bi.objv_tracker.clear();
1863
1864 new_be.bucket.name = new_bucket_name;
1865
1866 ret = ctl.bucket->store_bucket_instance_info(be.bucket, new_bi, y, dpp, RGWBucketCtl::BucketInstance::PutParams()
1867 .set_exclusive(false)
1868 .set_mtime(orig_mtime)
1869 .set_attrs(&attrs_m)
1870 .set_orig_info(&old_bi));
1871 if (ret < 0) {
1872 ldpp_dout(dpp, 0) << "ERROR: failed to put new bucket instance info for bucket=" << new_bi.bucket << " ret=" << ret << dendl;
1873 return ret;
1874 }
1875
1876 /* store a new entrypoint */
1877
1878 RGWObjVersionTracker ot;
1879 ot.generate_new_write_ver(cct);
1880
1881 ret = svc.bucket->store_bucket_entrypoint_info(ctx, RGWSI_Bucket::get_entrypoint_meta_key(new_be.bucket),
1882 new_be, true, mtime, &attrs, nullptr, y, dpp);
1883 if (ret < 0) {
1884 ldpp_dout(dpp, 0) << "ERROR: failed to put new bucket entrypoint for bucket=" << new_be.bucket << " ret=" << ret << dendl;
1885 return ret;
1886 }
1887
1888 /* link new bucket */
1889
1890 ret = ctl.bucket->link_bucket(new_be.owner, new_be.bucket, new_be.creation_time, y, dpp, false);
1891 if (ret < 0) {
1892 ldpp_dout(dpp, 0) << "ERROR: failed to link new bucket for bucket=" << new_be.bucket << " ret=" << ret << dendl;
1893 return ret;
1894 }
1895
1896 /* clean up old stuff */
1897
1898 ret = ctl.bucket->unlink_bucket(be.owner, entry_bucket, y, dpp, false);
1899 if (ret < 0) {
1900 ldpp_dout(dpp, -1) << "could not unlink bucket=" << entry << " owner=" << be.owner << dendl;
1901 }
1902
1903 // if (ret == -ECANCELED) it means that there was a race here, and someone
1904 // wrote to the bucket entrypoint just before we removed it. The question is
1905 // whether it was a newly created bucket entrypoint ... in which case we
1906 // should ignore the error and move forward, or whether it is a higher version
1907 // of the same bucket instance ... in which we should retry
1908 ret = svc.bucket->remove_bucket_entrypoint_info(ctx,
1909 RGWSI_Bucket::get_entrypoint_meta_key(be.bucket),
1910 &objv_tracker,
1911 y,
1912 dpp);
1913 if (ret < 0) {
1914 ldpp_dout(dpp, 0) << "ERROR: failed to put new bucket entrypoint for bucket=" << new_be.bucket << " ret=" << ret << dendl;
1915 return ret;
1916 }
1917
1918 ret = ctl.bucket->remove_bucket_instance_info(be.bucket, old_bi, y, dpp);
1919 if (ret < 0) {
1920 ldpp_dout(dpp, -1) << "could not delete bucket=" << entry << dendl;
1921 }
1922
1923
1924 /* idempotent */
1925
1926 return 0;
1927 }
1928
1929 int do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
1930 RGWMetadataObject *obj,
1931 RGWObjVersionTracker& objv_tracker,
1932 optional_yield y, const DoutPrefixProvider *dpp,
1933 RGWMDLogSyncType type, bool from_remote_zone) override {
1934 if (entry.find("-deleted-") != string::npos) {
1935 RGWObjVersionTracker ot;
1936 RGWMetadataObject *robj;
1937 int ret = do_get(op, entry, &robj, y, dpp);
1938 if (ret != -ENOENT) {
1939 if (ret < 0) {
1940 return ret;
1941 }
1942 ot.read_version = robj->get_version();
1943 delete robj;
1944
1945 ret = do_remove(op, entry, ot, y, dpp);
1946 if (ret < 0) {
1947 return ret;
1948 }
1949 }
1950 }
1951
1952 return RGWBucketMetadataHandler::do_put(op, entry, obj,
1953 objv_tracker, y, dpp, type, from_remote_zone);
1954 }
1955
1956 };
1957
1958 class RGWBucketInstanceMetadataHandler : public RGWBucketInstanceMetadataHandlerBase {
1959 int read_bucket_instance_entry(RGWSI_Bucket_BI_Ctx& ctx,
1960 const string& entry,
1961 RGWBucketCompleteInfo *bi,
1962 ceph::real_time *pmtime,
1963 optional_yield y,
1964 const DoutPrefixProvider *dpp) {
1965 return svc.bucket->read_bucket_instance_info(ctx,
1966 entry,
1967 &bi->info,
1968 pmtime, &bi->attrs,
1969 y,
1970 dpp);
1971 }
1972
1973 public:
1974 struct Svc {
1975 RGWSI_Zone *zone{nullptr};
1976 RGWSI_Bucket *bucket{nullptr};
1977 RGWSI_BucketIndex *bi{nullptr};
1978 } svc;
1979
1980 rgw::sal::Driver* driver;
1981
1982 RGWBucketInstanceMetadataHandler(rgw::sal::Driver* driver)
1983 : driver(driver) {}
1984
1985 void init(RGWSI_Zone *zone_svc,
1986 RGWSI_Bucket *bucket_svc,
1987 RGWSI_BucketIndex *bi_svc) override {
1988 base_init(bucket_svc->ctx(),
1989 bucket_svc->get_bi_be_handler().get());
1990 svc.zone = zone_svc;
1991 svc.bucket = bucket_svc;
1992 svc.bi = bi_svc;
1993 }
1994
1995 string get_type() override { return "bucket.instance"; }
1996
1997 RGWMetadataObject *get_meta_obj(JSONObj *jo, const obj_version& objv, const ceph::real_time& mtime) override {
1998 RGWBucketCompleteInfo bci;
1999
2000 try {
2001 decode_json_obj(bci, jo);
2002 } catch (JSONDecoder::err& e) {
2003 return nullptr;
2004 }
2005
2006 return new RGWBucketInstanceMetadataObject(bci, objv, mtime);
2007 }
2008
2009 int do_get(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWMetadataObject **obj, optional_yield y, const DoutPrefixProvider *dpp) override {
2010 RGWBucketCompleteInfo bci;
2011 real_time mtime;
2012
2013 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
2014
2015 int ret = svc.bucket->read_bucket_instance_info(ctx, entry, &bci.info, &mtime, &bci.attrs, y, dpp);
2016 if (ret < 0)
2017 return ret;
2018
2019 RGWBucketInstanceMetadataObject *mdo = new RGWBucketInstanceMetadataObject(bci, bci.info.objv_tracker.read_version, mtime);
2020
2021 *obj = mdo;
2022
2023 return 0;
2024 }
2025
2026 int do_put(RGWSI_MetaBackend_Handler::Op *op, string& entry,
2027 RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker,
2028 optional_yield y, const DoutPrefixProvider *dpp,
2029 RGWMDLogSyncType sync_type, bool from_remote_zone) override;
2030
2031 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker,
2032 optional_yield y, const DoutPrefixProvider *dpp) override {
2033 RGWBucketCompleteInfo bci;
2034
2035 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
2036
2037 int ret = read_bucket_instance_entry(ctx, entry, &bci, nullptr, y, dpp);
2038 if (ret < 0 && ret != -ENOENT)
2039 return ret;
2040
2041 return svc.bucket->remove_bucket_instance_info(ctx, entry, bci.info, &bci.info.objv_tracker, y, dpp);
2042 }
2043
2044 int call(std::function<int(RGWSI_Bucket_BI_Ctx& ctx)> f) {
2045 return call(nullopt, f);
2046 }
2047
2048 int call(std::optional<RGWSI_MetaBackend_CtxParams> bectx_params,
2049 std::function<int(RGWSI_Bucket_BI_Ctx& ctx)> f) {
2050 return be_handler->call(bectx_params, [&](RGWSI_MetaBackend_Handler::Op *op) {
2051 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
2052 return f(ctx);
2053 });
2054 }
2055 };
2056
2057 class RGWMetadataHandlerPut_BucketInstance : public RGWMetadataHandlerPut_SObj
2058 {
2059 CephContext *cct;
2060 RGWBucketInstanceMetadataHandler *bihandler;
2061 RGWBucketInstanceMetadataObject *obj;
2062 public:
2063 RGWMetadataHandlerPut_BucketInstance(CephContext *_cct,
2064 RGWBucketInstanceMetadataHandler *_handler,
2065 RGWSI_MetaBackend_Handler::Op *_op, string& entry,
2066 RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker,
2067 optional_yield y,
2068 RGWMDLogSyncType type, bool from_remote_zone) : RGWMetadataHandlerPut_SObj(_handler, _op, entry, _obj, objv_tracker, y, type, from_remote_zone),
2069 cct(_cct), bihandler(_handler) {
2070 obj = static_cast<RGWBucketInstanceMetadataObject *>(_obj);
2071
2072 auto& bci = obj->get_bci();
2073 obj->set_pattrs(&bci.attrs);
2074 }
2075
2076 void encode_obj(bufferlist *bl) override {
2077 obj->get_bucket_info().encode(*bl);
2078 }
2079
2080 int put_check(const DoutPrefixProvider *dpp) override;
2081 int put_checked(const DoutPrefixProvider *dpp) override;
2082 int put_post(const DoutPrefixProvider *dpp) override;
2083 };
2084
2085 int RGWBucketInstanceMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op *op,
2086 string& entry,
2087 RGWMetadataObject *obj,
2088 RGWObjVersionTracker& objv_tracker,
2089 optional_yield y,
2090 const DoutPrefixProvider *dpp,
2091 RGWMDLogSyncType type, bool from_remote_zone)
2092 {
2093 RGWMetadataHandlerPut_BucketInstance put_op(svc.bucket->ctx(), this, op, entry, obj,
2094 objv_tracker, y, type, from_remote_zone);
2095 return do_put_operate(&put_op, dpp);
2096 }
2097
2098 void init_default_bucket_layout(CephContext *cct, rgw::BucketLayout& layout,
2099 const RGWZone& zone,
2100 std::optional<uint32_t> shards,
2101 std::optional<rgw::BucketIndexType> type) {
2102 layout.current_index.gen = 0;
2103 layout.current_index.layout.normal.hash_type = rgw::BucketHashType::Mod;
2104
2105 layout.current_index.layout.type =
2106 type.value_or(rgw::BucketIndexType::Normal);
2107
2108 if (shards) {
2109 layout.current_index.layout.normal.num_shards = *shards;
2110 } else if (cct->_conf->rgw_override_bucket_index_max_shards > 0) {
2111 layout.current_index.layout.normal.num_shards =
2112 cct->_conf->rgw_override_bucket_index_max_shards;
2113 } else {
2114 layout.current_index.layout.normal.num_shards =
2115 zone.bucket_index_max_shards;
2116 }
2117
2118 if (layout.current_index.layout.type == rgw::BucketIndexType::Normal) {
2119 layout.logs.push_back(log_layout_from_index(0, layout.current_index));
2120 }
2121 }
2122
2123 int RGWMetadataHandlerPut_BucketInstance::put_check(const DoutPrefixProvider *dpp)
2124 {
2125 int ret;
2126
2127 RGWBucketCompleteInfo& bci = obj->get_bci();
2128
2129 RGWBucketInstanceMetadataObject *orig_obj = static_cast<RGWBucketInstanceMetadataObject *>(old_obj);
2130
2131 RGWBucketCompleteInfo *old_bci = (orig_obj ? &orig_obj->get_bci() : nullptr);
2132
2133 const bool exists = (!!orig_obj);
2134
2135 if (from_remote_zone) {
2136 // don't sync bucket layout changes
2137 if (!exists) {
2138 // replace peer's layout with default-constructed, then apply our defaults
2139 bci.info.layout = rgw::BucketLayout{};
2140 init_default_bucket_layout(cct, bci.info.layout,
2141 bihandler->svc.zone->get_zone(),
2142 std::nullopt, std::nullopt);
2143 } else {
2144 bci.info.layout = old_bci->info.layout;
2145 }
2146 }
2147
2148 if (!exists || old_bci->info.bucket.bucket_id != bci.info.bucket.bucket_id) {
2149 /* a new bucket, we need to select a new bucket placement for it */
2150 string tenant_name;
2151 string bucket_name;
2152 string bucket_instance;
2153 parse_bucket(entry, &tenant_name, &bucket_name, &bucket_instance);
2154
2155 RGWZonePlacementInfo rule_info;
2156 bci.info.bucket.name = bucket_name;
2157 bci.info.bucket.bucket_id = bucket_instance;
2158 bci.info.bucket.tenant = tenant_name;
2159 // if the sync module never writes data, don't require the zone to specify all placement targets
2160 if (bihandler->svc.zone->sync_module_supports_writes()) {
2161 ret = bihandler->svc.zone->select_bucket_location_by_rule(dpp, bci.info.placement_rule, &rule_info, y);
2162 if (ret < 0) {
2163 ldpp_dout(dpp, 0) << "ERROR: select_bucket_placement() returned " << ret << dendl;
2164 return ret;
2165 }
2166 }
2167 bci.info.layout.current_index.layout.type = rule_info.index_type;
2168 } else {
2169 /* always keep bucket versioning enabled on archive zone */
2170 if (bihandler->driver->get_zone()->get_tier_type() == "archive") {
2171 bci.info.flags = (bci.info.flags & ~BUCKET_VERSIONS_SUSPENDED) | BUCKET_VERSIONED;
2172 }
2173 /* existing bucket, keep its placement */
2174 bci.info.bucket.explicit_placement = old_bci->info.bucket.explicit_placement;
2175 bci.info.placement_rule = old_bci->info.placement_rule;
2176 }
2177
2178 /* record the read version (if any), store the new version */
2179 bci.info.objv_tracker.read_version = objv_tracker.read_version;
2180 bci.info.objv_tracker.write_version = objv_tracker.write_version;
2181
2182 return 0;
2183 }
2184
2185 int RGWMetadataHandlerPut_BucketInstance::put_checked(const DoutPrefixProvider *dpp)
2186 {
2187 RGWBucketInstanceMetadataObject *orig_obj = static_cast<RGWBucketInstanceMetadataObject *>(old_obj);
2188
2189 RGWBucketInfo *orig_info = (orig_obj ? &orig_obj->get_bucket_info() : nullptr);
2190
2191 auto& info = obj->get_bucket_info();
2192 auto mtime = obj->get_mtime();
2193 auto pattrs = obj->get_pattrs();
2194
2195 RGWSI_Bucket_BI_Ctx ctx(op->ctx());
2196
2197 return bihandler->svc.bucket->store_bucket_instance_info(ctx,
2198 entry,
2199 info,
2200 orig_info,
2201 false,
2202 mtime,
2203 pattrs,
2204 y,
2205 dpp);
2206 }
2207
2208 int RGWMetadataHandlerPut_BucketInstance::put_post(const DoutPrefixProvider *dpp)
2209 {
2210 RGWBucketCompleteInfo& bci = obj->get_bci();
2211
2212 objv_tracker = bci.info.objv_tracker;
2213
2214 int ret = bihandler->svc.bi->init_index(dpp, bci.info, bci.info.layout.current_index);
2215 if (ret < 0) {
2216 return ret;
2217 }
2218
2219 /* update lifecyle policy */
2220 {
2221 std::unique_ptr<rgw::sal::Bucket> bucket;
2222 ret = bihandler->driver->get_bucket(nullptr, bci.info, &bucket);
2223 if (ret < 0) {
2224 ldpp_dout(dpp, 0) << __func__ << " failed to get_bucket(...) for "
2225 << bci.info.bucket.name
2226 << dendl;
2227 return ret;
2228 }
2229
2230 auto lc = bihandler->driver->get_rgwlc();
2231
2232 auto lc_it = bci.attrs.find(RGW_ATTR_LC);
2233 if (lc_it != bci.attrs.end()) {
2234 ldpp_dout(dpp, 20) << "set lc config for " << bci.info.bucket.name << dendl;
2235 ret = lc->set_bucket_config(bucket.get(), bci.attrs, nullptr);
2236 if (ret < 0) {
2237 ldpp_dout(dpp, 0) << __func__ << " failed to set lc config for "
2238 << bci.info.bucket.name
2239 << dendl;
2240 return ret;
2241 }
2242
2243 } else {
2244 ldpp_dout(dpp, 20) << "remove lc config for " << bci.info.bucket.name << dendl;
2245 ret = lc->remove_bucket_config(bucket.get(), bci.attrs, false /* cannot merge attrs */);
2246 if (ret < 0) {
2247 ldpp_dout(dpp, 0) << __func__ << " failed to remove lc config for "
2248 << bci.info.bucket.name
2249 << dendl;
2250 return ret;
2251 }
2252 }
2253 } /* update lc */
2254
2255 return STATUS_APPLIED;
2256 }
2257
2258 class RGWArchiveBucketInstanceMetadataHandler : public RGWBucketInstanceMetadataHandler {
2259 public:
2260 RGWArchiveBucketInstanceMetadataHandler(rgw::sal::Driver* driver)
2261 : RGWBucketInstanceMetadataHandler(driver) {}
2262
2263 // N.B. replication of lifecycle policy relies on logic in RGWBucketInstanceMetadataHandler::do_put(...), override with caution
2264
2265 int do_remove(RGWSI_MetaBackend_Handler::Op *op, string& entry, RGWObjVersionTracker& objv_tracker, optional_yield y, const DoutPrefixProvider *dpp) override {
2266 ldpp_dout(dpp, 0) << "SKIP: bucket instance removal is not allowed on archive zone: bucket.instance:" << entry << dendl;
2267 return 0;
2268 }
2269 };
2270
2271 RGWBucketCtl::RGWBucketCtl(RGWSI_Zone *zone_svc,
2272 RGWSI_Bucket *bucket_svc,
2273 RGWSI_Bucket_Sync *bucket_sync_svc,
2274 RGWSI_BucketIndex *bi_svc,
2275 RGWSI_User* user_svc)
2276 : cct(zone_svc->ctx())
2277 {
2278 svc.zone = zone_svc;
2279 svc.bucket = bucket_svc;
2280 svc.bucket_sync = bucket_sync_svc;
2281 svc.bi = bi_svc;
2282 svc.user = user_svc;
2283 }
2284
2285 void RGWBucketCtl::init(RGWUserCtl *user_ctl,
2286 RGWBucketMetadataHandler *_bm_handler,
2287 RGWBucketInstanceMetadataHandler *_bmi_handler,
2288 RGWDataChangesLog *datalog,
2289 const DoutPrefixProvider *dpp)
2290 {
2291 ctl.user = user_ctl;
2292
2293 bm_handler = _bm_handler;
2294 bmi_handler = _bmi_handler;
2295
2296 bucket_be_handler = bm_handler->get_be_handler();
2297 bi_be_handler = bmi_handler->get_be_handler();
2298
2299 datalog->set_bucket_filter(
2300 [this](const rgw_bucket& bucket, optional_yield y, const DoutPrefixProvider *dpp) {
2301 return bucket_exports_data(bucket, y, dpp);
2302 });
2303 }
2304
2305 int RGWBucketCtl::call(std::function<int(RGWSI_Bucket_X_Ctx& ctx)> f) {
2306 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ep_ctx) {
2307 return bmi_handler->call([&](RGWSI_Bucket_BI_Ctx& bi_ctx) {
2308 RGWSI_Bucket_X_Ctx ctx{ep_ctx, bi_ctx};
2309 return f(ctx);
2310 });
2311 });
2312 }
2313
2314 int RGWBucketCtl::read_bucket_entrypoint_info(const rgw_bucket& bucket,
2315 RGWBucketEntryPoint *info,
2316 optional_yield y, const DoutPrefixProvider *dpp,
2317 const Bucket::GetParams& params)
2318 {
2319 return bm_handler->call(params.bectx_params, [&](RGWSI_Bucket_EP_Ctx& ctx) {
2320 return svc.bucket->read_bucket_entrypoint_info(ctx,
2321 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
2322 info,
2323 params.objv_tracker,
2324 params.mtime,
2325 params.attrs,
2326 y,
2327 dpp,
2328 params.cache_info,
2329 params.refresh_version);
2330 });
2331 }
2332
2333 int RGWBucketCtl::store_bucket_entrypoint_info(const rgw_bucket& bucket,
2334 RGWBucketEntryPoint& info,
2335 optional_yield y,
2336 const DoutPrefixProvider *dpp,
2337 const Bucket::PutParams& params)
2338 {
2339 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
2340 return svc.bucket->store_bucket_entrypoint_info(ctx,
2341 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
2342 info,
2343 params.exclusive,
2344 params.mtime,
2345 params.attrs,
2346 params.objv_tracker,
2347 y,
2348 dpp);
2349 });
2350 }
2351
2352 int RGWBucketCtl::remove_bucket_entrypoint_info(const rgw_bucket& bucket,
2353 optional_yield y,
2354 const DoutPrefixProvider *dpp,
2355 const Bucket::RemoveParams& params)
2356 {
2357 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
2358 return svc.bucket->remove_bucket_entrypoint_info(ctx,
2359 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
2360 params.objv_tracker,
2361 y,
2362 dpp);
2363 });
2364 }
2365
2366 int RGWBucketCtl::read_bucket_instance_info(const rgw_bucket& bucket,
2367 RGWBucketInfo *info,
2368 optional_yield y,
2369 const DoutPrefixProvider *dpp,
2370 const BucketInstance::GetParams& params)
2371 {
2372 int ret = bmi_handler->call(params.bectx_params, [&](RGWSI_Bucket_BI_Ctx& ctx) {
2373 return svc.bucket->read_bucket_instance_info(ctx,
2374 RGWSI_Bucket::get_bi_meta_key(bucket),
2375 info,
2376 params.mtime,
2377 params.attrs,
2378 y,
2379 dpp,
2380 params.cache_info,
2381 params.refresh_version);
2382 });
2383
2384 if (ret < 0) {
2385 return ret;
2386 }
2387
2388 if (params.objv_tracker) {
2389 *params.objv_tracker = info->objv_tracker;
2390 }
2391
2392 return 0;
2393 }
2394
2395 int RGWBucketCtl::read_bucket_info(const rgw_bucket& bucket,
2396 RGWBucketInfo *info,
2397 optional_yield y,
2398 const DoutPrefixProvider *dpp,
2399 const BucketInstance::GetParams& params,
2400 RGWObjVersionTracker *ep_objv_tracker)
2401 {
2402 const rgw_bucket *b = &bucket;
2403
2404 std::optional<RGWBucketEntryPoint> ep;
2405
2406 if (b->bucket_id.empty()) {
2407 ep.emplace();
2408
2409 int r = read_bucket_entrypoint_info(*b, &(*ep), y, dpp, RGWBucketCtl::Bucket::GetParams()
2410 .set_bectx_params(params.bectx_params)
2411 .set_objv_tracker(ep_objv_tracker));
2412 if (r < 0) {
2413 return r;
2414 }
2415
2416 b = &ep->bucket;
2417 }
2418
2419 int ret = bmi_handler->call(params.bectx_params, [&](RGWSI_Bucket_BI_Ctx& ctx) {
2420 return svc.bucket->read_bucket_instance_info(ctx,
2421 RGWSI_Bucket::get_bi_meta_key(*b),
2422 info,
2423 params.mtime,
2424 params.attrs,
2425 y, dpp,
2426 params.cache_info,
2427 params.refresh_version);
2428 });
2429
2430 if (ret < 0) {
2431 return ret;
2432 }
2433
2434 if (params.objv_tracker) {
2435 *params.objv_tracker = info->objv_tracker;
2436 }
2437
2438 return 0;
2439 }
2440
2441 int RGWBucketCtl::do_store_bucket_instance_info(RGWSI_Bucket_BI_Ctx& ctx,
2442 const rgw_bucket& bucket,
2443 RGWBucketInfo& info,
2444 optional_yield y,
2445 const DoutPrefixProvider *dpp,
2446 const BucketInstance::PutParams& params)
2447 {
2448 if (params.objv_tracker) {
2449 info.objv_tracker = *params.objv_tracker;
2450 }
2451
2452 return svc.bucket->store_bucket_instance_info(ctx,
2453 RGWSI_Bucket::get_bi_meta_key(bucket),
2454 info,
2455 params.orig_info,
2456 params.exclusive,
2457 params.mtime,
2458 params.attrs,
2459 y,
2460 dpp);
2461 }
2462
2463 int RGWBucketCtl::store_bucket_instance_info(const rgw_bucket& bucket,
2464 RGWBucketInfo& info,
2465 optional_yield y,
2466 const DoutPrefixProvider *dpp,
2467 const BucketInstance::PutParams& params)
2468 {
2469 return bmi_handler->call([&](RGWSI_Bucket_BI_Ctx& ctx) {
2470 return do_store_bucket_instance_info(ctx, bucket, info, y, dpp, params);
2471 });
2472 }
2473
2474 int RGWBucketCtl::remove_bucket_instance_info(const rgw_bucket& bucket,
2475 RGWBucketInfo& info,
2476 optional_yield y,
2477 const DoutPrefixProvider *dpp,
2478 const BucketInstance::RemoveParams& params)
2479 {
2480 if (params.objv_tracker) {
2481 info.objv_tracker = *params.objv_tracker;
2482 }
2483
2484 return bmi_handler->call([&](RGWSI_Bucket_BI_Ctx& ctx) {
2485 return svc.bucket->remove_bucket_instance_info(ctx,
2486 RGWSI_Bucket::get_bi_meta_key(bucket),
2487 info,
2488 &info.objv_tracker,
2489 y,
2490 dpp);
2491 });
2492 }
2493
2494 int RGWBucketCtl::do_store_linked_bucket_info(RGWSI_Bucket_X_Ctx& ctx,
2495 RGWBucketInfo& info,
2496 RGWBucketInfo *orig_info,
2497 bool exclusive, real_time mtime,
2498 obj_version *pep_objv,
2499 map<string, bufferlist> *pattrs,
2500 bool create_entry_point,
2501 optional_yield y, const DoutPrefixProvider *dpp)
2502 {
2503 bool create_head = !info.has_instance_obj || create_entry_point;
2504
2505 int ret = svc.bucket->store_bucket_instance_info(ctx.bi,
2506 RGWSI_Bucket::get_bi_meta_key(info.bucket),
2507 info,
2508 orig_info,
2509 exclusive,
2510 mtime, pattrs,
2511 y, dpp);
2512 if (ret < 0) {
2513 return ret;
2514 }
2515
2516 if (!create_head)
2517 return 0; /* done! */
2518
2519 RGWBucketEntryPoint entry_point;
2520 entry_point.bucket = info.bucket;
2521 entry_point.owner = info.owner;
2522 entry_point.creation_time = info.creation_time;
2523 entry_point.linked = true;
2524 RGWObjVersionTracker ot;
2525 if (pep_objv && !pep_objv->tag.empty()) {
2526 ot.write_version = *pep_objv;
2527 } else {
2528 ot.generate_new_write_ver(cct);
2529 if (pep_objv) {
2530 *pep_objv = ot.write_version;
2531 }
2532 }
2533 ret = svc.bucket->store_bucket_entrypoint_info(ctx.ep,
2534 RGWSI_Bucket::get_entrypoint_meta_key(info.bucket),
2535 entry_point,
2536 exclusive,
2537 mtime,
2538 pattrs,
2539 &ot,
2540 y,
2541 dpp);
2542 if (ret < 0)
2543 return ret;
2544
2545 return 0;
2546 }
2547 int RGWBucketCtl::convert_old_bucket_info(RGWSI_Bucket_X_Ctx& ctx,
2548 const rgw_bucket& bucket,
2549 optional_yield y,
2550 const DoutPrefixProvider *dpp)
2551 {
2552 RGWBucketEntryPoint entry_point;
2553 real_time ep_mtime;
2554 RGWObjVersionTracker ot;
2555 map<string, bufferlist> attrs;
2556 RGWBucketInfo info;
2557 auto cct = svc.bucket->ctx();
2558
2559 ldpp_dout(dpp, 10) << "RGWRados::convert_old_bucket_info(): bucket=" << bucket << dendl;
2560
2561 int ret = svc.bucket->read_bucket_entrypoint_info(ctx.ep,
2562 RGWSI_Bucket::get_entrypoint_meta_key(bucket),
2563 &entry_point, &ot, &ep_mtime, &attrs, y, dpp);
2564 if (ret < 0) {
2565 ldpp_dout(dpp, 0) << "ERROR: get_bucket_entrypoint_info() returned " << ret << " bucket=" << bucket << dendl;
2566 return ret;
2567 }
2568
2569 if (!entry_point.has_bucket_info) {
2570 /* already converted! */
2571 return 0;
2572 }
2573
2574 info = entry_point.old_bucket_info;
2575
2576 ot.generate_new_write_ver(cct);
2577
2578 ret = do_store_linked_bucket_info(ctx, info, nullptr, false, ep_mtime, &ot.write_version, &attrs, true, y, dpp);
2579 if (ret < 0) {
2580 ldpp_dout(dpp, 0) << "ERROR: failed to put_linked_bucket_info(): " << ret << dendl;
2581 return ret;
2582 }
2583
2584 return 0;
2585 }
2586
2587 int RGWBucketCtl::set_bucket_instance_attrs(RGWBucketInfo& bucket_info,
2588 map<string, bufferlist>& attrs,
2589 RGWObjVersionTracker *objv_tracker,
2590 optional_yield y,
2591 const DoutPrefixProvider *dpp)
2592 {
2593 return call([&](RGWSI_Bucket_X_Ctx& ctx) {
2594 rgw_bucket& bucket = bucket_info.bucket;
2595
2596 if (!bucket_info.has_instance_obj) {
2597 /* an old bucket object, need to convert it */
2598 int ret = convert_old_bucket_info(ctx, bucket, y, dpp);
2599 if (ret < 0) {
2600 ldpp_dout(dpp, 0) << "ERROR: failed converting old bucket info: " << ret << dendl;
2601 return ret;
2602 }
2603 }
2604
2605 return do_store_bucket_instance_info(ctx.bi,
2606 bucket,
2607 bucket_info,
2608 y,
2609 dpp,
2610 BucketInstance::PutParams().set_attrs(&attrs)
2611 .set_objv_tracker(objv_tracker)
2612 .set_orig_info(&bucket_info));
2613 });
2614 }
2615
2616
2617 int RGWBucketCtl::link_bucket(const rgw_user& user_id,
2618 const rgw_bucket& bucket,
2619 ceph::real_time creation_time,
2620 optional_yield y,
2621 const DoutPrefixProvider *dpp,
2622 bool update_entrypoint,
2623 rgw_ep_info *pinfo)
2624 {
2625 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
2626 return do_link_bucket(ctx, user_id, bucket, creation_time,
2627 update_entrypoint, pinfo, y, dpp);
2628 });
2629 }
2630
2631 int RGWBucketCtl::do_link_bucket(RGWSI_Bucket_EP_Ctx& ctx,
2632 const rgw_user& user_id,
2633 const rgw_bucket& bucket,
2634 ceph::real_time creation_time,
2635 bool update_entrypoint,
2636 rgw_ep_info *pinfo,
2637 optional_yield y,
2638 const DoutPrefixProvider *dpp)
2639 {
2640 int ret;
2641
2642 RGWBucketEntryPoint ep;
2643 RGWObjVersionTracker ot;
2644 RGWObjVersionTracker& rot = (pinfo) ? pinfo->ep_objv : ot;
2645 map<string, bufferlist> attrs, *pattrs = nullptr;
2646 string meta_key;
2647
2648 if (update_entrypoint) {
2649 meta_key = RGWSI_Bucket::get_entrypoint_meta_key(bucket);
2650 if (pinfo) {
2651 ep = pinfo->ep;
2652 pattrs = &pinfo->attrs;
2653 } else {
2654 ret = svc.bucket->read_bucket_entrypoint_info(ctx,
2655 meta_key,
2656 &ep, &rot,
2657 nullptr, &attrs,
2658 y, dpp);
2659 if (ret < 0 && ret != -ENOENT) {
2660 ldpp_dout(dpp, 0) << "ERROR: read_bucket_entrypoint_info() returned: "
2661 << cpp_strerror(-ret) << dendl;
2662 }
2663 pattrs = &attrs;
2664 }
2665 }
2666
2667 ret = svc.user->add_bucket(dpp, user_id, bucket, creation_time, y);
2668 if (ret < 0) {
2669 ldpp_dout(dpp, 0) << "ERROR: error adding bucket to user directory:"
2670 << " user=" << user_id
2671 << " bucket=" << bucket
2672 << " err=" << cpp_strerror(-ret)
2673 << dendl;
2674 goto done_err;
2675 }
2676
2677 if (!update_entrypoint)
2678 return 0;
2679
2680 ep.linked = true;
2681 ep.owner = user_id;
2682 ep.bucket = bucket;
2683 ret = svc.bucket->store_bucket_entrypoint_info(
2684 ctx, meta_key, ep, false, real_time(), pattrs, &rot, y, dpp);
2685 if (ret < 0)
2686 goto done_err;
2687
2688 return 0;
2689
2690 done_err:
2691 int r = do_unlink_bucket(ctx, user_id, bucket, true, y, dpp);
2692 if (r < 0) {
2693 ldpp_dout(dpp, 0) << "ERROR: failed unlinking bucket on error cleanup: "
2694 << cpp_strerror(-r) << dendl;
2695 }
2696 return ret;
2697 }
2698
2699 int RGWBucketCtl::unlink_bucket(const rgw_user& user_id, const rgw_bucket& bucket, optional_yield y, const DoutPrefixProvider *dpp, bool update_entrypoint)
2700 {
2701 return bm_handler->call([&](RGWSI_Bucket_EP_Ctx& ctx) {
2702 return do_unlink_bucket(ctx, user_id, bucket, update_entrypoint, y, dpp);
2703 });
2704 }
2705
2706 int RGWBucketCtl::do_unlink_bucket(RGWSI_Bucket_EP_Ctx& ctx,
2707 const rgw_user& user_id,
2708 const rgw_bucket& bucket,
2709 bool update_entrypoint,
2710 optional_yield y,
2711 const DoutPrefixProvider *dpp)
2712 {
2713 int ret = svc.user->remove_bucket(dpp, user_id, bucket, y);
2714 if (ret < 0) {
2715 ldpp_dout(dpp, 0) << "ERROR: error removing bucket from directory: "
2716 << cpp_strerror(-ret)<< dendl;
2717 }
2718
2719 if (!update_entrypoint)
2720 return 0;
2721
2722 RGWBucketEntryPoint ep;
2723 RGWObjVersionTracker ot;
2724 map<string, bufferlist> attrs;
2725 string meta_key = RGWSI_Bucket::get_entrypoint_meta_key(bucket);
2726 ret = svc.bucket->read_bucket_entrypoint_info(ctx, meta_key, &ep, &ot, nullptr, &attrs, y, dpp);
2727 if (ret == -ENOENT)
2728 return 0;
2729 if (ret < 0)
2730 return ret;
2731
2732 if (!ep.linked)
2733 return 0;
2734
2735 if (ep.owner != user_id) {
2736 ldpp_dout(dpp, 0) << "bucket entry point user mismatch, can't unlink bucket: " << ep.owner << " != " << user_id << dendl;
2737 return -EINVAL;
2738 }
2739
2740 ep.linked = false;
2741 return svc.bucket->store_bucket_entrypoint_info(ctx, meta_key, ep, false, real_time(), &attrs, &ot, y, dpp);
2742 }
2743
2744 int RGWBucketCtl::read_bucket_stats(const rgw_bucket& bucket,
2745 RGWBucketEnt *result,
2746 optional_yield y,
2747 const DoutPrefixProvider *dpp)
2748 {
2749 return call([&](RGWSI_Bucket_X_Ctx& ctx) {
2750 return svc.bucket->read_bucket_stats(ctx, bucket, result, y, dpp);
2751 });
2752 }
2753
2754 int RGWBucketCtl::read_buckets_stats(map<string, RGWBucketEnt>& m,
2755 optional_yield y, const DoutPrefixProvider *dpp)
2756 {
2757 return call([&](RGWSI_Bucket_X_Ctx& ctx) {
2758 return svc.bucket->read_buckets_stats(ctx, m, y, dpp);
2759 });
2760 }
2761
2762 int RGWBucketCtl::sync_user_stats(const DoutPrefixProvider *dpp,
2763 const rgw_user& user_id,
2764 const RGWBucketInfo& bucket_info,
2765 optional_yield y,
2766 RGWBucketEnt* pent)
2767 {
2768 RGWBucketEnt ent;
2769 if (!pent) {
2770 pent = &ent;
2771 }
2772 int r = svc.bi->read_stats(dpp, bucket_info, pent, y);
2773 if (r < 0) {
2774 ldpp_dout(dpp, 20) << __func__ << "(): failed to read bucket stats (r=" << r << ")" << dendl;
2775 return r;
2776 }
2777
2778 return svc.user->flush_bucket_stats(dpp, user_id, *pent, y);
2779 }
2780
2781 int RGWBucketCtl::get_sync_policy_handler(std::optional<rgw_zone_id> zone,
2782 std::optional<rgw_bucket> bucket,
2783 RGWBucketSyncPolicyHandlerRef *phandler,
2784 optional_yield y,
2785 const DoutPrefixProvider *dpp)
2786 {
2787 int r = call([&](RGWSI_Bucket_X_Ctx& ctx) {
2788 return svc.bucket_sync->get_policy_handler(ctx, zone, bucket, phandler, y, dpp);
2789 });
2790 if (r < 0) {
2791 ldpp_dout(dpp, 20) << __func__ << "(): failed to get policy handler for bucket=" << bucket << " (r=" << r << ")" << dendl;
2792 return r;
2793 }
2794 return 0;
2795 }
2796
2797 int RGWBucketCtl::bucket_exports_data(const rgw_bucket& bucket,
2798 optional_yield y,
2799 const DoutPrefixProvider *dpp)
2800 {
2801
2802 RGWBucketSyncPolicyHandlerRef handler;
2803
2804 int r = get_sync_policy_handler(std::nullopt, bucket, &handler, y, dpp);
2805 if (r < 0) {
2806 return r;
2807 }
2808
2809 return handler->bucket_exports_data();
2810 }
2811
2812 int RGWBucketCtl::bucket_imports_data(const rgw_bucket& bucket,
2813 optional_yield y, const DoutPrefixProvider *dpp)
2814 {
2815
2816 RGWBucketSyncPolicyHandlerRef handler;
2817
2818 int r = get_sync_policy_handler(std::nullopt, bucket, &handler, y, dpp);
2819 if (r < 0) {
2820 return r;
2821 }
2822
2823 return handler->bucket_imports_data();
2824 }
2825
2826 RGWBucketMetadataHandlerBase* RGWBucketMetaHandlerAllocator::alloc()
2827 {
2828 return new RGWBucketMetadataHandler();
2829 }
2830
2831 RGWBucketInstanceMetadataHandlerBase* RGWBucketInstanceMetaHandlerAllocator::alloc(rgw::sal::Driver* driver)
2832 {
2833 return new RGWBucketInstanceMetadataHandler(driver);
2834 }
2835
2836 RGWBucketMetadataHandlerBase* RGWArchiveBucketMetaHandlerAllocator::alloc()
2837 {
2838 return new RGWArchiveBucketMetadataHandler();
2839 }
2840
2841 RGWBucketInstanceMetadataHandlerBase* RGWArchiveBucketInstanceMetaHandlerAllocator::alloc(rgw::sal::Driver* driver)
2842 {
2843 return new RGWArchiveBucketInstanceMetadataHandler(driver);
2844 }
2845
2846
2847 void RGWBucketEntryPoint::generate_test_instances(list<RGWBucketEntryPoint*>& o)
2848 {
2849 RGWBucketEntryPoint *bp = new RGWBucketEntryPoint();
2850 init_bucket(&bp->bucket, "tenant", "bucket", "pool", ".index.pool", "marker", "10");
2851 bp->owner = "owner";
2852 bp->creation_time = ceph::real_clock::from_ceph_timespec({ceph_le32(2), ceph_le32(3)});
2853
2854 o.push_back(bp);
2855 o.push_back(new RGWBucketEntryPoint);
2856 }
2857
2858 void RGWBucketEntryPoint::dump(Formatter *f) const
2859 {
2860 encode_json("bucket", bucket, f);
2861 encode_json("owner", owner, f);
2862 utime_t ut(creation_time);
2863 encode_json("creation_time", ut, f);
2864 encode_json("linked", linked, f);
2865 encode_json("has_bucket_info", has_bucket_info, f);
2866 if (has_bucket_info) {
2867 encode_json("old_bucket_info", old_bucket_info, f);
2868 }
2869 }
2870
2871 void RGWBucketEntryPoint::decode_json(JSONObj *obj) {
2872 JSONDecoder::decode_json("bucket", bucket, obj);
2873 JSONDecoder::decode_json("owner", owner, obj);
2874 utime_t ut;
2875 JSONDecoder::decode_json("creation_time", ut, obj);
2876 creation_time = ut.to_real_time();
2877 JSONDecoder::decode_json("linked", linked, obj);
2878 JSONDecoder::decode_json("has_bucket_info", has_bucket_info, obj);
2879 if (has_bucket_info) {
2880 JSONDecoder::decode_json("old_bucket_info", old_bucket_info, obj);
2881 }
2882 }
2883