1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
5 #include "rgw_realm_watcher.h"
6 #include "rgw_sal_config.h"
9 #include "services/svc_zone.h"
11 #define dout_context g_ceph_context
12 #define dout_subsys ceph_subsys_rgw
15 using namespace rgw_zone_defaults
;
17 RGWMetaSyncStatusManager::~RGWMetaSyncStatusManager(){}
23 /// Generate a random uuid for realm/period/zonegroup/zone ids
24 static std::string
gen_random_uuid()
27 uuid
.generate_random();
28 return uuid
.to_string();
31 void RGWDefaultZoneGroupInfo::dump(Formatter
*f
) const {
32 encode_json("default_zonegroup", default_zonegroup
, f
);
35 void RGWDefaultZoneGroupInfo::decode_json(JSONObj
*obj
) {
37 JSONDecoder::decode_json("default_zonegroup", default_zonegroup
, obj
);
38 /* backward compatability with region */
39 if (default_zonegroup
.empty()) {
40 JSONDecoder::decode_json("default_region", default_zonegroup
, obj
);
44 int RGWZoneGroup::create_default(const DoutPrefixProvider
*dpp
, optional_yield y
, bool old_format
)
46 name
= default_zonegroup_name
;
47 api_name
= default_zonegroup_name
;
50 RGWZoneGroupPlacementTarget placement_target
;
51 placement_target
.name
= "default-placement";
52 placement_targets
[placement_target
.name
] = placement_target
;
53 default_placement
.name
= "default-placement";
55 RGWZoneParams
zone_params(default_zone_name
);
57 int r
= zone_params
.init(dpp
, cct
, sysobj_svc
, y
, false);
59 ldpp_dout(dpp
, 0) << "create_default: error initializing zone params: " << cpp_strerror(-r
) << dendl
;
63 r
= zone_params
.create_default(dpp
, y
);
64 if (r
< 0 && r
!= -EEXIST
) {
65 ldpp_dout(dpp
, 0) << "create_default: error in create_default zone params: " << cpp_strerror(-r
) << dendl
;
67 } else if (r
== -EEXIST
) {
68 ldpp_dout(dpp
, 10) << "zone_params::create_default() returned -EEXIST, we raced with another default zone_params creation" << dendl
;
69 zone_params
.clear_id();
70 r
= zone_params
.init(dpp
, cct
, sysobj_svc
, y
);
72 ldpp_dout(dpp
, 0) << "create_default: error in init existing zone params: " << cpp_strerror(-r
) << dendl
;
75 ldpp_dout(dpp
, 20) << "zone_params::create_default() " << zone_params
.get_name() << " id " << zone_params
.get_id()
79 RGWZone
& default_zone
= zones
[zone_params
.get_id()];
80 default_zone
.name
= zone_params
.get_name();
81 default_zone
.id
= zone_params
.get_id();
82 master_zone
= default_zone
.id
;
84 // enable all supported features
85 enabled_features
.insert(rgw::zone_features::supported
.begin(),
86 rgw::zone_features::supported
.end());
87 default_zone
.supported_features
= enabled_features
;
90 if (r
< 0 && r
!= -EEXIST
) {
91 ldpp_dout(dpp
, 0) << "error storing zone group info: " << cpp_strerror(-r
) << dendl
;
96 ldpp_dout(dpp
, 10) << "create_default() returned -EEXIST, we raced with another zonegroup creation" << dendl
;
98 r
= init(dpp
, cct
, sysobj_svc
, y
);
108 post_process_params(dpp
, y
);
113 int RGWZoneGroup::equals(const string
& other_zonegroup
) const
115 if (is_master
&& other_zonegroup
.empty())
118 return (id
== other_zonegroup
);
121 int RGWZoneGroup::add_zone(const DoutPrefixProvider
*dpp
,
122 const RGWZoneParams
& zone_params
, bool *is_master
, bool *read_only
,
123 const list
<string
>& endpoints
, const string
*ptier_type
,
124 bool *psync_from_all
, list
<string
>& sync_from
, list
<string
>& sync_from_rm
,
125 string
*predirect_zone
, std::optional
<int> bucket_index_max_shards
,
126 RGWSyncModulesManager
*sync_mgr
,
127 const rgw::zone_features::set
& enable_features
,
128 const rgw::zone_features::set
& disable_features
,
131 auto& zone_id
= zone_params
.get_id();
132 auto& zone_name
= zone_params
.get_name();
134 // check for duplicate zone name on insert
135 if (!zones
.count(zone_id
)) {
136 for (const auto& zone
: zones
) {
137 if (zone
.second
.name
== zone_name
) {
138 ldpp_dout(dpp
, 0) << "ERROR: found existing zone name " << zone_name
139 << " (" << zone
.first
<< ") in zonegroup " << get_name() << dendl
;
147 if (!master_zone
.empty() && master_zone
!= zone_id
) {
148 ldpp_dout(dpp
, 0) << "NOTICE: overriding master zone: " << master_zone
<< dendl
;
150 master_zone
= zone_id
;
151 } else if (master_zone
== zone_id
) {
156 RGWZone
& zone
= zones
[zone_id
];
157 zone
.name
= zone_name
;
159 if (!endpoints
.empty()) {
160 zone
.endpoints
= endpoints
;
163 zone
.read_only
= *read_only
;
166 zone
.tier_type
= *ptier_type
;
167 if (!sync_mgr
->get_module(*ptier_type
, nullptr)) {
168 ldpp_dout(dpp
, 0) << "ERROR: could not found sync module: " << *ptier_type
169 << ", valid sync modules: "
170 << sync_mgr
->get_registered_module_names()
176 if (psync_from_all
) {
177 zone
.sync_from_all
= *psync_from_all
;
180 if (predirect_zone
) {
181 zone
.redirect_zone
= *predirect_zone
;
184 if (bucket_index_max_shards
) {
185 zone
.bucket_index_max_shards
= *bucket_index_max_shards
;
188 for (auto add
: sync_from
) {
189 zone
.sync_from
.insert(add
);
192 for (auto rm
: sync_from_rm
) {
193 zone
.sync_from
.erase(rm
);
196 zone
.supported_features
.insert(enable_features
.begin(),
197 enable_features
.end());
199 for (const auto& feature
: disable_features
) {
200 if (enabled_features
.contains(feature
)) {
201 lderr(cct
) << "ERROR: Cannot disable zone feature \"" << feature
202 << "\" until it's been disabled in zonegroup " << name
<< dendl
;
205 auto i
= zone
.supported_features
.find(feature
);
206 if (i
== zone
.supported_features
.end()) {
207 ldout(cct
, 1) << "WARNING: zone feature \"" << feature
208 << "\" was not enabled in zone " << zone
.name
<< dendl
;
211 zone
.supported_features
.erase(i
);
214 post_process_params(dpp
, y
);
216 return update(dpp
,y
);
220 int RGWZoneGroup::rename_zone(const DoutPrefixProvider
*dpp
,
221 const RGWZoneParams
& zone_params
,
224 RGWZone
& zone
= zones
[zone_params
.get_id()];
225 zone
.name
= zone_params
.get_name();
227 return update(dpp
, y
);
230 void RGWZoneGroup::post_process_params(const DoutPrefixProvider
*dpp
, optional_yield y
)
232 bool log_data
= zones
.size() > 1;
234 if (master_zone
.empty()) {
235 auto iter
= zones
.begin();
236 if (iter
!= zones
.end()) {
237 master_zone
= iter
->first
;
241 for (auto& item
: zones
) {
242 RGWZone
& zone
= item
.second
;
243 zone
.log_data
= log_data
;
245 RGWZoneParams
zone_params(zone
.id
, zone
.name
);
246 int ret
= zone_params
.init(dpp
, cct
, sysobj_svc
, y
);
248 ldpp_dout(dpp
, 0) << "WARNING: could not read zone params for zone id=" << zone
.id
<< " name=" << zone
.name
<< dendl
;
252 for (auto& pitem
: zone_params
.placement_pools
) {
253 const string
& placement_name
= pitem
.first
;
254 if (placement_targets
.find(placement_name
) == placement_targets
.end()) {
255 RGWZoneGroupPlacementTarget placement_target
;
256 placement_target
.name
= placement_name
;
257 placement_targets
[placement_name
] = placement_target
;
262 if (default_placement
.empty() && !placement_targets
.empty()) {
263 default_placement
.init(placement_targets
.begin()->first
, RGW_STORAGE_CLASS_STANDARD
);
267 int RGWZoneGroup::remove_zone(const DoutPrefixProvider
*dpp
, const std::string
& zone_id
, optional_yield y
)
269 auto iter
= zones
.find(zone_id
);
270 if (iter
== zones
.end()) {
271 ldpp_dout(dpp
, 0) << "zone id " << zone_id
<< " is not a part of zonegroup "
278 post_process_params(dpp
, y
);
280 return update(dpp
, y
);
283 void RGWDefaultSystemMetaObjInfo::dump(Formatter
*f
) const {
284 encode_json("default_id", default_id
, f
);
287 void RGWDefaultSystemMetaObjInfo::decode_json(JSONObj
*obj
) {
288 JSONDecoder::decode_json("default_id", default_id
, obj
);
291 int RGWSystemMetaObj::rename(const DoutPrefixProvider
*dpp
, const string
& new_name
, optional_yield y
)
294 int ret
= read_id(dpp
, new_name
, new_id
, y
);
298 if (ret
< 0 && ret
!= -ENOENT
) {
299 ldpp_dout(dpp
, 0) << "Error read_id " << new_name
<< ": " << cpp_strerror(-ret
) << dendl
;
302 string old_name
= name
;
304 ret
= update(dpp
, y
);
306 ldpp_dout(dpp
, 0) << "Error storing new obj info " << new_name
<< ": " << cpp_strerror(-ret
) << dendl
;
309 ret
= store_name(dpp
, true, y
);
311 ldpp_dout(dpp
, 0) << "Error storing new name " << new_name
<< ": " << cpp_strerror(-ret
) << dendl
;
314 /* delete old name */
315 rgw_pool
pool(get_pool(cct
));
316 string oid
= get_names_oid_prefix() + old_name
;
317 rgw_raw_obj
old_name_obj(pool
, oid
);
318 auto sysobj
= sysobj_svc
->get_obj(old_name_obj
);
319 ret
= sysobj
.wop().remove(dpp
, y
);
321 ldpp_dout(dpp
, 0) << "Error delete old obj name " << old_name
<< ": " << cpp_strerror(-ret
) << dendl
;
328 int RGWSystemMetaObj::read(const DoutPrefixProvider
*dpp
, optional_yield y
)
330 int ret
= read_id(dpp
, name
, id
, y
);
335 return read_info(dpp
, id
, y
);
338 int RGWZoneParams::create_default(const DoutPrefixProvider
*dpp
, optional_yield y
, bool old_format
)
340 name
= default_zone_name
;
342 int r
= create(dpp
, y
);
354 const string
& RGWZoneParams::get_compression_type(const rgw_placement_rule
& placement_rule
) const
356 static const std::string NONE
{"none"};
357 auto p
= placement_pools
.find(placement_rule
.name
);
358 if (p
== placement_pools
.end()) {
361 const auto& type
= p
->second
.get_compression_type(placement_rule
.get_storage_class());
362 return !type
.empty() ? type
: NONE
;
365 // run an MD5 hash on the zone_id and return the first 32 bits
366 static uint32_t gen_short_zone_id(const std::string zone_id
)
368 unsigned char md5
[CEPH_CRYPTO_MD5_DIGESTSIZE
];
370 // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes
371 hash
.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
);
372 hash
.Update((const unsigned char *)zone_id
.c_str(), zone_id
.size());
376 memcpy((char *)&short_id
, md5
, sizeof(short_id
));
377 return std::max(short_id
, 1u);
380 int RGWPeriodMap::update(const RGWZoneGroup
& zonegroup
, CephContext
*cct
)
382 if (zonegroup
.is_master_zonegroup() && (!master_zonegroup
.empty() && zonegroup
.get_id() != master_zonegroup
)) {
383 ldout(cct
,0) << "Error updating periodmap, multiple master zonegroups configured "<< dendl
;
384 ldout(cct
,0) << "master zonegroup: " << master_zonegroup
<< " and " << zonegroup
.get_id() <<dendl
;
387 map
<string
, RGWZoneGroup
>::iterator iter
= zonegroups
.find(zonegroup
.get_id());
388 if (iter
!= zonegroups
.end()) {
389 RGWZoneGroup
& old_zonegroup
= iter
->second
;
390 if (!old_zonegroup
.api_name
.empty()) {
391 zonegroups_by_api
.erase(old_zonegroup
.api_name
);
394 zonegroups
[zonegroup
.get_id()] = zonegroup
;
396 if (!zonegroup
.api_name
.empty()) {
397 zonegroups_by_api
[zonegroup
.api_name
] = zonegroup
;
400 if (zonegroup
.is_master_zonegroup()) {
401 master_zonegroup
= zonegroup
.get_id();
402 } else if (master_zonegroup
== zonegroup
.get_id()) {
403 master_zonegroup
= "";
406 for (auto& i
: zonegroup
.zones
) {
407 auto& zone
= i
.second
;
408 if (short_zone_ids
.find(zone
.id
) != short_zone_ids
.end()) {
411 // calculate the zone's short id
412 uint32_t short_id
= gen_short_zone_id(zone
.id
);
414 // search for an existing zone with the same short id
415 for (auto& s
: short_zone_ids
) {
416 if (s
.second
== short_id
) {
417 ldout(cct
, 0) << "New zone '" << zone
.name
<< "' (" << zone
.id
418 << ") generates the same short_zone_id " << short_id
419 << " as existing zone id " << s
.first
<< dendl
;
424 short_zone_ids
[zone
.id
] = short_id
;
430 uint32_t RGWPeriodMap::get_zone_short_id(const string
& zone_id
) const
432 auto i
= short_zone_ids
.find(zone_id
);
433 if (i
== short_zone_ids
.end()) {
439 bool RGWPeriodMap::find_zone_by_name(const string
& zone_name
,
440 RGWZoneGroup
*zonegroup
,
443 for (auto& iter
: zonegroups
) {
444 auto& zg
= iter
.second
;
445 for (auto& ziter
: zg
.zones
) {
446 auto& z
= ziter
.second
;
448 if (z
.name
== zone_name
) {
461 int read_realm(const DoutPrefixProvider
* dpp
, optional_yield y
,
462 sal::ConfigStore
* cfgstore
,
463 std::string_view realm_id
,
464 std::string_view realm_name
,
466 std::unique_ptr
<sal::RealmWriter
>* writer
)
468 if (!realm_id
.empty()) {
469 return cfgstore
->read_realm_by_id(dpp
, y
, realm_id
, info
, writer
);
471 if (!realm_name
.empty()) {
472 return cfgstore
->read_realm_by_name(dpp
, y
, realm_name
, info
, writer
);
474 return cfgstore
->read_default_realm(dpp
, y
, info
, writer
);
477 int create_realm(const DoutPrefixProvider
* dpp
, optional_yield y
,
478 sal::ConfigStore
* cfgstore
, bool exclusive
,
480 std::unique_ptr
<sal::RealmWriter
>* writer_out
)
482 if (info
.name
.empty()) {
483 ldpp_dout(dpp
, -1) << __func__
<< " requires a realm name" << dendl
;
486 if (info
.id
.empty()) {
487 info
.id
= gen_random_uuid();
490 // if the realm already has a current_period, just make sure it exists
491 std::optional
<RGWPeriod
> period
;
492 if (!info
.current_period
.empty()) {
494 int r
= cfgstore
->read_period(dpp
, y
, info
.current_period
,
495 std::nullopt
, *period
);
497 ldpp_dout(dpp
, -1) << __func__
<< " failed to read realm's current_period="
498 << info
.current_period
<< " with " << cpp_strerror(r
) << dendl
;
504 std::unique_ptr
<sal::RealmWriter
> writer
;
505 int r
= cfgstore
->create_realm(dpp
, y
, exclusive
, info
, &writer
);
511 // initialize and exclusive-create the initial period
513 period
->id
= gen_random_uuid();
514 period
->period_map
.id
= period
->id
;
515 period
->epoch
= FIRST_EPOCH
;
516 period
->realm_id
= info
.id
;
517 period
->realm_name
= info
.name
;
519 r
= cfgstore
->create_period(dpp
, y
, true, *period
);
521 ldpp_dout(dpp
, -1) << __func__
<< " failed to create the initial period id="
522 << period
->id
<< " for realm " << info
.name
523 << " with " << cpp_strerror(r
) << dendl
;
528 // update the realm's current_period
529 r
= realm_set_current_period(dpp
, y
, cfgstore
, *writer
, info
, *period
);
534 // try to set as default. may race with another create, so pass exclusive=true
535 // so we don't override an existing default
536 r
= set_default_realm(dpp
, y
, cfgstore
, info
, true);
537 if (r
< 0 && r
!= -EEXIST
) {
538 ldpp_dout(dpp
, 0) << "WARNING: failed to set realm as default: "
539 << cpp_strerror(r
) << dendl
;
543 *writer_out
= std::move(writer
);
548 int set_default_realm(const DoutPrefixProvider
* dpp
, optional_yield y
,
549 sal::ConfigStore
* cfgstore
, const RGWRealm
& info
,
552 return cfgstore
->write_default_realm_id(dpp
, y
, exclusive
, info
.id
);
555 int realm_set_current_period(const DoutPrefixProvider
* dpp
, optional_yield y
,
556 sal::ConfigStore
* cfgstore
,
557 sal::RealmWriter
& writer
, RGWRealm
& realm
,
558 const RGWPeriod
& period
)
560 // update realm epoch to match the period's
561 if (realm
.epoch
> period
.realm_epoch
) {
562 ldpp_dout(dpp
, -1) << __func__
<< " with old realm epoch "
563 << period
.realm_epoch
<< ", current epoch=" << realm
.epoch
<< dendl
;
566 if (realm
.epoch
== period
.realm_epoch
&& realm
.current_period
!= period
.id
) {
567 ldpp_dout(dpp
, -1) << __func__
<< " with same realm epoch "
568 << period
.realm_epoch
<< ", but different period id "
569 << period
.id
<< " != " << realm
.current_period
<< dendl
;
573 realm
.epoch
= period
.realm_epoch
;
574 realm
.current_period
= period
.id
;
576 // update the realm object
577 int r
= writer
.write(dpp
, y
, realm
);
579 ldpp_dout(dpp
, -1) << __func__
<< " failed to overwrite realm "
580 << realm
.name
<< " with " << cpp_strerror(r
) << dendl
;
584 // reflect the zonegroup and period config
585 (void) reflect_period(dpp
, y
, cfgstore
, period
);
589 int reflect_period(const DoutPrefixProvider
* dpp
, optional_yield y
,
590 sal::ConfigStore
* cfgstore
, const RGWPeriod
& info
)
592 // overwrite the local period config and zonegroup objects
593 constexpr bool exclusive
= false;
595 int r
= cfgstore
->write_period_config(dpp
, y
, exclusive
, info
.realm_id
,
598 ldpp_dout(dpp
, -1) << __func__
<< " failed to store period config for realm id="
599 << info
.realm_id
<< " with " << cpp_strerror(r
) << dendl
;
603 for (auto& [zonegroup_id
, zonegroup
] : info
.period_map
.zonegroups
) {
604 r
= cfgstore
->create_zonegroup(dpp
, y
, exclusive
, zonegroup
, nullptr);
606 ldpp_dout(dpp
, -1) << __func__
<< " failed to store zonegroup id="
607 << zonegroup_id
<< " with " << cpp_strerror(r
) << dendl
;
610 if (zonegroup
.is_master
) {
611 // set master as default if no default exists
612 constexpr bool exclusive
= true;
613 r
= set_default_zonegroup(dpp
, y
, cfgstore
, zonegroup
, exclusive
);
615 ldpp_dout(dpp
, 1) << "Set the period's master zonegroup "
616 << zonegroup
.name
<< " as the default" << dendl
;
623 std::string
get_staging_period_id(std::string_view realm_id
)
625 return string_cat_reserve(realm_id
, ":staging");
628 void fork_period(const DoutPrefixProvider
* dpp
, RGWPeriod
& info
)
630 ldpp_dout(dpp
, 20) << __func__
<< " realm id=" << info
.realm_id
631 << " period id=" << info
.id
<< dendl
;
633 info
.predecessor_uuid
= std::move(info
.id
);
634 info
.id
= get_staging_period_id(info
.realm_id
);
635 info
.period_map
.reset();
639 int update_period(const DoutPrefixProvider
* dpp
, optional_yield y
,
640 sal::ConfigStore
* cfgstore
, RGWPeriod
& info
)
642 // clear zone short ids of removed zones. period_map.update() will add the
643 // remaining zones back
644 info
.period_map
.short_zone_ids
.clear();
646 // list all zonegroups in the realm
647 rgw::sal::ListResult
<std::string
> listing
;
648 std::array
<std::string
, 1000> zonegroup_names
; // list in pages of 1000
650 int ret
= cfgstore
->list_zonegroup_names(dpp
, y
, listing
.next
,
651 zonegroup_names
, listing
);
653 std::cerr
<< "failed to list zonegroups: " << cpp_strerror(-ret
) << std::endl
;
656 for (const auto& name
: listing
.entries
) {
658 ret
= cfgstore
->read_zonegroup_by_name(dpp
, y
, name
, zg
, nullptr);
660 ldpp_dout(dpp
, 0) << "WARNING: failed to read zonegroup "
661 << name
<< ": " << cpp_strerror(-ret
) << dendl
;
665 if (zg
.realm_id
!= info
.realm_id
) {
666 ldpp_dout(dpp
, 20) << "skipping zonegroup " << zg
.get_name()
667 << " with realm id " << zg
.realm_id
668 << ", not on our realm " << info
.realm_id
<< dendl
;
672 if (zg
.master_zone
.empty()) {
673 ldpp_dout(dpp
, 0) << "ERROR: zonegroup " << zg
.get_name() << " should have a master zone " << dendl
;
677 if (zg
.zones
.find(zg
.master_zone
) == zg
.zones
.end()) {
678 ldpp_dout(dpp
, 0) << "ERROR: zonegroup " << zg
.get_name()
679 << " has a non existent master zone "<< dendl
;
683 if (zg
.is_master_zonegroup()) {
684 info
.master_zonegroup
= zg
.get_id();
685 info
.master_zone
= zg
.master_zone
;
688 ret
= info
.period_map
.update(zg
, dpp
->get_cct());
692 } // foreach name in listing.entries
693 } while (!listing
.next
.empty());
695 // read the realm's current period config
696 int ret
= cfgstore
->read_period_config(dpp
, y
, info
.realm_id
,
698 if (ret
< 0 && ret
!= -ENOENT
) {
699 ldpp_dout(dpp
, 0) << "ERROR: failed to read period config: "
700 << cpp_strerror(ret
) << dendl
;
707 int commit_period(const DoutPrefixProvider
* dpp
, optional_yield y
,
708 sal::ConfigStore
* cfgstore
, sal::Driver
* driver
,
709 RGWRealm
& realm
, sal::RealmWriter
& realm_writer
,
710 const RGWPeriod
& current_period
,
711 RGWPeriod
& info
, std::ostream
& error_stream
,
714 auto zone_svc
= static_cast<rgw::sal::RadosStore
*>(driver
)->svc()->zone
; // XXX
716 ldpp_dout(dpp
, 20) << __func__
<< " realm " << realm
.id
717 << " period " << current_period
.id
<< dendl
;
718 // gateway must be in the master zone to commit
719 if (info
.master_zone
!= zone_svc
->get_zone_params().id
) {
720 error_stream
<< "Cannot commit period on zone "
721 << zone_svc
->get_zone_params().id
<< ", it must be sent to "
722 "the period's master zone " << info
.master_zone
<< '.' << std::endl
;
725 // period predecessor must match current period
726 if (info
.predecessor_uuid
!= current_period
.id
) {
727 error_stream
<< "Period predecessor " << info
.predecessor_uuid
728 << " does not match current period " << current_period
.id
729 << ". Use 'period pull' to get the latest period from the master, "
730 "reapply your changes, and try again." << std::endl
;
733 // realm epoch must be 1 greater than current period
734 if (info
.realm_epoch
!= current_period
.realm_epoch
+ 1) {
735 error_stream
<< "Period's realm epoch " << info
.realm_epoch
736 << " does not come directly after current realm epoch "
737 << current_period
.realm_epoch
<< ". Use 'realm pull' to get the "
738 "latest realm and period from the master zone, reapply your changes, "
739 "and try again." << std::endl
;
742 // did the master zone change?
743 if (info
.master_zone
!= current_period
.master_zone
) {
744 // store the current metadata sync status in the period
745 int r
= info
.update_sync_status(dpp
, driver
, current_period
,
746 error_stream
, force_if_stale
);
748 ldpp_dout(dpp
, 0) << "failed to update metadata sync status: "
749 << cpp_strerror(-r
) << dendl
;
752 // create an object with a new period id
753 info
.period_map
.id
= info
.id
= gen_random_uuid();
754 info
.epoch
= FIRST_EPOCH
;
756 constexpr bool exclusive
= true;
757 r
= cfgstore
->create_period(dpp
, y
, exclusive
, info
);
759 ldpp_dout(dpp
, 0) << "failed to create new period: " << cpp_strerror(-r
) << dendl
;
762 // set as current period
763 r
= realm_set_current_period(dpp
, y
, cfgstore
, realm_writer
, realm
, info
);
765 ldpp_dout(dpp
, 0) << "failed to update realm's current period: "
766 << cpp_strerror(-r
) << dendl
;
769 ldpp_dout(dpp
, 4) << "Promoted to master zone and committed new period "
771 (void) cfgstore
->realm_notify_new_period(dpp
, y
, info
);
774 // period must be based on current epoch
775 if (info
.epoch
!= current_period
.epoch
) {
776 error_stream
<< "Period epoch " << info
.epoch
<< " does not match "
777 "predecessor epoch " << current_period
.epoch
<< ". Use "
778 "'period pull' to get the latest epoch from the master zone, "
779 "reapply your changes, and try again." << std::endl
;
782 // set period as next epoch
783 info
.id
= current_period
.id
;
784 info
.epoch
= current_period
.epoch
+ 1;
785 info
.predecessor_uuid
= current_period
.predecessor_uuid
;
786 info
.realm_epoch
= current_period
.realm_epoch
;
788 constexpr bool exclusive
= true;
789 int r
= cfgstore
->create_period(dpp
, y
, exclusive
, info
);
791 // already have this epoch (or a more recent one)
795 ldpp_dout(dpp
, 0) << "failed to store period: " << cpp_strerror(r
) << dendl
;
798 r
= reflect_period(dpp
, y
, cfgstore
, info
);
800 ldpp_dout(dpp
, 0) << "failed to update local objects: " << cpp_strerror(r
) << dendl
;
803 ldpp_dout(dpp
, 4) << "Committed new epoch " << info
.epoch
804 << " for period " << info
.id
<< dendl
;
805 (void) cfgstore
->realm_notify_new_period(dpp
, y
, info
);
810 int read_zonegroup(const DoutPrefixProvider
* dpp
, optional_yield y
,
811 sal::ConfigStore
* cfgstore
,
812 std::string_view zonegroup_id
,
813 std::string_view zonegroup_name
,
815 std::unique_ptr
<sal::ZoneGroupWriter
>* writer
)
817 if (!zonegroup_id
.empty()) {
818 return cfgstore
->read_zonegroup_by_id(dpp
, y
, zonegroup_id
, info
, writer
);
820 if (!zonegroup_name
.empty()) {
821 return cfgstore
->read_zonegroup_by_name(dpp
, y
, zonegroup_name
, info
, writer
);
824 std::string realm_id
;
825 int r
= cfgstore
->read_default_realm_id(dpp
, y
, realm_id
);
827 return cfgstore
->read_zonegroup_by_name(dpp
, y
, default_zonegroup_name
,
833 return cfgstore
->read_default_zonegroup(dpp
, y
, realm_id
, info
, writer
);
836 int create_zonegroup(const DoutPrefixProvider
* dpp
, optional_yield y
,
837 sal::ConfigStore
* cfgstore
, bool exclusive
,
840 if (info
.name
.empty()) {
841 ldpp_dout(dpp
, -1) << __func__
<< " requires a zonegroup name" << dendl
;
844 if (info
.id
.empty()) {
845 info
.id
= gen_random_uuid();
848 // insert the default placement target if it doesn't exist
849 constexpr std::string_view default_placement_name
= "default-placement";
851 RGWZoneGroupPlacementTarget placement_target
;
852 placement_target
.name
= default_placement_name
;
854 info
.placement_targets
.emplace(default_placement_name
, placement_target
);
855 if (info
.default_placement
.name
.empty()) {
856 info
.default_placement
.name
= default_placement_name
;
859 int r
= cfgstore
->create_zonegroup(dpp
, y
, exclusive
, info
, nullptr);
861 ldpp_dout(dpp
, 0) << "failed to create zonegroup with "
862 << cpp_strerror(r
) << dendl
;
866 // try to set as default. may race with another create, so pass exclusive=true
867 // so we don't override an existing default
868 r
= set_default_zonegroup(dpp
, y
, cfgstore
, info
, true);
869 if (r
< 0 && r
!= -EEXIST
) {
870 ldpp_dout(dpp
, 0) << "WARNING: failed to set zonegroup as default: "
871 << cpp_strerror(r
) << dendl
;
877 int set_default_zonegroup(const DoutPrefixProvider
* dpp
, optional_yield y
,
878 sal::ConfigStore
* cfgstore
, const RGWZoneGroup
& info
,
881 return cfgstore
->write_default_zonegroup_id(
882 dpp
, y
, exclusive
, info
.realm_id
, info
.id
);
885 int remove_zone_from_group(const DoutPrefixProvider
* dpp
,
886 RGWZoneGroup
& zonegroup
,
887 const rgw_zone_id
& zone_id
)
889 auto z
= zonegroup
.zones
.find(zone_id
);
890 if (z
== zonegroup
.zones
.end()) {
893 zonegroup
.zones
.erase(z
);
895 if (zonegroup
.master_zone
== zone_id
) {
896 // choose a new master zone
897 auto m
= zonegroup
.zones
.begin();
898 if (m
!= zonegroup
.zones
.end()) {
899 zonegroup
.master_zone
= m
->first
;
900 ldpp_dout(dpp
, 0) << "NOTICE: promoted " << m
->second
.name
901 << " as new master_zone of zonegroup " << zonegroup
.name
<< dendl
;
903 ldpp_dout(dpp
, 0) << "NOTICE: removed master_zone of zonegroup "
904 << zonegroup
.name
<< dendl
;
908 const bool log_data
= zonegroup
.zones
.size() > 1;
909 for (auto& [id
, zone
] : zonegroup
.zones
) {
910 zone
.log_data
= log_data
;
916 // try to remove the given zone id from every zonegroup in the cluster
917 static int remove_zone_from_groups(const DoutPrefixProvider
* dpp
,
919 sal::ConfigStore
* cfgstore
,
920 const rgw_zone_id
& zone_id
)
922 std::array
<std::string
, 128> zonegroup_names
;
923 sal::ListResult
<std::string
> listing
;
925 int r
= cfgstore
->list_zonegroup_names(dpp
, y
, listing
.next
,
926 zonegroup_names
, listing
);
928 ldpp_dout(dpp
, 0) << "failed to list zonegroups with "
929 << cpp_strerror(r
) << dendl
;
933 for (const auto& name
: listing
.entries
) {
934 RGWZoneGroup zonegroup
;
935 std::unique_ptr
<sal::ZoneGroupWriter
> writer
;
936 r
= cfgstore
->read_zonegroup_by_name(dpp
, y
, name
, zonegroup
, &writer
);
938 ldpp_dout(dpp
, 0) << "WARNING: failed to load zonegroup " << name
939 << " with " << cpp_strerror(r
) << dendl
;
943 r
= remove_zone_from_group(dpp
, zonegroup
, zone_id
);
948 // write the updated zonegroup
949 r
= writer
->write(dpp
, y
, zonegroup
);
951 ldpp_dout(dpp
, 0) << "WARNING: failed to write zonegroup " << name
952 << " with " << cpp_strerror(r
) << dendl
;
955 ldpp_dout(dpp
, 0) << "Removed zone from zonegroup " << name
<< dendl
;
957 } while (!listing
.next
.empty());
963 int read_zone(const DoutPrefixProvider
* dpp
, optional_yield y
,
964 sal::ConfigStore
* cfgstore
,
965 std::string_view zone_id
,
966 std::string_view zone_name
,
968 std::unique_ptr
<sal::ZoneWriter
>* writer
)
970 if (!zone_id
.empty()) {
971 return cfgstore
->read_zone_by_id(dpp
, y
, zone_id
, info
, writer
);
973 if (!zone_name
.empty()) {
974 return cfgstore
->read_zone_by_name(dpp
, y
, zone_name
, info
, writer
);
977 std::string realm_id
;
978 int r
= cfgstore
->read_default_realm_id(dpp
, y
, realm_id
);
980 return cfgstore
->read_zone_by_name(dpp
, y
, default_zone_name
, info
, writer
);
985 return cfgstore
->read_default_zone(dpp
, y
, realm_id
, info
, writer
);
988 extern int get_zones_pool_set(const DoutPrefixProvider
*dpp
, optional_yield y
,
989 rgw::sal::ConfigStore
* cfgstore
,
990 std::string_view my_zone_id
,
991 std::set
<rgw_pool
>& pools
);
993 int create_zone(const DoutPrefixProvider
* dpp
, optional_yield y
,
994 sal::ConfigStore
* cfgstore
, bool exclusive
,
995 RGWZoneParams
& info
, std::unique_ptr
<sal::ZoneWriter
>* writer
)
997 if (info
.name
.empty()) {
998 ldpp_dout(dpp
, -1) << __func__
<< " requires a zone name" << dendl
;
1001 if (info
.id
.empty()) {
1002 info
.id
= gen_random_uuid();
1005 // add default placement with empty pool name
1007 auto& placement
= info
.placement_pools
["default-placement"];
1008 placement
.storage_classes
.set_storage_class(
1009 RGW_STORAGE_CLASS_STANDARD
, &pool
, nullptr);
1011 // build a set of all pool names used by other zones
1012 std::set
<rgw_pool
> pools
;
1013 int r
= get_zones_pool_set(dpp
, y
, cfgstore
, info
.id
, pools
);
1018 // initialize pool names with the zone name prefix
1019 r
= init_zone_pool_names(dpp
, y
, pools
, info
);
1024 r
= cfgstore
->create_zone(dpp
, y
, exclusive
, info
, nullptr);
1026 ldpp_dout(dpp
, 0) << "failed to create zone with "
1027 << cpp_strerror(r
) << dendl
;
1031 // try to set as default. may race with another create, so pass exclusive=true
1032 // so we don't override an existing default
1033 r
= set_default_zone(dpp
, y
, cfgstore
, info
, true);
1034 if (r
< 0 && r
!= -EEXIST
) {
1035 ldpp_dout(dpp
, 0) << "WARNING: failed to set zone as default: "
1036 << cpp_strerror(r
) << dendl
;
1043 int set_default_zone(const DoutPrefixProvider
* dpp
, optional_yield y
,
1044 sal::ConfigStore
* cfgstore
, const RGWZoneParams
& info
,
1047 return cfgstore
->write_default_zone_id(
1048 dpp
, y
, exclusive
, info
.realm_id
, info
.id
);
1051 int delete_zone(const DoutPrefixProvider
* dpp
, optional_yield y
,
1052 sal::ConfigStore
* cfgstore
, const RGWZoneParams
& info
,
1053 sal::ZoneWriter
& writer
)
1055 // remove this zone from any zonegroups that contain it
1056 int r
= remove_zone_from_groups(dpp
, y
, cfgstore
, info
.id
);
1061 return writer
.remove(dpp
, y
);
1066 static inline int conf_to_uint64(const JSONFormattable
& config
, const string
& key
, uint64_t *pval
)
1069 if (config
.find(key
, &sval
)) {
1071 uint64_t val
= strict_strtoll(sval
.c_str(), 10, &err
);
1080 int RGWZoneGroupPlacementTier::update_params(const JSONFormattable
& config
)
1084 if (config
.exists("retain_head_object")) {
1085 string s
= config
["retain_head_object"];
1087 retain_head_object
= true;
1089 retain_head_object
= false;
1093 if (tier_type
== "cloud-s3") {
1094 r
= t
.s3
.update_params(config
);
1100 int RGWZoneGroupPlacementTier::clear_params(const JSONFormattable
& config
)
1102 if (config
.exists("retain_head_object")) {
1103 retain_head_object
= false;
1106 if (tier_type
== "cloud-s3") {
1107 t
.s3
.clear_params(config
);
1113 int RGWZoneGroupPlacementTierS3::update_params(const JSONFormattable
& config
)
1117 if (config
.exists("endpoint")) {
1118 endpoint
= config
["endpoint"];
1120 if (config
.exists("target_path")) {
1121 target_path
= config
["target_path"];
1123 if (config
.exists("region")) {
1124 region
= config
["region"];
1126 if (config
.exists("host_style")) {
1128 s
= config
["host_style"];
1129 if (s
!= "virtual") {
1130 host_style
= PathStyle
;
1132 host_style
= VirtualStyle
;
1135 if (config
.exists("target_storage_class")) {
1136 target_storage_class
= config
["target_storage_class"];
1138 if (config
.exists("access_key")) {
1139 key
.id
= config
["access_key"];
1141 if (config
.exists("secret")) {
1142 key
.key
= config
["secret"];
1144 if (config
.exists("multipart_sync_threshold")) {
1145 r
= conf_to_uint64(config
, "multipart_sync_threshold", &multipart_sync_threshold
);
1147 multipart_sync_threshold
= DEFAULT_MULTIPART_SYNC_PART_SIZE
;
1151 if (config
.exists("multipart_min_part_size")) {
1152 r
= conf_to_uint64(config
, "multipart_min_part_size", &multipart_min_part_size
);
1154 multipart_min_part_size
= DEFAULT_MULTIPART_SYNC_PART_SIZE
;
1158 if (config
.exists("acls")) {
1159 const JSONFormattable
& cc
= config
["acls"];
1160 if (cc
.is_array()) {
1161 for (auto& c
: cc
.array()) {
1162 RGWTierACLMapping m
;
1164 if (!m
.source_id
.empty()) {
1165 acl_mappings
[m
.source_id
] = m
;
1169 RGWTierACLMapping m
;
1171 if (!m
.source_id
.empty()) {
1172 acl_mappings
[m
.source_id
] = m
;
1179 int RGWZoneGroupPlacementTierS3::clear_params(const JSONFormattable
& config
)
1181 if (config
.exists("endpoint")) {
1184 if (config
.exists("target_path")) {
1185 target_path
.clear();
1187 if (config
.exists("region")) {
1190 if (config
.exists("host_style")) {
1192 host_style
= PathStyle
;
1194 if (config
.exists("target_storage_class")) {
1195 target_storage_class
.clear();
1197 if (config
.exists("access_key")) {
1200 if (config
.exists("secret")) {
1203 if (config
.exists("multipart_sync_threshold")) {
1204 multipart_sync_threshold
= DEFAULT_MULTIPART_SYNC_PART_SIZE
;
1206 if (config
.exists("multipart_min_part_size")) {
1207 multipart_min_part_size
= DEFAULT_MULTIPART_SYNC_PART_SIZE
;
1209 if (config
.exists("acls")) {
1210 const JSONFormattable
& cc
= config
["acls"];
1211 if (cc
.is_array()) {
1212 for (auto& c
: cc
.array()) {
1213 RGWTierACLMapping m
;
1215 acl_mappings
.erase(m
.source_id
);
1218 RGWTierACLMapping m
;
1220 acl_mappings
.erase(m
.source_id
);
1226 void rgw_meta_sync_info::generate_test_instances(list
<rgw_meta_sync_info
*>& o
)
1228 auto info
= new rgw_meta_sync_info
;
1229 info
->state
= rgw_meta_sync_info::StateBuildingFullSyncMaps
;
1230 info
->period
= "periodid";
1231 info
->realm_epoch
= 5;
1233 o
.push_back(new rgw_meta_sync_info
);
1236 void rgw_meta_sync_marker::generate_test_instances(list
<rgw_meta_sync_marker
*>& o
)
1238 auto marker
= new rgw_meta_sync_marker
;
1239 marker
->state
= rgw_meta_sync_marker::IncrementalSync
;
1240 marker
->marker
= "01234";
1241 marker
->realm_epoch
= 5;
1242 o
.push_back(marker
);
1243 o
.push_back(new rgw_meta_sync_marker
);
1246 void rgw_meta_sync_status::generate_test_instances(list
<rgw_meta_sync_status
*>& o
)
1248 o
.push_back(new rgw_meta_sync_status
);
1251 void RGWZoneParams::generate_test_instances(list
<RGWZoneParams
*> &o
)
1253 o
.push_back(new RGWZoneParams
);
1254 o
.push_back(new RGWZoneParams
);
1257 void RGWPeriodLatestEpochInfo::generate_test_instances(list
<RGWPeriodLatestEpochInfo
*> &o
)
1259 RGWPeriodLatestEpochInfo
*z
= new RGWPeriodLatestEpochInfo
;
1261 o
.push_back(new RGWPeriodLatestEpochInfo
);
1264 void RGWZoneGroup::generate_test_instances(list
<RGWZoneGroup
*>& o
)
1266 RGWZoneGroup
*r
= new RGWZoneGroup
;
1268 o
.push_back(new RGWZoneGroup
);
1271 void RGWPeriodLatestEpochInfo::dump(Formatter
*f
) const {
1272 encode_json("latest_epoch", epoch
, f
);
1275 void RGWPeriodLatestEpochInfo::decode_json(JSONObj
*obj
) {
1276 JSONDecoder::decode_json("latest_epoch", epoch
, obj
);
1279 void RGWNameToId::dump(Formatter
*f
) const {
1280 encode_json("obj_id", obj_id
, f
);
1283 void RGWNameToId::decode_json(JSONObj
*obj
) {
1284 JSONDecoder::decode_json("obj_id", obj_id
, obj
);