1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
4 #include "rgw_acl_s3.h"
5 #include "rgw_tag_s3.h"
7 #include "rgw_bucket.h"
9 #include "rgw_bucket_sync.h"
11 #include "services/svc_zone.h"
12 #include "services/svc_bucket.h"
13 #include "services/svc_user.h"
15 #include "rgw_reshard.h"
17 // stolen from src/cls/version/cls_version.cc
18 #define VERSION_ATTR "ceph.objclass.version"
20 #include "cls/user/cls_user_types.h"
22 #include "rgw_sal_rados.h"
24 #define dout_subsys ceph_subsys_rgw
26 // seconds for timeout during RGWBucket::check_object_index
27 constexpr uint64_t BUCKET_TAG_QUICK_TIMEOUT
= 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;
36 * The tenant_name is always returned on purpose. May be empty, of course.
38 static void parse_bucket(const string
& bucket
,
41 string
*bucket_instance
= nullptr /* optional */)
44 * expected format: [tenant/]bucket:bucket_instance
46 int pos
= bucket
.find('/');
48 *tenant_name
= bucket
.substr(0, pos
);
52 string bn
= bucket
.substr(pos
+ 1);
55 *bucket_name
= std::move(bn
);
58 *bucket_name
= bn
.substr(0, pos
);
59 if (bucket_instance
) {
60 *bucket_instance
= bn
.substr(pos
+ 1);
64 * deal with the possible tenant:bucket:bucket_instance case
66 if (tenant_name
->empty()) {
67 pos
= bucket_instance
->find(':');
69 *tenant_name
= *bucket_name
;
70 *bucket_name
= bucket_instance
->substr(0, pos
);
71 *bucket_instance
= bucket_instance
->substr(pos
+ 1);
76 static void dump_mulipart_index_results(list
<rgw_obj_index_key
>& objs_to_unlink
,
79 for (const auto& o
: objs_to_unlink
) {
80 f
->dump_string("object", o
.name
);
84 void check_bad_user_bucket_mapping(rgw::sal::Driver
* driver
, rgw::sal::User
& user
,
87 const DoutPrefixProvider
*dpp
)
89 rgw::sal::BucketList user_buckets
;
92 CephContext
*cct
= driver
->ctx();
94 size_t max_entries
= cct
->_conf
->rgw_list_buckets_max_chunk
;
97 int ret
= user
.list_buckets(dpp
, marker
, string(), max_entries
, false, user_buckets
, y
);
99 ldout(driver
->ctx(), 0) << "failed to read user buckets: "
100 << cpp_strerror(-ret
) << dendl
;
104 map
<string
, std::unique_ptr
<rgw::sal::Bucket
>>& buckets
= user_buckets
.get_buckets();
105 for (auto i
= buckets
.begin();
110 auto& bucket
= i
->second
;
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
);
115 ldout(driver
->ctx(), 0) << "could not get bucket info for bucket=" << bucket
<< dendl
;
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
;
125 cout
<< "fixing" << std::endl
;
126 r
= actual_bucket
->chown(dpp
, user
, y
);
128 cerr
<< "failed to fix bucket: " << cpp_strerror(-r
) << std::endl
;
133 } while (user_buckets
.is_truncated());
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
)
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
);
145 int rgw_remove_object(const DoutPrefixProvider
*dpp
, rgw::sal::Driver
* driver
, rgw::sal::Bucket
* bucket
, rgw_obj_key
& key
)
147 if (key
.instance
.empty()) {
148 key
.instance
= "null";
151 std::unique_ptr
<rgw::sal::Object
> object
= bucket
->get_object(key
);
153 return object
->delete_object(dpp
, null_yield
);
156 static void set_err_msg(std::string
*sink
, std::string msg
)
158 if (sink
&& !msg
.empty())
162 int RGWBucket::init(rgw::sal::Driver
* _driver
, RGWBucketAdminOpState
& op_state
,
163 optional_yield y
, const DoutPrefixProvider
*dpp
, std::string
*err_msg
)
166 set_err_msg(err_msg
, "no storage!");
172 std::string bucket_name
= op_state
.get_bucket_name();
174 if (bucket_name
.empty() && op_state
.get_user_id().empty())
177 user
= driver
->get_user(op_state
.get_user_id());
178 std::string tenant
= user
->get_tenant();
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);
187 int r
= driver
->get_bucket(dpp
, user
.get(), tenant
, bucket_name
, &bucket
, y
);
189 set_err_msg(err_msg
, "failed to fetch bucket info for bucket=" + bucket_name
);
193 op_state
.set_bucket(bucket
->clone());
195 if (!rgw::sal::User::empty(user
.get())) {
196 r
= user
->load_user(dpp
, y
);
198 set_err_msg(err_msg
, "failed to fetch user info");
203 op_state
.display_name
= user
->get_display_name();
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
)
213 bool truncated
= false;
216 int ret
= driver
->meta_list_keys_init(dpp
, "bucket.instance", marker
, &handle
);
218 cerr
<< "ERROR: can't get key: " << cpp_strerror(-ret
) << std::endl
;
219 driver
->meta_list_keys_complete(handle
);
224 ret
= driver
->meta_list_keys_next(dpp
, handle
, 1000, keys
, &truncated
);
226 cerr
<< "ERROR: lists_keys_next(): " << cpp_strerror(-ret
) << std::endl
;
227 driver
->meta_list_keys_complete(handle
);
230 for (list
<string
>::iterator iter
= keys
.begin(); iter
!= keys
.end(); ++iter
) {
232 ret
= rgw_bucket_parse_bucket_key(cct
, s
, bucket_out
, nullptr);
236 if (bucket_id
== bucket_out
->bucket_id
) {
237 driver
->meta_list_keys_complete(handle
);
242 driver
->meta_list_keys_complete(handle
);
246 int RGWBucket::chown(RGWBucketAdminOpState
& op_state
, const string
& marker
,
247 optional_yield y
, const DoutPrefixProvider
*dpp
, std::string
*err_msg
)
249 /* User passed in by rgw_admin is the new user; get the current user and set it in
251 std::unique_ptr
<rgw::sal::User
> old_user
= driver
->get_user(bucket
->get_info().owner
);
252 bucket
->set_owner(old_user
.get());
254 return rgw_chown_bucket_and_objects(driver
, bucket
.get(), user
.get(), marker
, err_msg
, dpp
, y
);
257 int RGWBucket::set_quota(RGWBucketAdminOpState
& op_state
, const DoutPrefixProvider
*dpp
, std::string
*err_msg
)
259 bucket
= op_state
.get_bucket()->clone();
261 bucket
->get_info().quota
= op_state
.quota
;
262 int r
= bucket
->put_info(dpp
, false, real_time());
264 set_err_msg(err_msg
, "ERROR: failed writing bucket instance info: " + cpp_strerror(-r
));
270 int RGWBucket::remove_object(const DoutPrefixProvider
*dpp
, RGWBucketAdminOpState
& op_state
, std::string
*err_msg
)
272 std::string object_name
= op_state
.get_object_name();
274 rgw_obj_key
key(object_name
);
276 bucket
= op_state
.get_bucket()->clone();
278 int ret
= rgw_remove_object(dpp
, driver
, bucket
.get(), key
);
280 set_err_msg(err_msg
, "unable to remove object" + cpp_strerror(-ret
));
287 static void dump_bucket_index(const vector
<rgw_bucket_dir_entry
>& objs
, Formatter
*f
)
289 for (auto iter
= objs
.begin(); iter
!= objs
.end(); ++iter
) {
290 f
->dump_string("object", iter
->key
.name
);
294 static void dump_bucket_usage(map
<RGWObjCategory
, RGWStorageStats
>& stats
, Formatter
*formatter
)
296 map
<RGWObjCategory
, RGWStorageStats
>::iterator iter
;
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
));
303 formatter
->close_section();
305 formatter
->close_section();
308 static void dump_index_check(map
<RGWObjCategory
, RGWStorageStats
> existing_stats
,
309 map
<RGWObjCategory
, RGWStorageStats
> calculated_stats
,
310 Formatter
*formatter
)
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();
322 int RGWBucket::check_bad_index_multipart(RGWBucketAdminOpState
& op_state
,
323 RGWFormatterFlusher
& flusher
,
324 const DoutPrefixProvider
*dpp
,
325 std::string
*err_msg
)
327 const bool fix_index
= op_state
.will_fix_index();
329 bucket
= op_state
.get_bucket()->clone();
331 rgw::sal::Bucket::ListParams params
;
332 params
.list_versions
= true;
333 params
.ns
= RGW_OBJ_NS_MULTIPART
;
335 std::map
<std::string
, bool> meta_objs
;
336 std::map
<rgw_obj_index_key
, std::string
> all_objs
;
339 rgw::sal::Bucket::ListResults results
;
340 int r
= bucket
->list(dpp
, params
, listing_max_entries
, results
, null_yield
);
342 set_err_msg(err_msg
, "failed to list objects in bucket=" + bucket
->get_name() +
343 " err=" + cpp_strerror(-r
));
347 is_truncated
= results
.is_truncated
;
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();
354 int pos
= oid
.find_last_of('.');
356 /* obj has no suffix */
360 std::string name
= oid
.substr(0, pos
);
361 std::string suffix
= oid
.substr(pos
+ 1);
363 if (suffix
.compare("meta") == 0) {
364 meta_objs
[name
] = true;
366 all_objs
[key
] = name
;
370 } while (is_truncated
);
372 std::list
<rgw_obj_index_key
> objs_to_unlink
;
373 Formatter
*f
= flusher
.get_formatter();
375 f
->open_array_section("invalid_multipart_entries");
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
);
383 if (objs_to_unlink
.size() > listing_max_entries
) {
385 // note: under rados this removes directly from rados index objects
386 int r
= bucket
->remove_objs_from_index(dpp
, objs_to_unlink
);
388 set_err_msg(err_msg
, "ERROR: remove_obj_from_index() returned error: " +
394 dump_mulipart_index_results(objs_to_unlink
, f
);
396 objs_to_unlink
.clear();
401 // note: under rados this removes directly from rados index objects
402 int r
= bucket
->remove_objs_from_index(dpp
, objs_to_unlink
);
404 set_err_msg(err_msg
, "ERROR: remove_obj_from_index() returned error: " +
411 dump_mulipart_index_results(objs_to_unlink
, f
);
418 int RGWBucket::check_object_index(const DoutPrefixProvider
*dpp
,
419 RGWBucketAdminOpState
& op_state
,
420 RGWFormatterFlusher
& flusher
,
422 std::string
*err_msg
)
425 bool fix_index
= op_state
.will_fix_index();
428 set_err_msg(err_msg
, "check-objects flag requires fix index enabled");
432 // use a quicker/shorter tag timeout during this process
433 bucket
->set_tag_timeout(dpp
, BUCKET_TAG_QUICK_TIMEOUT
);
435 rgw::sal::Bucket::ListResults results
;
436 results
.is_truncated
= true;
438 Formatter
*formatter
= flusher
.get_formatter();
439 formatter
->open_object_section("objects");
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
;
446 int r
= bucket
->list(dpp
, params
, listing_max_entries
, results
, y
);
451 set_err_msg(err_msg
, "ERROR: failed operation r=" + cpp_strerror(-r
));
454 dump_bucket_index(results
.objs
, formatter
);
458 formatter
->close_section();
460 // restore normal tag timeout for bucket
461 bucket
->set_tag_timeout(dpp
, 0);
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
)
473 bool fix_index
= op_state
.will_fix_index();
475 int r
= bucket
->check_index(dpp
, existing_stats
, calculated_stats
);
477 set_err_msg(err_msg
, "failed to check index error=" + cpp_strerror(-r
));
482 r
= bucket
->rebuild_index(dpp
);
484 set_err_msg(err_msg
, "failed to rebuild index err=" + cpp_strerror(-r
));
492 int RGWBucket::sync(RGWBucketAdminOpState
& op_state
, const DoutPrefixProvider
*dpp
, std::string
*err_msg
)
494 if (!driver
->is_meta_master()) {
495 set_err_msg(err_msg
, "ERROR: failed to update bucket sync: only allowed on meta master zone");
498 bool sync
= op_state
.will_sync_bucket();
500 bucket
->get_info().flags
&= ~BUCKET_DATASYNC_DISABLED
;
502 bucket
->get_info().flags
|= BUCKET_DATASYNC_DISABLED
;
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());
509 set_err_msg(err_msg
, "ERROR: failed writing bucket instance info:" + cpp_strerror(-r
));
517 int RGWBucket::policy_bl_to_stream(bufferlist
& bl
, ostream
& o
)
519 RGWAccessControlPolicy_S3
policy(g_ceph_context
);
520 int ret
= decode_bl(bl
, policy
);
522 ldout(driver
->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl
;
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
)
532 std::unique_ptr
<rgw::sal::Object::ReadOp
> rop
= obj
->get_read_op();
534 return rop
->get_attr(dpp
, attr_name
, out_bl
, y
);
537 int RGWBucket::get_policy(RGWBucketAdminOpState
& op_state
, RGWAccessControlPolicy
& policy
, optional_yield y
, const DoutPrefixProvider
*dpp
)
540 std::string object_name
= op_state
.get_object_name();
542 bucket
= op_state
.get_bucket()->clone();
544 if (!object_name
.empty()) {
546 std::unique_ptr
<rgw::sal::Object
> obj
= bucket
->get_object(rgw_obj_key(object_name
));
548 ret
= rgw_object_get_attr(dpp
, driver
, obj
.get(), RGW_ATTR_ACL
, bl
, y
);
553 ret
= decode_bl(bl
, policy
);
555 ldout(driver
->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl
;
560 map
<string
, bufferlist
>::iterator aiter
= bucket
->get_attrs().find(RGW_ATTR_ACL
);
561 if (aiter
== bucket
->get_attrs().end()) {
565 ret
= decode_bl(aiter
->second
, policy
);
567 ldout(driver
->ctx(),0) << "failed to decode RGWAccessControlPolicy" << dendl
;
574 int RGWBucketAdminOp::get_policy(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
,
575 RGWAccessControlPolicy
& policy
, const DoutPrefixProvider
*dpp
)
579 int ret
= bucket
.init(driver
, op_state
, null_yield
, dpp
);
583 ret
= bucket
.get_policy(op_state
, policy
, null_yield
, dpp
);
590 /* Wrappers to facilitate RESTful interface */
593 int RGWBucketAdminOp::get_policy(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
,
594 RGWFormatterFlusher
& flusher
, const DoutPrefixProvider
*dpp
)
596 RGWAccessControlPolicy
policy(driver
->ctx());
598 int ret
= get_policy(driver
, op_state
, policy
, dpp
);
602 Formatter
*formatter
= flusher
.get_formatter();
606 formatter
->open_object_section("policy");
607 policy
.dump(formatter
);
608 formatter
->close_section();
615 int RGWBucketAdminOp::dump_s3_policy(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
,
616 ostream
& os
, const DoutPrefixProvider
*dpp
)
618 RGWAccessControlPolicy_S3
policy(driver
->ctx());
620 int ret
= get_policy(driver
, op_state
, policy
, dpp
);
629 int RGWBucketAdminOp::unlink(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
, const DoutPrefixProvider
*dpp
)
633 int ret
= bucket
.init(driver
, op_state
, null_yield
, dpp
);
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);
640 int RGWBucketAdminOp::link(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
, const DoutPrefixProvider
*dpp
, string
*err
)
642 if (!op_state
.is_user_op()) {
643 set_err_msg(err
, "empty user id");
648 int ret
= bucket
.init(driver
, op_state
, null_yield
, dpp
, err
);
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
;
657 loc_bucket
= op_state
.get_bucket()->clone();
659 if (!bucket_id
.empty() && bucket_id
!= loc_bucket
->get_bucket_id()) {
661 "specified bucket id does not match " + loc_bucket
->get_bucket_id());
665 old_bucket
= loc_bucket
->clone();
667 loc_bucket
->get_key().tenant
= op_state
.get_user_id().tenant
;
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);
675 loc_bucket
->get_key().name
= op_state
.new_bucket_name
;
679 RGWObjVersionTracker objv_tracker
;
680 RGWObjVersionTracker old_version
= loc_bucket
->get_info().objv_tracker
;
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
;
687 "While crossing the Anavros you have displeased the goddess Hera."
688 " You must sacrifice your ancient bucket " + loc_bucket
->get_bucket_id());
691 bufferlist
& aclbl
= aiter
->second
;
692 RGWAccessControlPolicy policy
;
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");
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);
705 set_err_msg(err
, "could not unlink policy from user " + owner
.get_id().to_str());
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
;
714 RGWAccessControlPolicy policy_instance
;
715 policy_instance
.create_default(op_state
.get_user_id(), display_name
);
716 owner
= policy_instance
.get_owner();
719 policy_instance
.encode(aclbl
);
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;
729 r
= loc_bucket
->put_info(dpp
, exclusive
, ceph::real_time());
731 set_err_msg(err
, "ERROR: failed writing bucket instance info: " + cpp_strerror(-r
));
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
;
741 rgw::sal::Attrs ep_attrs
;
742 rgw_ep_info ep_data
{ep
, ep_attrs
};
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
);
746 set_err_msg(err
, "failed to relink bucket");
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
));
757 set_err_msg(err
, "failed to unlink old bucket " + old_bucket
->get_tenant() + "/" + old_bucket
->get_name());
760 r
= static_cast<rgw::sal::RadosStore
*>(driver
)->ctl()->bucket
->remove_bucket_instance_info(
761 old_bucket
->get_key(), old_bucket
->get_info(),
763 RGWBucketCtl::BucketInstance::RemoveParams()
764 .set_objv_tracker(&ep_data
.ep_objv
));
766 set_err_msg(err
, "failed to unlink old bucket " + old_bucket
->get_tenant() + "/" + old_bucket
->get_name());
774 int RGWBucketAdminOp::chown(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
, const string
& marker
, const DoutPrefixProvider
*dpp
, string
*err
)
778 int ret
= bucket
.init(driver
, op_state
, null_yield
, dpp
, err
);
782 return bucket
.chown(op_state
, marker
, null_yield
, dpp
, err
);
786 int RGWBucketAdminOp::check_index(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
,
787 RGWFormatterFlusher
& flusher
, optional_yield y
, const DoutPrefixProvider
*dpp
)
790 map
<RGWObjCategory
, RGWStorageStats
> existing_stats
;
791 map
<RGWObjCategory
, RGWStorageStats
> calculated_stats
;
796 ret
= bucket
.init(driver
, op_state
, null_yield
, dpp
);
800 Formatter
*formatter
= flusher
.get_formatter();
803 ret
= bucket
.check_bad_index_multipart(op_state
, flusher
, dpp
);
807 ret
= bucket
.check_object_index(dpp
, op_state
, flusher
, y
);
811 ret
= bucket
.check_index(dpp
, op_state
, existing_stats
, calculated_stats
);
815 dump_index_check(existing_stats
, calculated_stats
, formatter
);
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
)
825 std::unique_ptr
<rgw::sal::Bucket
> bucket
;
826 std::unique_ptr
<rgw::sal::User
> user
= driver
->get_user(op_state
.get_user_id());
828 int ret
= driver
->get_bucket(dpp
, user
.get(), user
->get_tenant(), op_state
.get_bucket_name(),
834 ret
= bucket
->remove_bucket_bypass_gc(op_state
.get_max_aio(), keep_index_consistent
, y
, dpp
);
836 ret
= bucket
->remove_bucket(dpp
, op_state
.will_delete_children(),
842 int RGWBucketAdminOp::remove_object(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
, const DoutPrefixProvider
*dpp
)
846 int ret
= bucket
.init(driver
, op_state
, null_yield
, dpp
);
850 return bucket
.remove_object(dpp
, op_state
);
853 int RGWBucketAdminOp::sync_bucket(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
, const DoutPrefixProvider
*dpp
, string
*err_msg
)
856 int ret
= bucket
.init(driver
, op_state
, null_yield
, dpp
, err_msg
);
861 return bucket
.sync(op_state
, dpp
, err_msg
);
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
)
870 std::unique_ptr
<rgw::sal::Bucket
> bucket
;
871 map
<RGWObjCategory
, RGWStorageStats
> stats
;
873 int ret
= driver
->get_bucket(dpp
, nullptr, tenant_name
, bucket_name
, &bucket
, null_yield
);
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
;
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
);
889 cerr
<< "error getting bucket stats bucket=" << bucket
->get_name() << " ret=" << ret
<< std::endl
;
893 utime_t
ut(bucket
->get_modification_time());
894 utime_t
ctime_ut(bucket
->get_creation_time());
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
);
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
};
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
;
931 formatter
->close_section();
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
,
944 const size_t max_entries
=
945 driver
->ctx()->_conf
->rgw_list_buckets_max_chunk
;
947 const size_t safe_max_objs_per_shard
=
948 driver
->ctx()->_conf
->rgw_safe_max_objects_per_shard
;
950 uint16_t shard_warn_pct
=
951 driver
->ctx()->_conf
->rgw_shard_warning_threshold
;
952 if (shard_warn_pct
> 100)
955 Formatter
*formatter
= flusher
.get_formatter();
958 formatter
->open_array_section("users");
960 for (const auto& user_id
: user_ids
) {
962 formatter
->open_object_section("user");
963 formatter
->dump_string("user_id", user_id
);
964 formatter
->open_array_section("buckets");
967 rgw::sal::BucketList buckets
;
969 std::unique_ptr
<rgw::sal::User
> user
= driver
->get_user(rgw_user(user_id
));
971 ret
= user
->list_buckets(dpp
, marker
, string(), max_entries
, false, buckets
, y
);
976 map
<string
, std::unique_ptr
<rgw::sal::Bucket
>>& m_buckets
= buckets
.get_buckets();
978 for (const auto& iter
: m_buckets
) {
979 auto& bucket
= iter
.second
;
980 uint64_t num_objects
= 0;
982 marker
= bucket
->get_name(); /* Casey's location for marker update,
983 * as we may now not reach the end of
986 ret
= bucket
->load_bucket(dpp
, y
);
990 const auto& index
= bucket
->get_info().get_current_index();
991 if (is_layout_indexless(index
)) {
992 continue; // indexless buckets don't have stats
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);
1003 for (const auto& s
: stats
) {
1004 num_objects
+= s
.second
.num_objects
;
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
;
1013 uint64_t fill_pct
= objs_per_shard
* 100 / safe_max_objs_per_shard
;
1014 if (fill_pct
> 100) {
1015 ss
<< "OVER " << fill_pct
<< "%";
1017 } else if (fill_pct
>= shard_warn_pct
) {
1018 ss
<< "WARN " << fill_pct
<< "%";
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();
1037 formatter
->flush(cout
);
1038 } while (buckets
.is_truncated()); /* foreach: bucket */
1040 formatter
->close_section();
1041 formatter
->close_section();
1042 formatter
->flush(cout
);
1044 } /* foreach: user_id */
1046 formatter
->close_section();
1047 formatter
->flush(cout
);
1050 } /* RGWBucketAdminOp::limit_check */
1052 int RGWBucketAdminOp::info(rgw::sal::Driver
* driver
,
1053 RGWBucketAdminOpState
& op_state
,
1054 RGWFormatterFlusher
& flusher
,
1056 const DoutPrefixProvider
*dpp
)
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
);
1064 return -ERR_NO_SUCH_BUCKET
;
1069 Formatter
*formatter
= flusher
.get_formatter();
1072 CephContext
*cct
= driver
->ctx();
1074 const size_t max_entries
= cct
->_conf
->rgw_list_buckets_max_chunk
;
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");
1081 rgw::sal::BucketList buckets
;
1082 std::unique_ptr
<rgw::sal::User
> user
= driver
->get_user(op_state
.get_user_id());
1084 const std::string empty_end_marker
;
1085 constexpr bool no_need_stats
= false; // set need_stats to false
1088 ret
= user
->list_buckets(dpp
, marker
, empty_end_marker
, max_entries
,
1089 no_need_stats
, buckets
, y
);
1094 const std::string
* marker_cursor
= nullptr;
1095 map
<string
, std::unique_ptr
<rgw::sal::Bucket
>>& m
= buckets
.get_buckets();
1097 for (const auto& i
: m
) {
1098 const std::string
& obj_name
= i
.first
;
1099 if (!bucket_name
.empty() && bucket_name
!= obj_name
) {
1104 bucket_stats(driver
, user_id
.tenant
, obj_name
, formatter
, dpp
);
1106 formatter
->dump_string("bucket", obj_name
);
1109 marker_cursor
= &obj_name
;
1111 if (marker_cursor
) {
1112 marker
= *marker_cursor
;
1116 } while (buckets
.is_truncated());
1118 formatter
->close_section();
1119 } else if (!bucket_name
.empty()) {
1120 ret
= bucket_stats(driver
, user_id
.tenant
, bucket_name
, formatter
, dpp
);
1125 void *handle
= nullptr;
1126 bool truncated
= true;
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
,
1135 for (auto& bucket_name
: buckets
) {
1137 bucket_stats(driver
, user_id
.tenant
, bucket_name
, formatter
, dpp
);
1139 formatter
->dump_string("bucket", bucket_name
);
1143 driver
->meta_list_keys_complete(handle
);
1145 formatter
->close_section();
1153 int RGWBucketAdminOp::set_quota(rgw::sal::Driver
* driver
, RGWBucketAdminOpState
& op_state
, const DoutPrefixProvider
*dpp
)
1157 int ret
= bucket
.init(driver
, op_state
, null_yield
, dpp
);
1160 return bucket
.set_quota(op_state
, dpp
);
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));
1168 return std::make_pair(std::string(), bucket_name
);
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
)
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
;
1185 rgw_bucket_parse_bucket_key(driver
->ctx(), bucket_instance
, &rbucket
, nullptr);
1186 int r
= driver
->get_bucket(dpp
, nullptr, rbucket
, &bucket
, null_yield
);
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
;
1193 binfo
= bucket
->get_info();
1194 if (binfo
.reshard_status
== cls_rgw_reshard_status::DONE
)
1195 stale_instances
.emplace_back(std::move(binfo
));
1197 other_instances
.emplace_back(std::move(binfo
));
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
);
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()));
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
;
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
)
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
);
1231 other_instances
.end());
1233 // check if there are still instances left
1234 if (other_instances
.empty()) {
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
1243 RGWBucketReshardLock
reshard_lock(static_cast<rgw::sal::RadosStore
*>(driver
), cur_bucket
->get_info(), true);
1244 r
= reshard_lock
.lock(dpp
);
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
;
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()));
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
&,
1267 rgw::sal::Driver
*)> process_f
)
1271 Formatter
*formatter
= flusher
.get_formatter();
1272 static constexpr auto default_max_keys
= 1000;
1274 int ret
= driver
->meta_list_keys_init(dpp
, "bucket.instance", marker
, &handle
);
1276 cerr
<< "ERROR: can't get key: " << cpp_strerror(-ret
) << std::endl
;
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
);
1290 list
<std::string
> keys
;
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
;
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
));
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
);
1311 } while (truncated
);
1316 int RGWBucketAdminOp::list_stale_instances(rgw::sal::Driver
* driver
,
1317 RGWBucketAdminOpState
& op_state
,
1318 RGWFormatterFlusher
& flusher
,
1319 const DoutPrefixProvider
*dpp
)
1321 auto process_f
= [](const bucket_instance_ls
& lst
,
1322 Formatter
*formatter
,
1324 for (const auto& binfo
: lst
)
1325 formatter
->dump_string("key", binfo
.bucket
.get_key());
1327 return process_stale_instances(driver
, op_state
, flusher
, dpp
, process_f
);
1331 int RGWBucketAdminOp::clear_stale_instances(rgw::sal::Driver
* driver
,
1332 RGWBucketAdminOpState
& op_state
,
1333 RGWFormatterFlusher
& flusher
,
1334 const DoutPrefixProvider
*dpp
)
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
);
1344 auto md_key
= "bucket.instance:" + binfo
.bucket
.get_key();
1345 ret
= driver
->meta_remove(dpp
, md_key
, null_yield
);
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();
1354 return process_stale_instances(driver
, op_state
, flusher
, dpp
, process_f
);
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
)
1362 std::unique_ptr
<rgw::sal::Bucket
> bucket
;
1363 int ret
= driver
->get_bucket(dpp
, nullptr, tenant_name
, bucket_name
, &bucket
, null_yield
);
1365 // TODO: Should we handle the case where the bucket could've been removed between
1366 // listing and fetching?
1370 return rgw::lc::fix_lc_shard_entry(dpp
, driver
, driver
->get_rgwlc()->get_lc(), bucket
.get());
1373 static void format_lc_status(Formatter
* formatter
,
1374 const std::string
& tenant_name
,
1375 const std::string
& bucket_name
,
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
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
)
1391 int ret
= fix_single_bucket_lc(driver
, tenant_name
, bucket_name
, dpp
);
1392 format_lc_status(formatter
, tenant_name
, bucket_name
, -ret
);
1395 int RGWBucketAdminOp::fix_lc_shards(rgw::sal::Driver
* driver
,
1396 RGWBucketAdminOpState
& op_state
,
1397 RGWFormatterFlusher
& flusher
,
1398 const DoutPrefixProvider
*dpp
)
1402 Formatter
*formatter
= flusher
.get_formatter();
1403 static constexpr auto default_max_keys
= 1000;
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
);
1412 int ret
= driver
->meta_list_keys_init(dpp
, "bucket", marker
, &handle
);
1414 std::cerr
<< "ERROR: can't get key: " << cpp_strerror(-ret
) << std::endl
;
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
);
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
;
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
);
1437 formatter
->flush(cout
); // regularly flush every 1k entries
1438 } while (truncated
);
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
)
1451 std::unique_ptr
<rgw::sal::Object
> obj
= bucket
->get_object(key
);
1452 bufferlist delete_at_bl
;
1454 int ret
= rgw_object_get_attr(dpp
, driver
, obj
.get(), RGW_ATTR_DELETE_AT
, delete_at_bl
, null_yield
);
1456 return false; // no delete at attr, proceed
1459 ret
= decode_bl(delete_at_bl
, delete_at
);
1461 return false; // failed to parse
1464 if (delete_at
<= ceph_clock_now() && !delete_at
.is_zero()) {
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
)
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
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
);
1488 rgw::sal::Bucket::ListParams params
;
1489 rgw::sal::Bucket::ListResults results
;
1491 params
.list_versions
= bucket
->versioned();
1492 params
.allow_unordered
= true;
1495 int ret
= bucket
->list(dpp
, params
, listing_max_entries
, results
, null_yield
);
1497 ldpp_dout(dpp
, -1) << "ERROR failed to list objects in the bucket" << dendl
;
1500 for (const auto& obj
: results
.objs
) {
1501 rgw_obj_key
key(obj
.key
);
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
;
1509 ret
= rgw_remove_object(dpp
, driver
, bucket
, key
);
1510 formatter
->dump_int("status", ret
);
1513 formatter
->close_section(); // object_status
1516 formatter
->flush(cout
); // regularly flush every 1k entries
1517 } while (results
.is_truncated
);
1522 int RGWBucketAdminOp::fix_obj_expiry(rgw::sal::Driver
* driver
,
1523 RGWBucketAdminOpState
& op_state
,
1524 RGWFormatterFlusher
& flusher
,
1525 const DoutPrefixProvider
*dpp
, bool dry_run
)
1527 RGWBucket admin_bucket
;
1528 int ret
= admin_bucket
.init(driver
, op_state
, null_yield
, dpp
);
1530 ldpp_dout(dpp
, -1) << "failed to initialize bucket" << dendl
;
1533 std::unique_ptr
<rgw::sal::Bucket
> bucket
;
1534 ret
= driver
->get_bucket(nullptr, admin_bucket
.get_bucket_info(), &bucket
);
1539 return fix_bucket_obj_expiry(dpp
, driver
, bucket
.get(), flusher
, dry_run
);
1542 void RGWBucketCompleteInfo::dump(Formatter
*f
) const {
1543 encode_json("bucket_info", info
, f
);
1544 encode_json("attrs", attrs
, f
);
1547 void RGWBucketCompleteInfo::decode_json(JSONObj
*obj
) {
1548 JSONDecoder::decode_json("bucket_info", info
, obj
);
1549 JSONDecoder::decode_json("attrs", attrs
, obj
);
1552 class RGWBucketMetadataHandler
: public RGWBucketMetadataHandlerBase
{
1555 RGWSI_Bucket
*bucket
{nullptr};
1559 RGWBucketCtl
*bucket
{nullptr};
1562 RGWBucketMetadataHandler() {}
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
;
1572 string
get_type() override
{ return "bucket"; }
1574 RGWMetadataObject
*get_meta_obj(JSONObj
*jo
, const obj_version
& objv
, const ceph::real_time
& mtime
) override
{
1575 RGWBucketEntryPoint be
;
1578 decode_json_obj(be
, jo
);
1579 } catch (JSONDecoder::err
& e
) {
1583 return new RGWBucketEntryMetadataObject(be
, objv
, mtime
);
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
;
1591 map
<string
, bufferlist
> attrs
;
1593 RGWSI_Bucket_EP_Ctx
ctx(op
->ctx());
1595 int ret
= svc
.bucket
->read_bucket_entrypoint_info(ctx
, entry
, &be
, &ot
, &mtime
, &attrs
, y
, dpp
);
1599 RGWBucketEntryMetadataObject
*mdo
= new RGWBucketEntryMetadataObject(be
, ot
.read_version
, mtime
, std::move(attrs
));
1606 int do_put(RGWSI_MetaBackend_Handler::Op
*op
, string
& entry
,
1607 RGWMetadataObject
*obj
,
1608 RGWObjVersionTracker
& objv_tracker
,
1610 const DoutPrefixProvider
*dpp
,
1611 RGWMDLogSyncType type
, bool from_remote_zone
) override
;
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
;
1617 real_time orig_mtime
;
1619 RGWSI_Bucket_EP_Ctx
ctx(op
->ctx());
1621 int ret
= svc
.bucket
->read_bucket_entrypoint_info(ctx
, entry
, &be
, &objv_tracker
, &orig_mtime
, nullptr, y
, dpp
);
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.
1630 ret
= ctl
.bucket
->unlink_bucket(be
.owner
, be
.bucket
, y
, dpp
, false);
1632 ldpp_dout(dpp
, -1) << "could not unlink bucket=" << entry
<< " owner=" << be
.owner
<< dendl
;
1635 ret
= svc
.bucket
->remove_bucket_entrypoint_info(ctx
, entry
, &objv_tracker
, y
, dpp
);
1637 ldpp_dout(dpp
, -1) << "could not delete bucket=" << entry
<< dendl
;
1643 int call(std::function
<int(RGWSI_Bucket_EP_Ctx
& ctx
)> f
) {
1644 return call(nullopt
, f
);
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());
1656 class RGWMetadataHandlerPut_Bucket
: public RGWMetadataHandlerPut_SObj
1658 RGWBucketMetadataHandler
*bhandler
;
1659 RGWBucketEntryMetadataObject
*obj
;
1661 RGWMetadataHandlerPut_Bucket(RGWBucketMetadataHandler
*_handler
,
1662 RGWSI_MetaBackend_Handler::Op
*op
, string
& entry
,
1663 RGWMetadataObject
*_obj
, RGWObjVersionTracker
& objv_tracker
,
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
);
1669 ~RGWMetadataHandlerPut_Bucket() {}
1671 void encode_obj(bufferlist
*bl
) override
{
1672 obj
->get_ep().encode(*bl
);
1675 int put_checked(const DoutPrefixProvider
*dpp
) override
;
1676 int put_post(const DoutPrefixProvider
*dpp
) override
;
1679 int RGWBucketMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op
*op
, string
& entry
,
1680 RGWMetadataObject
*obj
,
1681 RGWObjVersionTracker
& objv_tracker
,
1683 const DoutPrefixProvider
*dpp
,
1684 RGWMDLogSyncType type
, bool from_remote_zone
)
1686 RGWMetadataHandlerPut_Bucket
put_op(this, op
, entry
, obj
, objv_tracker
, y
, type
, from_remote_zone
);
1687 return do_put_operate(&put_op
, dpp
);
1690 int RGWMetadataHandlerPut_Bucket::put_checked(const DoutPrefixProvider
*dpp
)
1692 RGWBucketEntryMetadataObject
*orig_obj
= static_cast<RGWBucketEntryMetadataObject
*>(old_obj
);
1695 obj
->set_pattrs(&orig_obj
->get_attrs());
1698 auto& be
= obj
->get_ep();
1699 auto mtime
= obj
->get_mtime();
1700 auto pattrs
= obj
->get_pattrs();
1702 RGWSI_Bucket_EP_Ctx
ctx(op
->ctx());
1704 return bhandler
->svc
.bucket
->store_bucket_entrypoint_info(ctx
, entry
,
1714 int RGWMetadataHandlerPut_Bucket::put_post(const DoutPrefixProvider
*dpp
)
1716 auto& be
= obj
->get_ep();
1722 ret
= bhandler
->ctl
.bucket
->link_bucket(be
.owner
, be
.bucket
, be
.creation_time
, y
, dpp
, false);
1724 ret
= bhandler
->ctl
.bucket
->unlink_bucket(be
.owner
, be
.bucket
, y
, dpp
, false);
1730 static void get_md5_digest(const RGWBucketEntryPoint
*be
, string
& md5_digest
) {
1732 char md5
[CEPH_CRYPTO_MD5_DIGESTSIZE
* 2 + 1];
1733 unsigned char m
[CEPH_CRYPTO_MD5_DIGESTSIZE
];
1736 Formatter
*f
= new JSONFormatter(false);
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());
1746 buf_to_hex(m
, CEPH_CRYPTO_MD5_DIGESTSIZE
, md5
);
1753 #define ARCHIVE_META_ATTR RGW_ATTR_PREFIX "zone.archive.info"
1755 struct archive_meta_info
{
1756 rgw_bucket orig_bucket
;
1758 bool from_attrs(CephContext
*cct
, map
<string
, bufferlist
>& attrs
) {
1759 auto iter
= attrs
.find(ARCHIVE_META_ATTR
);
1760 if (iter
== attrs
.end()) {
1764 auto bliter
= iter
->second
.cbegin();
1767 } catch (buffer::error
& err
) {
1768 ldout(cct
, 0) << "ERROR: failed to decode archive meta info" << dendl
;
1775 void store_in_attrs(map
<string
, bufferlist
>& attrs
) const {
1776 encode(attrs
[ARCHIVE_META_ATTR
]);
1779 void encode(bufferlist
& bl
) const {
1780 ENCODE_START(1, 1, bl
);
1781 encode(orig_bucket
, bl
);
1785 void decode(bufferlist::const_iterator
& bl
) {
1786 DECODE_START(1, bl
);
1787 decode(orig_bucket
, bl
);
1791 WRITE_CLASS_ENCODER(archive_meta_info
)
1793 class RGWArchiveBucketMetadataHandler
: public RGWBucketMetadataHandler
{
1795 RGWArchiveBucketMetadataHandler() {}
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();
1801 RGWSI_Bucket_EP_Ctx
ctx(op
->ctx());
1803 ldpp_dout(dpp
, 5) << "SKIP: bucket removal is not allowed on archive zone: bucket:" << entry
<< " ... proceeding to rename" << dendl
;
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
;
1813 /* read original entrypoint */
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
);
1822 string bi_meta_name
= RGWSI_Bucket::get_bi_meta_key(be
.bucket
);
1824 /* read original bucket instance info */
1826 map
<string
, bufferlist
> attrs_m
;
1827 ceph::real_time orig_mtime
;
1828 RGWBucketInfo old_bi
;
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
));
1837 archive_meta_info ami
;
1839 if (!ami
.from_attrs(svc
.bucket
->ctx(), attrs_m
)) {
1840 ami
.orig_bucket
= old_bi
.bucket
;
1841 ami
.store_in_attrs(attrs_m
);
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
1851 string new_bucket_name
;
1853 RGWBucketInfo new_bi
= old_bi
;
1854 RGWBucketEntryPoint new_be
= be
;
1858 get_md5_digest(&new_be
, md5_digest
);
1859 new_bucket_name
= ami
.orig_bucket
.name
+ "-deleted-" + md5_digest
;
1861 new_bi
.bucket
.name
= new_bucket_name
;
1862 new_bi
.objv_tracker
.clear();
1864 new_be
.bucket
.name
= new_bucket_name
;
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
));
1872 ldpp_dout(dpp
, 0) << "ERROR: failed to put new bucket instance info for bucket=" << new_bi
.bucket
<< " ret=" << ret
<< dendl
;
1876 /* store a new entrypoint */
1878 RGWObjVersionTracker ot
;
1879 ot
.generate_new_write_ver(cct
);
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
);
1884 ldpp_dout(dpp
, 0) << "ERROR: failed to put new bucket entrypoint for bucket=" << new_be
.bucket
<< " ret=" << ret
<< dendl
;
1888 /* link new bucket */
1890 ret
= ctl
.bucket
->link_bucket(new_be
.owner
, new_be
.bucket
, new_be
.creation_time
, y
, dpp
, false);
1892 ldpp_dout(dpp
, 0) << "ERROR: failed to link new bucket for bucket=" << new_be
.bucket
<< " ret=" << ret
<< dendl
;
1896 /* clean up old stuff */
1898 ret
= ctl
.bucket
->unlink_bucket(be
.owner
, entry_bucket
, y
, dpp
, false);
1900 ldpp_dout(dpp
, -1) << "could not unlink bucket=" << entry
<< " owner=" << be
.owner
<< dendl
;
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
),
1914 ldpp_dout(dpp
, 0) << "ERROR: failed to put new bucket entrypoint for bucket=" << new_be
.bucket
<< " ret=" << ret
<< dendl
;
1918 ret
= ctl
.bucket
->remove_bucket_instance_info(be
.bucket
, old_bi
, y
, dpp
);
1920 ldpp_dout(dpp
, -1) << "could not delete bucket=" << entry
<< dendl
;
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
) {
1942 ot
.read_version
= robj
->get_version();
1945 ret
= do_remove(op
, entry
, ot
, y
, dpp
);
1952 return RGWBucketMetadataHandler::do_put(op
, entry
, obj
,
1953 objv_tracker
, y
, dpp
, type
, from_remote_zone
);
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
,
1964 const DoutPrefixProvider
*dpp
) {
1965 return svc
.bucket
->read_bucket_instance_info(ctx
,
1975 RGWSI_Zone
*zone
{nullptr};
1976 RGWSI_Bucket
*bucket
{nullptr};
1977 RGWSI_BucketIndex
*bi
{nullptr};
1980 rgw::sal::Driver
* driver
;
1982 RGWBucketInstanceMetadataHandler(rgw::sal::Driver
* driver
)
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
;
1995 string
get_type() override
{ return "bucket.instance"; }
1997 RGWMetadataObject
*get_meta_obj(JSONObj
*jo
, const obj_version
& objv
, const ceph::real_time
& mtime
) override
{
1998 RGWBucketCompleteInfo bci
;
2001 decode_json_obj(bci
, jo
);
2002 } catch (JSONDecoder::err
& e
) {
2006 return new RGWBucketInstanceMetadataObject(bci
, objv
, mtime
);
2009 int do_get(RGWSI_MetaBackend_Handler::Op
*op
, string
& entry
, RGWMetadataObject
**obj
, optional_yield y
, const DoutPrefixProvider
*dpp
) override
{
2010 RGWBucketCompleteInfo bci
;
2013 RGWSI_Bucket_BI_Ctx
ctx(op
->ctx());
2015 int ret
= svc
.bucket
->read_bucket_instance_info(ctx
, entry
, &bci
.info
, &mtime
, &bci
.attrs
, y
, dpp
);
2019 RGWBucketInstanceMetadataObject
*mdo
= new RGWBucketInstanceMetadataObject(bci
, bci
.info
.objv_tracker
.read_version
, mtime
);
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
;
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
;
2035 RGWSI_Bucket_BI_Ctx
ctx(op
->ctx());
2037 int ret
= read_bucket_instance_entry(ctx
, entry
, &bci
, nullptr, y
, dpp
);
2038 if (ret
< 0 && ret
!= -ENOENT
)
2041 return svc
.bucket
->remove_bucket_instance_info(ctx
, entry
, bci
.info
, &bci
.info
.objv_tracker
, y
, dpp
);
2044 int call(std::function
<int(RGWSI_Bucket_BI_Ctx
& ctx
)> f
) {
2045 return call(nullopt
, f
);
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());
2057 class RGWMetadataHandlerPut_BucketInstance
: public RGWMetadataHandlerPut_SObj
2060 RGWBucketInstanceMetadataHandler
*bihandler
;
2061 RGWBucketInstanceMetadataObject
*obj
;
2063 RGWMetadataHandlerPut_BucketInstance(CephContext
*_cct
,
2064 RGWBucketInstanceMetadataHandler
*_handler
,
2065 RGWSI_MetaBackend_Handler::Op
*_op
, string
& entry
,
2066 RGWMetadataObject
*_obj
, RGWObjVersionTracker
& objv_tracker
,
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
);
2072 auto& bci
= obj
->get_bci();
2073 obj
->set_pattrs(&bci
.attrs
);
2076 void encode_obj(bufferlist
*bl
) override
{
2077 obj
->get_bucket_info().encode(*bl
);
2080 int put_check(const DoutPrefixProvider
*dpp
) override
;
2081 int put_checked(const DoutPrefixProvider
*dpp
) override
;
2082 int put_post(const DoutPrefixProvider
*dpp
) override
;
2085 int RGWBucketInstanceMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op
*op
,
2087 RGWMetadataObject
*obj
,
2088 RGWObjVersionTracker
& objv_tracker
,
2090 const DoutPrefixProvider
*dpp
,
2091 RGWMDLogSyncType type
, bool from_remote_zone
)
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
);
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
;
2105 layout
.current_index
.layout
.type
=
2106 type
.value_or(rgw::BucketIndexType::Normal
);
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
;
2114 layout
.current_index
.layout
.normal
.num_shards
=
2115 zone
.bucket_index_max_shards
;
2118 if (layout
.current_index
.layout
.type
== rgw::BucketIndexType::Normal
) {
2119 layout
.logs
.push_back(log_layout_from_index(0, layout
.current_index
));
2123 int RGWMetadataHandlerPut_BucketInstance::put_check(const DoutPrefixProvider
*dpp
)
2127 RGWBucketCompleteInfo
& bci
= obj
->get_bci();
2129 RGWBucketInstanceMetadataObject
*orig_obj
= static_cast<RGWBucketInstanceMetadataObject
*>(old_obj
);
2131 RGWBucketCompleteInfo
*old_bci
= (orig_obj
? &orig_obj
->get_bci() : nullptr);
2133 const bool exists
= (!!orig_obj
);
2135 if (from_remote_zone
) {
2136 // don't sync bucket layout changes
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
);
2144 bci
.info
.layout
= old_bci
->info
.layout
;
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 */
2152 string bucket_instance
;
2153 parse_bucket(entry
, &tenant_name
, &bucket_name
, &bucket_instance
);
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
);
2163 ldpp_dout(dpp
, 0) << "ERROR: select_bucket_placement() returned " << ret
<< dendl
;
2167 bci
.info
.layout
.current_index
.layout
.type
= rule_info
.index_type
;
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
;
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
;
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
;
2185 int RGWMetadataHandlerPut_BucketInstance::put_checked(const DoutPrefixProvider
*dpp
)
2187 RGWBucketInstanceMetadataObject
*orig_obj
= static_cast<RGWBucketInstanceMetadataObject
*>(old_obj
);
2189 RGWBucketInfo
*orig_info
= (orig_obj
? &orig_obj
->get_bucket_info() : nullptr);
2191 auto& info
= obj
->get_bucket_info();
2192 auto mtime
= obj
->get_mtime();
2193 auto pattrs
= obj
->get_pattrs();
2195 RGWSI_Bucket_BI_Ctx
ctx(op
->ctx());
2197 return bihandler
->svc
.bucket
->store_bucket_instance_info(ctx
,
2208 int RGWMetadataHandlerPut_BucketInstance::put_post(const DoutPrefixProvider
*dpp
)
2210 RGWBucketCompleteInfo
& bci
= obj
->get_bci();
2212 objv_tracker
= bci
.info
.objv_tracker
;
2214 int ret
= bihandler
->svc
.bi
->init_index(dpp
, bci
.info
, bci
.info
.layout
.current_index
);
2219 /* update lifecyle policy */
2221 std::unique_ptr
<rgw::sal::Bucket
> bucket
;
2222 ret
= bihandler
->driver
->get_bucket(nullptr, bci
.info
, &bucket
);
2224 ldpp_dout(dpp
, 0) << __func__
<< " failed to get_bucket(...) for "
2225 << bci
.info
.bucket
.name
2230 auto lc
= bihandler
->driver
->get_rgwlc();
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);
2237 ldpp_dout(dpp
, 0) << __func__
<< " failed to set lc config for "
2238 << bci
.info
.bucket
.name
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 */);
2247 ldpp_dout(dpp
, 0) << __func__
<< " failed to remove lc config for "
2248 << bci
.info
.bucket
.name
2255 return STATUS_APPLIED
;
2258 class RGWArchiveBucketInstanceMetadataHandler
: public RGWBucketInstanceMetadataHandler
{
2260 RGWArchiveBucketInstanceMetadataHandler(rgw::sal::Driver
* driver
)
2261 : RGWBucketInstanceMetadataHandler(driver
) {}
2263 // N.B. replication of lifecycle policy relies on logic in RGWBucketInstanceMetadataHandler::do_put(...), override with caution
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
;
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())
2278 svc
.zone
= zone_svc
;
2279 svc
.bucket
= bucket_svc
;
2280 svc
.bucket_sync
= bucket_sync_svc
;
2282 svc
.user
= user_svc
;
2285 void RGWBucketCtl::init(RGWUserCtl
*user_ctl
,
2286 RGWBucketMetadataHandler
*_bm_handler
,
2287 RGWBucketInstanceMetadataHandler
*_bmi_handler
,
2288 RGWDataChangesLog
*datalog
,
2289 const DoutPrefixProvider
*dpp
)
2291 ctl
.user
= user_ctl
;
2293 bm_handler
= _bm_handler
;
2294 bmi_handler
= _bmi_handler
;
2296 bucket_be_handler
= bm_handler
->get_be_handler();
2297 bi_be_handler
= bmi_handler
->get_be_handler();
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
);
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
};
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
)
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
),
2323 params
.objv_tracker
,
2329 params
.refresh_version
);
2333 int RGWBucketCtl::store_bucket_entrypoint_info(const rgw_bucket
& bucket
,
2334 RGWBucketEntryPoint
& info
,
2336 const DoutPrefixProvider
*dpp
,
2337 const Bucket::PutParams
& params
)
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
),
2346 params
.objv_tracker
,
2352 int RGWBucketCtl::remove_bucket_entrypoint_info(const rgw_bucket
& bucket
,
2354 const DoutPrefixProvider
*dpp
,
2355 const Bucket::RemoveParams
& params
)
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
,
2366 int RGWBucketCtl::read_bucket_instance_info(const rgw_bucket
& bucket
,
2367 RGWBucketInfo
*info
,
2369 const DoutPrefixProvider
*dpp
,
2370 const BucketInstance::GetParams
& params
)
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
),
2381 params
.refresh_version
);
2388 if (params
.objv_tracker
) {
2389 *params
.objv_tracker
= info
->objv_tracker
;
2395 int RGWBucketCtl::read_bucket_info(const rgw_bucket
& bucket
,
2396 RGWBucketInfo
*info
,
2398 const DoutPrefixProvider
*dpp
,
2399 const BucketInstance::GetParams
& params
,
2400 RGWObjVersionTracker
*ep_objv_tracker
)
2402 const rgw_bucket
*b
= &bucket
;
2404 std::optional
<RGWBucketEntryPoint
> ep
;
2406 if (b
->bucket_id
.empty()) {
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
));
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
),
2427 params
.refresh_version
);
2434 if (params
.objv_tracker
) {
2435 *params
.objv_tracker
= info
->objv_tracker
;
2441 int RGWBucketCtl::do_store_bucket_instance_info(RGWSI_Bucket_BI_Ctx
& ctx
,
2442 const rgw_bucket
& bucket
,
2443 RGWBucketInfo
& info
,
2445 const DoutPrefixProvider
*dpp
,
2446 const BucketInstance::PutParams
& params
)
2448 if (params
.objv_tracker
) {
2449 info
.objv_tracker
= *params
.objv_tracker
;
2452 return svc
.bucket
->store_bucket_instance_info(ctx
,
2453 RGWSI_Bucket::get_bi_meta_key(bucket
),
2463 int RGWBucketCtl::store_bucket_instance_info(const rgw_bucket
& bucket
,
2464 RGWBucketInfo
& info
,
2466 const DoutPrefixProvider
*dpp
,
2467 const BucketInstance::PutParams
& params
)
2469 return bmi_handler
->call([&](RGWSI_Bucket_BI_Ctx
& ctx
) {
2470 return do_store_bucket_instance_info(ctx
, bucket
, info
, y
, dpp
, params
);
2474 int RGWBucketCtl::remove_bucket_instance_info(const rgw_bucket
& bucket
,
2475 RGWBucketInfo
& info
,
2477 const DoutPrefixProvider
*dpp
,
2478 const BucketInstance::RemoveParams
& params
)
2480 if (params
.objv_tracker
) {
2481 info
.objv_tracker
= *params
.objv_tracker
;
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
),
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
)
2503 bool create_head
= !info
.has_instance_obj
|| create_entry_point
;
2505 int ret
= svc
.bucket
->store_bucket_instance_info(ctx
.bi
,
2506 RGWSI_Bucket::get_bi_meta_key(info
.bucket
),
2517 return 0; /* done! */
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
;
2528 ot
.generate_new_write_ver(cct
);
2530 *pep_objv
= ot
.write_version
;
2533 ret
= svc
.bucket
->store_bucket_entrypoint_info(ctx
.ep
,
2534 RGWSI_Bucket::get_entrypoint_meta_key(info
.bucket
),
2547 int RGWBucketCtl::convert_old_bucket_info(RGWSI_Bucket_X_Ctx
& ctx
,
2548 const rgw_bucket
& bucket
,
2550 const DoutPrefixProvider
*dpp
)
2552 RGWBucketEntryPoint entry_point
;
2554 RGWObjVersionTracker ot
;
2555 map
<string
, bufferlist
> attrs
;
2557 auto cct
= svc
.bucket
->ctx();
2559 ldpp_dout(dpp
, 10) << "RGWRados::convert_old_bucket_info(): bucket=" << bucket
<< dendl
;
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
);
2565 ldpp_dout(dpp
, 0) << "ERROR: get_bucket_entrypoint_info() returned " << ret
<< " bucket=" << bucket
<< dendl
;
2569 if (!entry_point
.has_bucket_info
) {
2570 /* already converted! */
2574 info
= entry_point
.old_bucket_info
;
2576 ot
.generate_new_write_ver(cct
);
2578 ret
= do_store_linked_bucket_info(ctx
, info
, nullptr, false, ep_mtime
, &ot
.write_version
, &attrs
, true, y
, dpp
);
2580 ldpp_dout(dpp
, 0) << "ERROR: failed to put_linked_bucket_info(): " << ret
<< dendl
;
2587 int RGWBucketCtl::set_bucket_instance_attrs(RGWBucketInfo
& bucket_info
,
2588 map
<string
, bufferlist
>& attrs
,
2589 RGWObjVersionTracker
*objv_tracker
,
2591 const DoutPrefixProvider
*dpp
)
2593 return call([&](RGWSI_Bucket_X_Ctx
& ctx
) {
2594 rgw_bucket
& bucket
= bucket_info
.bucket
;
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
);
2600 ldpp_dout(dpp
, 0) << "ERROR: failed converting old bucket info: " << ret
<< dendl
;
2605 return do_store_bucket_instance_info(ctx
.bi
,
2610 BucketInstance::PutParams().set_attrs(&attrs
)
2611 .set_objv_tracker(objv_tracker
)
2612 .set_orig_info(&bucket_info
));
2617 int RGWBucketCtl::link_bucket(const rgw_user
& user_id
,
2618 const rgw_bucket
& bucket
,
2619 ceph::real_time creation_time
,
2621 const DoutPrefixProvider
*dpp
,
2622 bool update_entrypoint
,
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
);
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
,
2638 const DoutPrefixProvider
*dpp
)
2642 RGWBucketEntryPoint ep
;
2643 RGWObjVersionTracker ot
;
2644 RGWObjVersionTracker
& rot
= (pinfo
) ? pinfo
->ep_objv
: ot
;
2645 map
<string
, bufferlist
> attrs
, *pattrs
= nullptr;
2648 if (update_entrypoint
) {
2649 meta_key
= RGWSI_Bucket::get_entrypoint_meta_key(bucket
);
2652 pattrs
= &pinfo
->attrs
;
2654 ret
= svc
.bucket
->read_bucket_entrypoint_info(ctx
,
2659 if (ret
< 0 && ret
!= -ENOENT
) {
2660 ldpp_dout(dpp
, 0) << "ERROR: read_bucket_entrypoint_info() returned: "
2661 << cpp_strerror(-ret
) << dendl
;
2667 ret
= svc
.user
->add_bucket(dpp
, user_id
, bucket
, creation_time
, y
);
2669 ldpp_dout(dpp
, 0) << "ERROR: error adding bucket to user directory:"
2670 << " user=" << user_id
2671 << " bucket=" << bucket
2672 << " err=" << cpp_strerror(-ret
)
2677 if (!update_entrypoint
)
2683 ret
= svc
.bucket
->store_bucket_entrypoint_info(
2684 ctx
, meta_key
, ep
, false, real_time(), pattrs
, &rot
, y
, dpp
);
2691 int r
= do_unlink_bucket(ctx
, user_id
, bucket
, true, y
, dpp
);
2693 ldpp_dout(dpp
, 0) << "ERROR: failed unlinking bucket on error cleanup: "
2694 << cpp_strerror(-r
) << dendl
;
2699 int RGWBucketCtl::unlink_bucket(const rgw_user
& user_id
, const rgw_bucket
& bucket
, optional_yield y
, const DoutPrefixProvider
*dpp
, bool update_entrypoint
)
2701 return bm_handler
->call([&](RGWSI_Bucket_EP_Ctx
& ctx
) {
2702 return do_unlink_bucket(ctx
, user_id
, bucket
, update_entrypoint
, y
, dpp
);
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
,
2711 const DoutPrefixProvider
*dpp
)
2713 int ret
= svc
.user
->remove_bucket(dpp
, user_id
, bucket
, y
);
2715 ldpp_dout(dpp
, 0) << "ERROR: error removing bucket from directory: "
2716 << cpp_strerror(-ret
)<< dendl
;
2719 if (!update_entrypoint
)
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
);
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
;
2741 return svc
.bucket
->store_bucket_entrypoint_info(ctx
, meta_key
, ep
, false, real_time(), &attrs
, &ot
, y
, dpp
);
2744 int RGWBucketCtl::read_bucket_stats(const rgw_bucket
& bucket
,
2745 RGWBucketEnt
*result
,
2747 const DoutPrefixProvider
*dpp
)
2749 return call([&](RGWSI_Bucket_X_Ctx
& ctx
) {
2750 return svc
.bucket
->read_bucket_stats(ctx
, bucket
, result
, y
, dpp
);
2754 int RGWBucketCtl::read_buckets_stats(map
<string
, RGWBucketEnt
>& m
,
2755 optional_yield y
, const DoutPrefixProvider
*dpp
)
2757 return call([&](RGWSI_Bucket_X_Ctx
& ctx
) {
2758 return svc
.bucket
->read_buckets_stats(ctx
, m
, y
, dpp
);
2762 int RGWBucketCtl::sync_user_stats(const DoutPrefixProvider
*dpp
,
2763 const rgw_user
& user_id
,
2764 const RGWBucketInfo
& bucket_info
,
2772 int r
= svc
.bi
->read_stats(dpp
, bucket_info
, pent
, y
);
2774 ldpp_dout(dpp
, 20) << __func__
<< "(): failed to read bucket stats (r=" << r
<< ")" << dendl
;
2778 return svc
.user
->flush_bucket_stats(dpp
, user_id
, *pent
, y
);
2781 int RGWBucketCtl::get_sync_policy_handler(std::optional
<rgw_zone_id
> zone
,
2782 std::optional
<rgw_bucket
> bucket
,
2783 RGWBucketSyncPolicyHandlerRef
*phandler
,
2785 const DoutPrefixProvider
*dpp
)
2787 int r
= call([&](RGWSI_Bucket_X_Ctx
& ctx
) {
2788 return svc
.bucket_sync
->get_policy_handler(ctx
, zone
, bucket
, phandler
, y
, dpp
);
2791 ldpp_dout(dpp
, 20) << __func__
<< "(): failed to get policy handler for bucket=" << bucket
<< " (r=" << r
<< ")" << dendl
;
2797 int RGWBucketCtl::bucket_exports_data(const rgw_bucket
& bucket
,
2799 const DoutPrefixProvider
*dpp
)
2802 RGWBucketSyncPolicyHandlerRef handler
;
2804 int r
= get_sync_policy_handler(std::nullopt
, bucket
, &handler
, y
, dpp
);
2809 return handler
->bucket_exports_data();
2812 int RGWBucketCtl::bucket_imports_data(const rgw_bucket
& bucket
,
2813 optional_yield y
, const DoutPrefixProvider
*dpp
)
2816 RGWBucketSyncPolicyHandlerRef handler
;
2818 int r
= get_sync_policy_handler(std::nullopt
, bucket
, &handler
, y
, dpp
);
2823 return handler
->bucket_imports_data();
2826 RGWBucketMetadataHandlerBase
* RGWBucketMetaHandlerAllocator::alloc()
2828 return new RGWBucketMetadataHandler();
2831 RGWBucketInstanceMetadataHandlerBase
* RGWBucketInstanceMetaHandlerAllocator::alloc(rgw::sal::Driver
* driver
)
2833 return new RGWBucketInstanceMetadataHandler(driver
);
2836 RGWBucketMetadataHandlerBase
* RGWArchiveBucketMetaHandlerAllocator::alloc()
2838 return new RGWArchiveBucketMetadataHandler();
2841 RGWBucketInstanceMetadataHandlerBase
* RGWArchiveBucketInstanceMetaHandlerAllocator::alloc(rgw::sal::Driver
* driver
)
2843 return new RGWArchiveBucketInstanceMetadataHandler(driver
);
2847 void RGWBucketEntryPoint::generate_test_instances(list
<RGWBucketEntryPoint
*>& o
)
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)});
2855 o
.push_back(new RGWBucketEntryPoint
);
2858 void RGWBucketEntryPoint::dump(Formatter
*f
) const
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
);
2871 void RGWBucketEntryPoint::decode_json(JSONObj
*obj
) {
2872 JSONDecoder::decode_json("bucket", bucket
, obj
);
2873 JSONDecoder::decode_json("owner", owner
, obj
);
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
);