From: Yehuda Sadeh Date: Fri, 10 Aug 2018 21:36:48 +0000 (-0700) Subject: rgw: svc: initial work on zone_svc X-Git-Tag: v14.1.0~965^2~44 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=e44a5fe22ef4a96a3547760685324bc11bbe228e;p=ceph.git rgw: svc: initial work on zone_svc Signed-off-by: Yehuda Sadeh --- diff --git a/src/rgw/CMakeLists.txt b/src/rgw/CMakeLists.txt index fa3a4d3c5a1c..0e376bd94c0a 100644 --- a/src/rgw/CMakeLists.txt +++ b/src/rgw/CMakeLists.txt @@ -40,6 +40,7 @@ endfunction() set(librgw_common_srcs services/svc_rados.cc + services/svc_zone.cc rgw_service.cc rgw_acl.cc rgw_acl_s3.cc diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index 780863afdabe..42d334204427 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -236,1851 +236,6 @@ void RGWObjectCtxImpl::invalidate(const rgw_raw_obj objs_state.erase(iter); } -void RGWDefaultZoneGroupInfo::dump(Formatter *f) const { - encode_json("default_zonegroup", default_zonegroup, f); -} - -void RGWDefaultZoneGroupInfo::decode_json(JSONObj *obj) { - - JSONDecoder::decode_json("default_zonegroup", default_zonegroup, obj); - /* backward compatability with region */ - if (default_zonegroup.empty()) { - JSONDecoder::decode_json("default_region", default_zonegroup, obj); - } -} - -rgw_pool RGWZoneGroup::get_pool(CephContext *cct_) -{ - if (cct_->_conf->rgw_zonegroup_root_pool.empty()) { - return rgw_pool(RGW_DEFAULT_ZONEGROUP_ROOT_POOL); - } - - return rgw_pool(cct_->_conf->rgw_zonegroup_root_pool); -} - -int RGWZoneGroup::create_default(bool old_format) -{ - name = default_zonegroup_name; - api_name = default_zonegroup_name; - is_master = true; - - RGWZoneGroupPlacementTarget placement_target; - placement_target.name = "default-placement"; - placement_targets[placement_target.name] = placement_target; - default_placement = "default-placement"; - - RGWZoneParams zone_params(default_zone_name); - - int r = zone_params.init(cct, store, false); - if (r < 0) { - ldout(cct, 0) << "create_default: error initializing zone params: " << cpp_strerror(-r) << dendl; - return r; - } - - r = zone_params.create_default(); - if (r < 0 && r != -EEXIST) { - ldout(cct, 0) << "create_default: error in create_default zone params: " << cpp_strerror(-r) << dendl; - return r; - } else if (r == -EEXIST) { - ldout(cct, 10) << "zone_params::create_default() returned -EEXIST, we raced with another default zone_params creation" << dendl; - zone_params.clear_id(); - r = zone_params.init(cct, store); - if (r < 0) { - ldout(cct, 0) << "create_default: error in init existing zone params: " << cpp_strerror(-r) << dendl; - return r; - } - ldout(cct, 20) << "zone_params::create_default() " << zone_params.get_name() << " id " << zone_params.get_id() - << dendl; - } - - RGWZone& default_zone = zones[zone_params.get_id()]; - default_zone.name = zone_params.get_name(); - default_zone.id = zone_params.get_id(); - master_zone = default_zone.id; - - r = create(); - if (r < 0 && r != -EEXIST) { - ldout(cct, 0) << "error storing zone group info: " << cpp_strerror(-r) << dendl; - return r; - } - - if (r == -EEXIST) { - ldout(cct, 10) << "create_default() returned -EEXIST, we raced with another zonegroup creation" << dendl; - id.clear(); - r = init(cct, store); - if (r < 0) { - return r; - } - } - - if (old_format) { - name = id; - } - - post_process_params(); - - return 0; -} - -const string RGWZoneGroup::get_default_oid(bool old_region_format) -{ - if (old_region_format) { - if (cct->_conf->rgw_default_region_info_oid.empty()) { - return default_region_info_oid; - } - return cct->_conf->rgw_default_region_info_oid; - } - - string default_oid = cct->_conf->rgw_default_zonegroup_info_oid; - - if (cct->_conf->rgw_default_zonegroup_info_oid.empty()) { - default_oid = default_zone_group_info_oid; - } - - default_oid += "." + realm_id; - - return default_oid; -} - -const string& RGWZoneGroup::get_info_oid_prefix(bool old_region_format) -{ - if (old_region_format) { - return region_info_oid_prefix; - } - return zone_group_info_oid_prefix; -} - -const string& RGWZoneGroup::get_names_oid_prefix() -{ - return zonegroup_names_oid_prefix; -} - -const string& RGWZoneGroup::get_predefined_name(CephContext *cct) { - return cct->_conf->rgw_zonegroup; -} - -int RGWZoneGroup::equals(const string& other_zonegroup) const -{ - if (is_master && other_zonegroup.empty()) - return true; - - return (id == other_zonegroup); -} - -int RGWZoneGroup::add_zone(const RGWZoneParams& zone_params, bool *is_master, bool *read_only, - const list& endpoints, const string *ptier_type, - bool *psync_from_all, list& sync_from, list& sync_from_rm, - string *predirect_zone) -{ - auto& zone_id = zone_params.get_id(); - auto& zone_name = zone_params.get_name(); - - // check for duplicate zone name on insert - if (!zones.count(zone_id)) { - for (const auto& zone : zones) { - if (zone.second.name == zone_name) { - ldout(cct, 0) << "ERROR: found existing zone name " << zone_name - << " (" << zone.first << ") in zonegroup " << get_name() << dendl; - return -EEXIST; - } - } - } - - if (is_master) { - if (*is_master) { - if (!master_zone.empty() && master_zone != zone_id) { - ldout(cct, 0) << "NOTICE: overriding master zone: " << master_zone << dendl; - } - master_zone = zone_id; - } else if (master_zone == zone_id) { - master_zone.clear(); - } - } - - RGWZone& zone = zones[zone_id]; - zone.name = zone_name; - zone.id = zone_id; - if (!endpoints.empty()) { - zone.endpoints = endpoints; - } - if (read_only) { - zone.read_only = *read_only; - } - if (ptier_type) { - zone.tier_type = *ptier_type; - if (!store->get_sync_modules_manager()->get_module(*ptier_type, nullptr)) { - ldout(cct, 0) << "ERROR: could not found sync module: " << *ptier_type - << ", valid sync modules: " - << store->get_sync_modules_manager()->get_registered_module_names() - << dendl; - return -ENOENT; - } - } - - if (psync_from_all) { - zone.sync_from_all = *psync_from_all; - } - - if (predirect_zone) { - zone.redirect_zone = *predirect_zone; - } - - for (auto add : sync_from) { - zone.sync_from.insert(add); - } - - for (auto rm : sync_from_rm) { - zone.sync_from.erase(rm); - } - - post_process_params(); - - return update(); -} - - -int RGWZoneGroup::rename_zone(const RGWZoneParams& zone_params) -{ - RGWZone& zone = zones[zone_params.get_id()]; - zone.name = zone_params.get_name(); - - return update(); -} - -void RGWZoneGroup::post_process_params() -{ - bool log_data = zones.size() > 1; - - if (master_zone.empty()) { - map::iterator iter = zones.begin(); - if (iter != zones.end()) { - master_zone = iter->first; - } - } - - for (map::iterator iter = zones.begin(); iter != zones.end(); ++iter) { - RGWZone& zone = iter->second; - zone.log_data = log_data; - - RGWZoneParams zone_params(zone.id, zone.name); - int ret = zone_params.init(cct, store); - if (ret < 0) { - ldout(cct, 0) << "WARNING: could not read zone params for zone id=" << zone.id << " name=" << zone.name << dendl; - continue; - } - - for (map::iterator iter = zone_params.placement_pools.begin(); - iter != zone_params.placement_pools.end(); ++iter) { - const string& placement_name = iter->first; - if (placement_targets.find(placement_name) == placement_targets.end()) { - RGWZoneGroupPlacementTarget placement_target; - placement_target.name = placement_name; - placement_targets[placement_name] = placement_target; - } - } - } - - if (default_placement.empty() && !placement_targets.empty()) { - default_placement = placement_targets.begin()->first; - } -} - -int RGWZoneGroup::remove_zone(const std::string& zone_id) -{ - map::iterator iter = zones.find(zone_id); - if (iter == zones.end()) { - ldout(cct, 0) << "zone id " << zone_id << " is not a part of zonegroup " - << name << dendl; - return -ENOENT; - } - - zones.erase(iter); - - post_process_params(); - - return update(); -} - -int RGWZoneGroup::read_default_id(string& default_id, bool old_format) -{ - if (realm_id.empty()) { - /* try using default realm */ - RGWRealm realm; - int ret = realm.init(cct, store); - // no default realm exist - if (ret < 0) { - return read_id(default_zonegroup_name, default_id); - } - realm_id = realm.get_id(); - } - - return RGWSystemMetaObj::read_default_id(default_id, old_format); -} - -int RGWZoneGroup::set_as_default(bool exclusive) -{ - if (realm_id.empty()) { - /* try using default realm */ - RGWRealm realm; - int ret = realm.init(cct, store); - if (ret < 0) { - ldout(cct, 10) << "could not read realm id: " << cpp_strerror(-ret) << dendl; - return -EINVAL; - } - realm_id = realm.get_id(); - } - - return RGWSystemMetaObj::set_as_default(exclusive); -} - -int RGWSystemMetaObj::init(CephContext *_cct, RGWRados *_store, bool setup_obj, bool old_format) -{ - cct = _cct; - store = _store; - - if (!setup_obj) - return 0; - - if (old_format && id.empty()) { - id = name; - } - - if (id.empty()) { - int r; - if (name.empty()) { - name = get_predefined_name(cct); - } - if (name.empty()) { - r = use_default(old_format); - if (r < 0) { - return r; - } - } else if (!old_format) { - r = read_id(name, id); - if (r < 0) { - if (r != -ENOENT) { - ldout(cct, 0) << "error in read_id for object name: " << name << " : " << cpp_strerror(-r) << dendl; - } - return r; - } - } - } - - return read_info(id, old_format); -} - -int RGWSystemMetaObj::read_default(RGWDefaultSystemMetaObjInfo& default_info, const string& oid) -{ - using ceph::decode; - auto pool = get_pool(cct); - bufferlist bl; - RGWObjectCtx obj_ctx(store); - int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL); - if (ret < 0) - return ret; - - try { - auto iter = bl.cbegin(); - decode(default_info, iter); - } catch (buffer::error& err) { - ldout(cct, 0) << "error decoding data from " << pool << ":" << oid << dendl; - return -EIO; - } - - return 0; -} - -int RGWSystemMetaObj::read_default_id(string& default_id, bool old_format) -{ - RGWDefaultSystemMetaObjInfo default_info; - - int ret = read_default(default_info, get_default_oid(old_format)); - if (ret < 0) { - return ret; - } - - default_id = default_info.default_id; - - return 0; -} - -int RGWSystemMetaObj::use_default(bool old_format) -{ - return read_default_id(id, old_format); -} - -int RGWSystemMetaObj::set_as_default(bool exclusive) -{ - using ceph::encode; - string oid = get_default_oid(); - - rgw_pool pool(get_pool(cct)); - bufferlist bl; - - RGWDefaultSystemMetaObjInfo default_info; - default_info.default_id = id; - - encode(default_info, bl); - - int ret = rgw_put_system_obj(store, pool, oid, bl, - exclusive, NULL, real_time(), NULL); - if (ret < 0) - return ret; - - return 0; -} - -int RGWSystemMetaObj::read_id(const string& obj_name, string& object_id) -{ - using ceph::decode; - rgw_pool pool(get_pool(cct)); - bufferlist bl; - - string oid = get_names_oid_prefix() + obj_name; - - RGWObjectCtx obj_ctx(store); - int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL); - if (ret < 0) { - return ret; - } - - RGWNameToId nameToId; - try { - auto iter = bl.cbegin(); - decode(nameToId, iter); - } catch (buffer::error& err) { - ldout(cct, 0) << "ERROR: failed to decode obj from " << pool << ":" << oid << dendl; - return -EIO; - } - object_id = nameToId.obj_id; - return 0; -} - -int RGWSystemMetaObj::delete_obj(bool old_format) -{ - rgw_pool pool(get_pool(cct)); - - /* check to see if obj is the default */ - RGWDefaultSystemMetaObjInfo default_info; - int ret = read_default(default_info, get_default_oid(old_format)); - if (ret < 0 && ret != -ENOENT) - return ret; - if (default_info.default_id == id || (old_format && default_info.default_id == name)) { - string oid = get_default_oid(old_format); - rgw_raw_obj default_named_obj(pool, oid); - ret = store->delete_system_obj(default_named_obj); - if (ret < 0) { - ldout(cct, 0) << "Error delete default obj name " << name << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - } - if (!old_format) { - string oid = get_names_oid_prefix() + name; - rgw_raw_obj object_name(pool, oid); - ret = store->delete_system_obj(object_name); - if (ret < 0) { - ldout(cct, 0) << "Error delete obj name " << name << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - } - - string oid = get_info_oid_prefix(old_format); - if (old_format) { - oid += name; - } else { - oid += id; - } - - rgw_raw_obj object_id(pool, oid); - ret = store->delete_system_obj(object_id); - if (ret < 0) { - ldout(cct, 0) << "Error delete object id " << id << ": " << cpp_strerror(-ret) << dendl; - } - - return ret; -} - -int RGWSystemMetaObj::store_name(bool exclusive) -{ - rgw_pool pool(get_pool(cct)); - string oid = get_names_oid_prefix() + name; - - RGWNameToId nameToId; - nameToId.obj_id = id; - - bufferlist bl; - using ceph::encode; - encode(nameToId, bl); - return rgw_put_system_obj(store, pool, oid, bl, exclusive, NULL, real_time(), NULL); -} - -int RGWSystemMetaObj::rename(const string& new_name) -{ - string new_id; - int ret = read_id(new_name, new_id); - if (!ret) { - return -EEXIST; - } - if (ret < 0 && ret != -ENOENT) { - ldout(cct, 0) << "Error read_id " << new_name << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - string old_name = name; - name = new_name; - ret = update(); - if (ret < 0) { - ldout(cct, 0) << "Error storing new obj info " << new_name << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - ret = store_name(true); - if (ret < 0) { - ldout(cct, 0) << "Error storing new name " << new_name << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - /* delete old name */ - rgw_pool pool(get_pool(cct)); - string oid = get_names_oid_prefix() + old_name; - rgw_raw_obj old_name_obj(pool, oid); - ret = store->delete_system_obj(old_name_obj); - if (ret < 0) { - ldout(cct, 0) << "Error delete old obj name " << old_name << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - - return ret; -} - -int RGWSystemMetaObj::read_info(const string& obj_id, bool old_format) -{ - rgw_pool pool(get_pool(cct)); - - bufferlist bl; - - string oid = get_info_oid_prefix(old_format) + obj_id; - - RGWObjectCtx obj_ctx(store); - int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL); - if (ret < 0) { - ldout(cct, 0) << "failed reading obj info from " << pool << ":" << oid << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - using ceph::decode; - - try { - auto iter = bl.cbegin(); - decode(*this, iter); - } catch (buffer::error& err) { - ldout(cct, 0) << "ERROR: failed to decode obj from " << pool << ":" << oid << dendl; - return -EIO; - } - - return 0; -} - -int RGWSystemMetaObj::read() -{ - int ret = read_id(name, id); - if (ret < 0) { - return ret; - } - - return read_info(id); -} - -int RGWSystemMetaObj::create(bool exclusive) -{ - int ret; - - /* check to see the name is not used */ - ret = read_id(name, id); - if (exclusive && ret == 0) { - ldout(cct, 10) << "ERROR: name " << name << " already in use for obj id " << id << dendl; - return -EEXIST; - } else if ( ret < 0 && ret != -ENOENT) { - ldout(cct, 0) << "failed reading obj id " << id << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - - if (id.empty()) { - /* create unique id */ - uuid_d new_uuid; - char uuid_str[37]; - new_uuid.generate_random(); - new_uuid.print(uuid_str); - id = uuid_str; - } - - ret = store_info(exclusive); - if (ret < 0) { - ldout(cct, 0) << "ERROR: storing info for " << id << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - - return store_name(exclusive); -} - -int RGWSystemMetaObj::store_info(bool exclusive) -{ - rgw_pool pool(get_pool(cct)); - - string oid = get_info_oid_prefix() + id; - - bufferlist bl; - using ceph::encode; - encode(*this, bl); - return rgw_put_system_obj(store, pool, oid, bl, exclusive, NULL, real_time(), NULL); -} - -int RGWSystemMetaObj::write(bool exclusive) -{ - int ret = store_info(exclusive); - if (ret < 0) { - ldout(cct, 20) << __func__ << "(): store_info() returned ret=" << ret << dendl; - return ret; - } - ret = store_name(exclusive); - if (ret < 0) { - ldout(cct, 20) << __func__ << "(): store_name() returned ret=" << ret << dendl; - return ret; - } - return 0; -} - - -const string& RGWRealm::get_predefined_name(CephContext *cct) { - return cct->_conf->rgw_realm; -} - -int RGWRealm::create(bool exclusive) -{ - int ret = RGWSystemMetaObj::create(exclusive); - if (ret < 0) { - ldout(cct, 0) << "ERROR creating new realm object " << name << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - // create the control object for watch/notify - ret = create_control(exclusive); - if (ret < 0) { - ldout(cct, 0) << "ERROR creating control for new realm " << name << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - RGWPeriod period; - if (current_period.empty()) { - /* create new period for the realm */ - ret = period.init(cct, store, id, name, false); - if (ret < 0 ) { - return ret; - } - ret = period.create(true); - if (ret < 0) { - ldout(cct, 0) << "ERROR: creating new period for realm " << name << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - } else { - period = RGWPeriod(current_period, 0); - int ret = period.init(cct, store, id, name); - if (ret < 0) { - ldout(cct, 0) << "ERROR: failed to init period " << current_period << dendl; - return ret; - } - } - ret = set_current_period(period); - if (ret < 0) { - ldout(cct, 0) << "ERROR: failed set current period " << current_period << dendl; - return ret; - } - // try to set as default. may race with another create, so pass exclusive=true - // so we don't override an existing default - ret = set_as_default(true); - if (ret < 0 && ret != -EEXIST) { - ldout(cct, 0) << "WARNING: failed to set realm as default realm, ret=" << ret << dendl; - } - - return 0; -} - -int RGWRealm::delete_obj() -{ - int ret = RGWSystemMetaObj::delete_obj(); - if (ret < 0) { - return ret; - } - return delete_control(); -} - -int RGWRealm::create_control(bool exclusive) -{ - auto pool = rgw_pool{get_pool(cct)}; - auto oid = get_control_oid(); - bufferlist bl; - return rgw_put_system_obj(store, pool, oid, bl, exclusive, - nullptr, real_time(), nullptr); -} - -int RGWRealm::delete_control() -{ - auto pool = rgw_pool{get_pool(cct)}; - auto obj = rgw_raw_obj{pool, get_control_oid()}; - return store->delete_system_obj(obj); -} - -rgw_pool RGWRealm::get_pool(CephContext *cct) -{ - if (cct->_conf->rgw_realm_root_pool.empty()) { - return rgw_pool(RGW_DEFAULT_REALM_ROOT_POOL); - } - return rgw_pool(cct->_conf->rgw_realm_root_pool); -} - -const string RGWRealm::get_default_oid(bool old_format) -{ - if (cct->_conf->rgw_default_realm_info_oid.empty()) { - return default_realm_info_oid; - } - return cct->_conf->rgw_default_realm_info_oid; -} - -const string& RGWRealm::get_names_oid_prefix() -{ - return realm_names_oid_prefix; -} - -const string& RGWRealm::get_info_oid_prefix(bool old_format) -{ - return realm_info_oid_prefix; -} - -int RGWRealm::set_current_period(RGWPeriod& period) -{ - // update realm epoch to match the period's - if (epoch > period.get_realm_epoch()) { - ldout(cct, 0) << "ERROR: set_current_period with old realm epoch " - << period.get_realm_epoch() << ", current epoch=" << epoch << dendl; - return -EINVAL; - } - if (epoch == period.get_realm_epoch() && current_period != period.get_id()) { - ldout(cct, 0) << "ERROR: set_current_period with same realm epoch " - << period.get_realm_epoch() << ", but different period id " - << period.get_id() << " != " << current_period << dendl; - return -EINVAL; - } - - epoch = period.get_realm_epoch(); - current_period = period.get_id(); - - int ret = update(); - if (ret < 0) { - ldout(cct, 0) << "ERROR: period update: " << cpp_strerror(-ret) << dendl; - return ret; - } - - ret = period.reflect(); - if (ret < 0) { - ldout(cct, 0) << "ERROR: period.reflect(): " << cpp_strerror(-ret) << dendl; - return ret; - } - - return 0; -} - -string RGWRealm::get_control_oid() -{ - return get_info_oid_prefix() + id + ".control"; -} - -int RGWRealm::notify_zone(bufferlist& bl) -{ - // open a context on the realm's pool - rgw_pool pool{get_pool(cct)}; - librados::IoCtx ctx; - int r = rgw_init_ioctx(store->get_rados_handle(), pool, ctx); - if (r < 0) { - ldout(cct, 0) << "Failed to open pool " << pool << dendl; - return r; - } - // send a notify on the realm object - r = ctx.notify2(get_control_oid(), bl, 0, nullptr); - if (r < 0) { - ldout(cct, 0) << "Realm notify failed with " << r << dendl; - return r; - } - return 0; -} - -int RGWRealm::notify_new_period(const RGWPeriod& period) -{ - bufferlist bl; - using ceph::encode; - // push the period to dependent zonegroups/zones - encode(RGWRealmNotify::ZonesNeedPeriod, bl); - encode(period, bl); - // reload the gateway with the new period - encode(RGWRealmNotify::Reload, bl); - - return notify_zone(bl); -} - -std::string RGWPeriodConfig::get_oid(const std::string& realm_id) -{ - if (realm_id.empty()) { - return "period_config.default"; - } - return "period_config." + realm_id; -} - -rgw_pool RGWPeriodConfig::get_pool(CephContext *cct) -{ - const auto& pool_name = cct->_conf->rgw_period_root_pool; - if (pool_name.empty()) { - return {RGW_DEFAULT_PERIOD_ROOT_POOL}; - } - return {pool_name}; -} - -int RGWPeriodConfig::read(RGWRados *store, const std::string& realm_id) -{ - RGWObjectCtx obj_ctx(store); - const auto& pool = get_pool(store->ctx()); - const auto& oid = get_oid(realm_id); - bufferlist bl; - - int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, nullptr, nullptr); - if (ret < 0) { - return ret; - } - using ceph::decode; - try { - auto iter = bl.cbegin(); - decode(*this, iter); - } catch (buffer::error& err) { - return -EIO; - } - return 0; -} - -int RGWPeriodConfig::write(RGWRados *store, const std::string& realm_id) -{ - const auto& pool = get_pool(store->ctx()); - const auto& oid = get_oid(realm_id); - bufferlist bl; - using ceph::encode; - encode(*this, bl); - return rgw_put_system_obj(store, pool, oid, bl, - false, nullptr, real_time(), nullptr); -} - -int RGWPeriod::init(CephContext *_cct, RGWRados *_store, const string& period_realm_id, - const string& period_realm_name, bool setup_obj) -{ - cct = _cct; - store = _store; - realm_id = period_realm_id; - realm_name = period_realm_name; - - if (!setup_obj) - return 0; - - return init(_cct, _store, setup_obj); -} - - -int RGWPeriod::init(CephContext *_cct, RGWRados *_store, bool setup_obj) -{ - cct = _cct; - store = _store; - - if (!setup_obj) - return 0; - - if (id.empty()) { - RGWRealm realm(realm_id, realm_name); - int ret = realm.init(cct, store); - if (ret < 0) { - ldout(cct, 0) << "RGWPeriod::init failed to init realm " << realm_name << " id " << realm_id << " : " << - cpp_strerror(-ret) << dendl; - return ret; - } - id = realm.get_current_period(); - realm_id = realm.get_id(); - } - - if (!epoch) { - int ret = use_latest_epoch(); - if (ret < 0) { - ldout(cct, 0) << "failed to use_latest_epoch period id " << id << " realm " << realm_name << " id " << realm_id - << " : " << cpp_strerror(-ret) << dendl; - return ret; - } - } - - return read_info(); -} - - -int RGWPeriod::get_zonegroup(RGWZoneGroup& zonegroup, const string& zonegroup_id) { - map::const_iterator iter; - if (!zonegroup_id.empty()) { - iter = period_map.zonegroups.find(zonegroup_id); - } else { - iter = period_map.zonegroups.find("default"); - } - if (iter != period_map.zonegroups.end()) { - zonegroup = iter->second; - return 0; - } - - return -ENOENT; -} - -bool RGWRados::get_redirect_zone_endpoint(string *endpoint) -{ - if (zone_public_config.redirect_zone.empty()) { - return false; - } - - auto iter = zone_conn_map.find(zone_public_config.redirect_zone); - if (iter == zone_conn_map.end()) { - ldout(cct, 0) << "ERROR: cannot find entry for redirect zone: " << zone_public_config.redirect_zone << dendl; - return false; - } - - RGWRESTConn *conn = iter->second; - - int ret = conn->get_url(*endpoint); - if (ret < 0) { - ldout(cct, 0) << "ERROR: redirect zone, conn->get_endpoint() returned ret=" << ret << dendl; - return false; - } - - return true; -} - -const string& RGWPeriod::get_latest_epoch_oid() -{ - if (cct->_conf->rgw_period_latest_epoch_info_oid.empty()) { - return period_latest_epoch_info_oid; - } - return cct->_conf->rgw_period_latest_epoch_info_oid; -} - -const string& RGWPeriod::get_info_oid_prefix() -{ - return period_info_oid_prefix; -} - -const string RGWPeriod::get_period_oid_prefix() -{ - return get_info_oid_prefix() + id; -} - -const string RGWPeriod::get_period_oid() -{ - std::ostringstream oss; - oss << get_period_oid_prefix(); - // skip the epoch for the staging period - if (id != get_staging_id(realm_id)) - oss << "." << epoch; - return oss.str(); -} - -int RGWPeriod::read_latest_epoch(RGWPeriodLatestEpochInfo& info, - RGWObjVersionTracker *objv) -{ - string oid = get_period_oid_prefix() + get_latest_epoch_oid(); - - rgw_pool pool(get_pool(cct)); - bufferlist bl; - RGWObjectCtx obj_ctx(store); - int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, objv, nullptr); - if (ret < 0) { - ldout(cct, 1) << "error read_lastest_epoch " << pool << ":" << oid << dendl; - return ret; - } - try { - auto iter = bl.cbegin(); - using ceph::decode; - decode(info, iter); - } catch (buffer::error& err) { - ldout(cct, 0) << "error decoding data from " << pool << ":" << oid << dendl; - return -EIO; - } - - return 0; -} - -int RGWPeriod::get_latest_epoch(epoch_t& latest_epoch) -{ - RGWPeriodLatestEpochInfo info; - - int ret = read_latest_epoch(info); - if (ret < 0) { - return ret; - } - - latest_epoch = info.epoch; - - return 0; -} - -int RGWPeriod::use_latest_epoch() -{ - RGWPeriodLatestEpochInfo info; - int ret = read_latest_epoch(info); - if (ret < 0) { - return ret; - } - - epoch = info.epoch; - - return 0; -} - -int RGWPeriod::set_latest_epoch(epoch_t epoch, bool exclusive, - RGWObjVersionTracker *objv) -{ - string oid = get_period_oid_prefix() + get_latest_epoch_oid(); - - rgw_pool pool(get_pool(cct)); - bufferlist bl; - - RGWPeriodLatestEpochInfo info; - info.epoch = epoch; - - using ceph::encode; - encode(info, bl); - - return rgw_put_system_obj(store, pool, oid, bl, - exclusive, objv, real_time(), nullptr); -} - -int RGWPeriod::update_latest_epoch(epoch_t epoch) -{ - static constexpr int MAX_RETRIES = 20; - - for (int i = 0; i < MAX_RETRIES; i++) { - RGWPeriodLatestEpochInfo info; - RGWObjVersionTracker objv; - bool exclusive = false; - - // read existing epoch - int r = read_latest_epoch(info, &objv); - if (r == -ENOENT) { - // use an exclusive create to set the epoch atomically - exclusive = true; - ldout(cct, 20) << "creating initial latest_epoch=" << epoch - << " for period=" << id << dendl; - } else if (r < 0) { - ldout(cct, 0) << "ERROR: failed to read latest_epoch" << dendl; - return r; - } else if (epoch <= info.epoch) { - r = -EEXIST; // fail with EEXIST if epoch is not newer - ldout(cct, 1) << "found existing latest_epoch " << info.epoch - << " >= given epoch " << epoch << ", returning r=" << r << dendl; - return r; - } else { - ldout(cct, 20) << "updating latest_epoch from " << info.epoch - << " -> " << epoch << " on period=" << id << dendl; - } - - r = set_latest_epoch(epoch, exclusive, &objv); - if (r == -EEXIST) { - continue; // exclusive create raced with another update, retry - } else if (r == -ECANCELED) { - continue; // write raced with a conflicting version, retry - } - if (r < 0) { - ldout(cct, 0) << "ERROR: failed to write latest_epoch" << dendl; - return r; - } - return 0; // return success - } - - return -ECANCELED; // fail after max retries -} - -int RGWPeriod::delete_obj() -{ - rgw_pool pool(get_pool(cct)); - - // delete the object for each period epoch - for (epoch_t e = 1; e <= epoch; e++) { - RGWPeriod p{get_id(), e}; - rgw_raw_obj oid{pool, p.get_period_oid()}; - int ret = store->delete_system_obj(oid); - if (ret < 0) { - ldout(cct, 0) << "WARNING: failed to delete period object " << oid - << ": " << cpp_strerror(-ret) << dendl; - } - } - - // delete the .latest_epoch object - rgw_raw_obj oid{pool, get_period_oid_prefix() + get_latest_epoch_oid()}; - int ret = store->delete_system_obj(oid); - if (ret < 0) { - ldout(cct, 0) << "WARNING: failed to delete period object " << oid - << ": " << cpp_strerror(-ret) << dendl; - } - return ret; -} - -int RGWPeriod::read_info() -{ - rgw_pool pool(get_pool(cct)); - - bufferlist bl; - - RGWObjectCtx obj_ctx(store); - int ret = rgw_get_system_obj(store, obj_ctx, pool, get_period_oid(), bl, NULL, NULL); - if (ret < 0) { - ldout(cct, 0) << "failed reading obj info from " << pool << ":" << get_period_oid() << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - - try { - using ceph::decode; - auto iter = bl.cbegin(); - decode(*this, iter); - } catch (buffer::error& err) { - ldout(cct, 0) << "ERROR: failed to decode obj from " << pool << ":" << get_period_oid() << dendl; - return -EIO; - } - - return 0; -} - -int RGWPeriod::create(bool exclusive) -{ - int ret; - - /* create unique id */ - uuid_d new_uuid; - char uuid_str[37]; - new_uuid.generate_random(); - new_uuid.print(uuid_str); - id = uuid_str; - - epoch = FIRST_EPOCH; - - period_map.id = id; - - ret = store_info(exclusive); - if (ret < 0) { - ldout(cct, 0) << "ERROR: storing info for " << id << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - - ret = set_latest_epoch(epoch); - if (ret < 0) { - ldout(cct, 0) << "ERROR: setting latest epoch " << id << ": " << cpp_strerror(-ret) << dendl; - } - - return ret; -} - -int RGWPeriod::store_info(bool exclusive) -{ - rgw_pool pool(get_pool(cct)); - - string oid = get_period_oid(); - bufferlist bl; - using ceph::encode; - encode(*this, bl); - - return rgw_put_system_obj(store, pool, oid, bl, - exclusive, NULL, real_time(), NULL); -} - -rgw_pool RGWPeriod::get_pool(CephContext *cct) -{ - if (cct->_conf->rgw_period_root_pool.empty()) { - return rgw_pool(RGW_DEFAULT_PERIOD_ROOT_POOL); - } - return rgw_pool(cct->_conf->rgw_period_root_pool); -} - -int RGWPeriod::add_zonegroup(const RGWZoneGroup& zonegroup) -{ - if (zonegroup.realm_id != realm_id) { - return 0; - } - int ret = period_map.update(zonegroup, cct); - if (ret < 0) { - ldout(cct, 0) << "ERROR: updating period map: " << cpp_strerror(-ret) << dendl; - return ret; - } - - return store_info(false); -} - -int RGWPeriod::update() -{ - ldout(cct, 20) << __func__ << " realm " << realm_id << " period " << get_id() << dendl; - list zonegroups; - int ret = store->list_zonegroups(zonegroups); - if (ret < 0) { - ldout(cct, 0) << "ERROR: failed to list zonegroups: " << cpp_strerror(-ret) << dendl; - return ret; - } - - // clear zone short ids of removed zones. period_map.update() will add the - // remaining zones back - period_map.short_zone_ids.clear(); - - for (auto& iter : zonegroups) { - RGWZoneGroup zg(string(), iter); - ret = zg.init(cct, store); - if (ret < 0) { - ldout(cct, 0) << "WARNING: zg.init() failed: " << cpp_strerror(-ret) << dendl; - continue; - } - - if (zg.realm_id != realm_id) { - ldout(cct, 20) << "skipping zonegroup " << zg.get_name() << " zone realm id " << zg.realm_id << ", not on our realm " << realm_id << dendl; - continue; - } - - if (zg.master_zone.empty()) { - ldout(cct, 0) << "ERROR: zonegroup " << zg.get_name() << " should have a master zone " << dendl; - return -EINVAL; - } - - if (zg.is_master_zonegroup()) { - master_zonegroup = zg.get_id(); - master_zone = zg.master_zone; - } - - int ret = period_map.update(zg, cct); - if (ret < 0) { - return ret; - } - } - - ret = period_config.read(store, realm_id); - if (ret < 0 && ret != -ENOENT) { - ldout(cct, 0) << "ERROR: failed to read period config: " - << cpp_strerror(ret) << dendl; - return ret; - } - return 0; -} - -int RGWPeriod::reflect() -{ - for (auto& iter : period_map.zonegroups) { - RGWZoneGroup& zg = iter.second; - zg.reinit_instance(cct, store); - int r = zg.write(false); - if (r < 0) { - ldout(cct, 0) << "ERROR: failed to store zonegroup info for zonegroup=" << iter.first << ": " << cpp_strerror(-r) << dendl; - return r; - } - if (zg.is_master_zonegroup()) { - // set master as default if no default exists - r = zg.set_as_default(true); - if (r == 0) { - ldout(cct, 1) << "Set the period's master zonegroup " << zg.get_id() - << " as the default" << dendl; - } - } - } - - int r = period_config.write(store, realm_id); - if (r < 0) { - ldout(cct, 0) << "ERROR: failed to store period config: " - << cpp_strerror(-r) << dendl; - return r; - } - return 0; -} - -void RGWPeriod::fork() -{ - ldout(cct, 20) << __func__ << " realm " << realm_id << " period " << id << dendl; - predecessor_uuid = id; - id = get_staging_id(realm_id); - period_map.reset(); - realm_epoch++; -} - -static int read_sync_status(RGWRados *store, rgw_meta_sync_status *sync_status) -{ - // initialize a sync status manager to read the status - RGWMetaSyncStatusManager mgr(store, store->get_async_rados()); - int r = mgr.init(); - if (r < 0) { - return r; - } - r = mgr.read_sync_status(sync_status); - mgr.stop(); - return r; -} - -int RGWPeriod::update_sync_status(const RGWPeriod ¤t_period, - std::ostream& error_stream, - bool force_if_stale) -{ - rgw_meta_sync_status status; - int r = read_sync_status(store, &status); - if (r < 0) { - ldout(cct, 0) << "period failed to read sync status: " - << cpp_strerror(-r) << dendl; - return r; - } - - std::vector markers; - - const auto current_epoch = current_period.get_realm_epoch(); - if (current_epoch != status.sync_info.realm_epoch) { - // no sync status markers for the current period - ceph_assert(current_epoch > status.sync_info.realm_epoch); - const int behind = current_epoch - status.sync_info.realm_epoch; - if (!force_if_stale && current_epoch > 1) { - error_stream << "ERROR: This zone is " << behind << " period(s) behind " - "the current master zone in metadata sync. If this zone is promoted " - "to master, any metadata changes during that time are likely to " - "be lost.\n" - "Waiting for this zone to catch up on metadata sync (see " - "'radosgw-admin sync status') is recommended.\n" - "To promote this zone to master anyway, add the flag " - "--yes-i-really-mean-it." << std::endl; - return -EINVAL; - } - // empty sync status markers - other zones will skip this period during - // incremental metadata sync - markers.resize(status.sync_info.num_shards); - } else { - markers.reserve(status.sync_info.num_shards); - for (auto& i : status.sync_markers) { - auto& marker = i.second; - // filter out markers from other periods - if (marker.realm_epoch != current_epoch) { - marker.marker.clear(); - } - markers.emplace_back(std::move(marker.marker)); - } - } - - std::swap(sync_status, markers); - return 0; -} - -int RGWPeriod::commit(RGWRealm& realm, const RGWPeriod& current_period, - std::ostream& error_stream, bool force_if_stale) -{ - ldout(cct, 20) << __func__ << " realm " << realm.get_id() << " period " << current_period.get_id() << dendl; - // gateway must be in the master zone to commit - if (master_zone != store->get_zone_params().get_id()) { - error_stream << "Cannot commit period on zone " - << store->get_zone_params().get_id() << ", it must be sent to " - "the period's master zone " << master_zone << '.' << std::endl; - return -EINVAL; - } - // period predecessor must match current period - if (predecessor_uuid != current_period.get_id()) { - error_stream << "Period predecessor " << predecessor_uuid - << " does not match current period " << current_period.get_id() - << ". Use 'period pull' to get the latest period from the master, " - "reapply your changes, and try again." << std::endl; - return -EINVAL; - } - // realm epoch must be 1 greater than current period - if (realm_epoch != current_period.get_realm_epoch() + 1) { - error_stream << "Period's realm epoch " << realm_epoch - << " does not come directly after current realm epoch " - << current_period.get_realm_epoch() << ". Use 'realm pull' to get the " - "latest realm and period from the master zone, reapply your changes, " - "and try again." << std::endl; - return -EINVAL; - } - // did the master zone change? - if (master_zone != current_period.get_master_zone()) { - // store the current metadata sync status in the period - int r = update_sync_status(current_period, error_stream, force_if_stale); - if (r < 0) { - ldout(cct, 0) << "failed to update metadata sync status: " - << cpp_strerror(-r) << dendl; - return r; - } - // create an object with a new period id - r = create(true); - if (r < 0) { - ldout(cct, 0) << "failed to create new period: " << cpp_strerror(-r) << dendl; - return r; - } - // set as current period - r = realm.set_current_period(*this); - if (r < 0) { - ldout(cct, 0) << "failed to update realm's current period: " - << cpp_strerror(-r) << dendl; - return r; - } - ldout(cct, 4) << "Promoted to master zone and committed new period " - << id << dendl; - realm.notify_new_period(*this); - return 0; - } - // period must be based on current epoch - if (epoch != current_period.get_epoch()) { - error_stream << "Period epoch " << epoch << " does not match " - "predecessor epoch " << current_period.get_epoch() - << ". Use 'period pull' to get the latest epoch from the master zone, " - "reapply your changes, and try again." << std::endl; - return -EINVAL; - } - // set period as next epoch - set_id(current_period.get_id()); - set_epoch(current_period.get_epoch() + 1); - set_predecessor(current_period.get_predecessor()); - realm_epoch = current_period.get_realm_epoch(); - // write the period to rados - int r = store_info(false); - if (r < 0) { - ldout(cct, 0) << "failed to store period: " << cpp_strerror(-r) << dendl; - return r; - } - // set as latest epoch - r = update_latest_epoch(epoch); - if (r == -EEXIST) { - // already have this epoch (or a more recent one) - return 0; - } - if (r < 0) { - ldout(cct, 0) << "failed to set latest epoch: " << cpp_strerror(-r) << dendl; - return r; - } - r = reflect(); - if (r < 0) { - ldout(cct, 0) << "failed to update local objects: " << cpp_strerror(-r) << dendl; - return r; - } - ldout(cct, 4) << "Committed new epoch " << epoch - << " for period " << id << dendl; - realm.notify_new_period(*this); - return 0; -} - -int RGWZoneParams::create_default(bool old_format) -{ - name = default_zone_name; - - int r = create(); - if (r < 0) { - return r; - } - - if (old_format) { - name = id; - } - - return r; -} - - -int get_zones_pool_set(CephContext* cct, - RGWRados* store, - const list& zones, - const string& my_zone_id, - set& pool_names) -{ - for(auto const& iter : zones) { - RGWZoneParams zone(iter); - int r = zone.init(cct, store); - if (r < 0) { - ldout(cct, 0) << "Error: init zone " << iter << ":" << cpp_strerror(-r) << dendl; - return r; - } - if (zone.get_id() != my_zone_id) { - pool_names.insert(zone.domain_root); - pool_names.insert(zone.metadata_heap); - pool_names.insert(zone.control_pool); - pool_names.insert(zone.gc_pool); - pool_names.insert(zone.log_pool); - pool_names.insert(zone.intent_log_pool); - pool_names.insert(zone.usage_log_pool); - pool_names.insert(zone.user_keys_pool); - pool_names.insert(zone.user_email_pool); - pool_names.insert(zone.user_swift_pool); - pool_names.insert(zone.user_uid_pool); - pool_names.insert(zone.otp_pool); - pool_names.insert(zone.roles_pool); - pool_names.insert(zone.reshard_pool); - for(auto& iter : zone.placement_pools) { - pool_names.insert(iter.second.index_pool); - pool_names.insert(iter.second.data_pool); - pool_names.insert(iter.second.data_extra_pool); - } - } - } - return 0; -} - -rgw_pool fix_zone_pool_dup(set pools, - const string& default_prefix, - const string& default_suffix, - const rgw_pool& suggested_pool) -{ - string suggested_name = suggested_pool.to_str(); - - string prefix = default_prefix; - string suffix = default_suffix; - - if (!suggested_pool.empty()) { - prefix = suggested_name.substr(0, suggested_name.find(".")); - suffix = suggested_name.substr(prefix.length()); - } - - rgw_pool pool(prefix + suffix); - - if (pools.find(pool) == pools.end()) { - return pool; - } else { - while(true) { - pool = prefix + "_" + std::to_string(std::rand()) + suffix; - if (pools.find(pool) == pools.end()) { - return pool; - } - } - } -} - -int RGWZoneParams::fix_pool_names() -{ - - list zones; - int r = store->list_zones(zones); - if (r < 0) { - ldout(cct, 10) << "WARNING: store->list_zones() returned r=" << r << dendl; - } - - set pools; - r = get_zones_pool_set(cct, store, zones, id, pools); - if (r < 0) { - ldout(cct, 0) << "Error: get_zones_pool_names" << r << dendl; - return r; - } - - domain_root = fix_zone_pool_dup(pools, name, ".rgw.meta:root", domain_root); - if (!metadata_heap.name.empty()) { - metadata_heap = fix_zone_pool_dup(pools, name, ".rgw.meta:heap", metadata_heap); - } - control_pool = fix_zone_pool_dup(pools, name, ".rgw.control", control_pool); - gc_pool = fix_zone_pool_dup(pools, name ,".rgw.log:gc", gc_pool); - lc_pool = fix_zone_pool_dup(pools, name ,".rgw.log:lc", lc_pool); - log_pool = fix_zone_pool_dup(pools, name, ".rgw.log", log_pool); - intent_log_pool = fix_zone_pool_dup(pools, name, ".rgw.log:intent", intent_log_pool); - usage_log_pool = fix_zone_pool_dup(pools, name, ".rgw.log:usage", usage_log_pool); - user_keys_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.keys", user_keys_pool); - user_email_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.email", user_email_pool); - user_swift_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.swift", user_swift_pool); - user_uid_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.uid", user_uid_pool); - roles_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:roles", roles_pool); - reshard_pool = fix_zone_pool_dup(pools, name, ".rgw.log:reshard", reshard_pool); - otp_pool = fix_zone_pool_dup(pools, name, ".rgw.otp", otp_pool); - - for(auto& iter : placement_pools) { - iter.second.index_pool = fix_zone_pool_dup(pools, name, "." + default_bucket_index_pool_suffix, - iter.second.index_pool); - iter.second.data_pool = fix_zone_pool_dup(pools, name, "." + default_storage_pool_suffix, - iter.second.data_pool); - iter.second.data_extra_pool= fix_zone_pool_dup(pools, name, "." + default_storage_extra_pool_suffix, - iter.second.data_extra_pool); - } - - return 0; -} - -int RGWZoneParams::create(bool exclusive) -{ - /* check for old pools config */ - rgw_raw_obj obj(domain_root, avail_pools); - int r = store->raw_obj_stat(obj, NULL, NULL, NULL, NULL, NULL, NULL); - if (r < 0) { - ldout(store->ctx(), 10) << "couldn't find old data placement pools config, setting up new ones for the zone" << dendl; - /* a new system, let's set new placement info */ - RGWZonePlacementInfo default_placement; - default_placement.index_pool = name + "." + default_bucket_index_pool_suffix; - default_placement.data_pool = name + "." + default_storage_pool_suffix; - default_placement.data_extra_pool = name + "." + default_storage_extra_pool_suffix; - placement_pools["default-placement"] = default_placement; - } - - r = fix_pool_names(); - if (r < 0) { - ldout(cct, 0) << "ERROR: fix_pool_names returned r=" << r << dendl; - return r; - } - - r = RGWSystemMetaObj::create(exclusive); - if (r < 0) { - return r; - } - - // try to set as default. may race with another create, so pass exclusive=true - // so we don't override an existing default - r = set_as_default(true); - if (r < 0 && r != -EEXIST) { - ldout(cct, 10) << "WARNING: failed to set zone as default, r=" << r << dendl; - } - - return 0; -} - -rgw_pool RGWZoneParams::get_pool(CephContext *cct) -{ - if (cct->_conf->rgw_zone_root_pool.empty()) { - return rgw_pool(RGW_DEFAULT_ZONE_ROOT_POOL); - } - - return rgw_pool(cct->_conf->rgw_zone_root_pool); -} - -const string RGWZoneParams::get_default_oid(bool old_format) -{ - if (old_format) { - return cct->_conf->rgw_default_zone_info_oid; - } - - return cct->_conf->rgw_default_zone_info_oid + "." + realm_id; -} - -const string& RGWZoneParams::get_names_oid_prefix() -{ - return zone_names_oid_prefix; -} - -const string& RGWZoneParams::get_info_oid_prefix(bool old_format) -{ - return zone_info_oid_prefix; -} - -const string& RGWZoneParams::get_predefined_name(CephContext *cct) { - return cct->_conf->rgw_zone; -} - -int RGWZoneParams::init(CephContext *cct, RGWRados *store, bool setup_obj, bool old_format) -{ - if (name.empty()) { - name = cct->_conf->rgw_zone; - } - - return RGWSystemMetaObj::init(cct, store, setup_obj, old_format); -} - -int RGWZoneParams::read_default_id(string& default_id, bool old_format) -{ - if (realm_id.empty()) { - /* try using default realm */ - RGWRealm realm; - int ret = realm.init(cct, store); - //no default realm exist - if (ret < 0) { - return read_id(default_zone_name, default_id); - } - realm_id = realm.get_id(); - } - - return RGWSystemMetaObj::read_default_id(default_id, old_format); -} - - -int RGWZoneParams::set_as_default(bool exclusive) -{ - if (realm_id.empty()) { - /* try using default realm */ - RGWRealm realm; - int ret = realm.init(cct, store); - if (ret < 0) { - ldout(cct, 10) << "could not read realm id: " << cpp_strerror(-ret) << dendl; - return -EINVAL; - } - realm_id = realm.get_id(); - } - - return RGWSystemMetaObj::set_as_default(exclusive); -} - -const string& RGWZoneParams::get_compression_type(const string& placement_rule) const -{ - static const std::string NONE{"none"}; - auto p = placement_pools.find(placement_rule); - if (p == placement_pools.end()) { - return NONE; - } - const auto& type = p->second.compression_type; - return !type.empty() ? type : NONE; -} - -void RGWPeriodMap::encode(bufferlist& bl) const { - ENCODE_START(2, 1, bl); - encode(id, bl); - encode(zonegroups, bl); - encode(master_zonegroup, bl); - encode(short_zone_ids, bl); - ENCODE_FINISH(bl); -} - -void RGWPeriodMap::decode(bufferlist::const_iterator& bl) { - DECODE_START(2, bl); - decode(id, bl); - decode(zonegroups, bl); - decode(master_zonegroup, bl); - if (struct_v >= 2) { - decode(short_zone_ids, bl); - } - DECODE_FINISH(bl); - - zonegroups_by_api.clear(); - for (map::iterator iter = zonegroups.begin(); - iter != zonegroups.end(); ++iter) { - RGWZoneGroup& zonegroup = iter->second; - zonegroups_by_api[zonegroup.api_name] = zonegroup; - if (zonegroup.is_master_zonegroup()) { - master_zonegroup = zonegroup.get_id(); - } - } -} - -// run an MD5 hash on the zone_id and return the first 32 bits -static uint32_t gen_short_zone_id(const std::string zone_id) -{ - unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE]; - MD5 hash; - hash.Update((const unsigned char *)zone_id.c_str(), zone_id.size()); - hash.Final(md5); - - uint32_t short_id; - memcpy((char *)&short_id, md5, sizeof(short_id)); - return std::max(short_id, 1u); -} - -int RGWPeriodMap::update(const RGWZoneGroup& zonegroup, CephContext *cct) -{ - if (zonegroup.is_master_zonegroup() && (!master_zonegroup.empty() && zonegroup.get_id() != master_zonegroup)) { - ldout(cct,0) << "Error updating periodmap, multiple master zonegroups configured "<< dendl; - ldout(cct,0) << "master zonegroup: " << master_zonegroup << " and " << zonegroup.get_id() <::iterator iter = zonegroups.find(zonegroup.get_id()); - if (iter != zonegroups.end()) { - RGWZoneGroup& old_zonegroup = iter->second; - if (!old_zonegroup.api_name.empty()) { - zonegroups_by_api.erase(old_zonegroup.api_name); - } - } - zonegroups[zonegroup.get_id()] = zonegroup; - - if (!zonegroup.api_name.empty()) { - zonegroups_by_api[zonegroup.api_name] = zonegroup; - } - - if (zonegroup.is_master_zonegroup()) { - master_zonegroup = zonegroup.get_id(); - } else if (master_zonegroup == zonegroup.get_id()) { - master_zonegroup = ""; - } - - for (auto& i : zonegroup.zones) { - auto& zone = i.second; - if (short_zone_ids.find(zone.id) != short_zone_ids.end()) { - continue; - } - // calculate the zone's short id - uint32_t short_id = gen_short_zone_id(zone.id); - - // search for an existing zone with the same short id - for (auto& s : short_zone_ids) { - if (s.second == short_id) { - ldout(cct, 0) << "New zone '" << zone.name << "' (" << zone.id - << ") generates the same short_zone_id " << short_id - << " as existing zone id " << s.first << dendl; - return -EEXIST; - } - } - - short_zone_ids[zone.id] = short_id; - } - - return 0; -} - -uint32_t RGWPeriodMap::get_zone_short_id(const string& zone_id) const -{ - auto i = short_zone_ids.find(zone_id); - if (i == short_zone_ids.end()) { - return 0; - } - return i->second; -} - -int RGWZoneGroupMap::read(CephContext *cct, RGWRados *store) -{ - - RGWPeriod period; - int ret = period.init(cct, store); - if (ret < 0) { - cerr << "failed to read current period info: " << cpp_strerror(ret); - return ret; - } - - bucket_quota = period.get_config().bucket_quota; - user_quota = period.get_config().user_quota; - zonegroups = period.get_map().zonegroups; - zonegroups_by_api = period.get_map().zonegroups_by_api; - master_zonegroup = period.get_map().master_zonegroup; - - return 0; -} - -void RGWRegionMap::encode(bufferlist& bl) const { - ENCODE_START( 3, 1, bl); - encode(regions, bl); - encode(master_region, bl); - encode(bucket_quota, bl); - encode(user_quota, bl); - ENCODE_FINISH(bl); -} - -void RGWRegionMap::decode(bufferlist::const_iterator& bl) { - DECODE_START(3, bl); - decode(regions, bl); - decode(master_region, bl); - if (struct_v >= 2) - decode(bucket_quota, bl); - if (struct_v >= 3) - decode(user_quota, bl); - DECODE_FINISH(bl); -} - -void RGWZoneGroupMap::encode(bufferlist& bl) const { - ENCODE_START( 3, 1, bl); - encode(zonegroups, bl); - encode(master_zonegroup, bl); - encode(bucket_quota, bl); - encode(user_quota, bl); - ENCODE_FINISH(bl); -} - -void RGWZoneGroupMap::decode(bufferlist::const_iterator& bl) { - DECODE_START(3, bl); - decode(zonegroups, bl); - decode(master_zonegroup, bl); - if (struct_v >= 2) - decode(bucket_quota, bl); - if (struct_v >= 3) - decode(user_quota, bl); - DECODE_FINISH(bl); - - zonegroups_by_api.clear(); - for (map::iterator iter = zonegroups.begin(); - iter != zonegroups.end(); ++iter) { - RGWZoneGroup& zonegroup = iter->second; - zonegroups_by_api[zonegroup.api_name] = zonegroup; - if (zonegroup.is_master_zonegroup()) { - master_zonegroup = zonegroup.get_name(); - } - } -} - void RGWObjVersionTracker::prepare_op_for_read(ObjectReadOperation *op) { obj_version *check_objv = version_for_check(); diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h index d48d95678372..7f7c7413e50a 100644 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@ -27,6 +27,8 @@ #include "rgw_sync_module.h" #include "rgw_sync_log_trim.h" +#include "services/svc_zone.h" + class RGWWatcher; class SafeTimer; class ACLOwner; @@ -44,6 +46,8 @@ struct RGWZoneGroup; struct RGWZoneParams; class RGWReshard; class RGWReshardWait; +struct RGWZone; +struct RGWPeriod; /* flags for put_obj_meta() */ #define PUT_OBJ_CREATE 0x01 @@ -1031,943 +1035,6 @@ struct RGWNameToId { }; WRITE_CLASS_ENCODER(RGWNameToId) -class RGWSystemMetaObj { -protected: - string id; - string name; - - CephContext *cct; - RGWRados *store; - - int store_name(bool exclusive); - int store_info(bool exclusive); - int read_info(const string& obj_id, bool old_format = false); - int read_id(const string& obj_name, string& obj_id); - int read_default(RGWDefaultSystemMetaObjInfo& default_info, - const string& oid); - /* read and use default id */ - int use_default(bool old_format = false); - -public: - RGWSystemMetaObj() : cct(NULL), store(NULL) {} - RGWSystemMetaObj(const string& _name): name(_name), cct(NULL), store(NULL) {} - RGWSystemMetaObj(const string& _id, const string& _name) : id(_id), name(_name), cct(NULL), store(NULL) {} - RGWSystemMetaObj(CephContext *_cct, RGWRados *_store): cct(_cct), store(_store){} - RGWSystemMetaObj(const string& _name, CephContext *_cct, RGWRados *_store): name(_name), cct(_cct), store(_store){} - const string& get_name() const { return name; } - const string& get_id() const { return id; } - - void set_name(const string& _name) { name = _name;} - void set_id(const string& _id) { id = _id;} - void clear_id() { id.clear(); } - - virtual ~RGWSystemMetaObj() {} - - virtual void encode(bufferlist& bl) const { - ENCODE_START(1, 1, bl); - encode(id, bl); - encode(name, bl); - ENCODE_FINISH(bl); - } - - virtual void decode(bufferlist::const_iterator& bl) { - DECODE_START(1, bl); - decode(id, bl); - decode(name, bl); - DECODE_FINISH(bl); - } - - void reinit_instance(CephContext *_cct, RGWRados *_store) { - cct = _cct; - store = _store; - } - int init(CephContext *_cct, RGWRados *_store, bool setup_obj = true, bool old_format = false); - virtual int read_default_id(string& default_id, bool old_format = false); - virtual int set_as_default(bool exclusive = false); - int delete_default(); - virtual int create(bool exclusive = true); - int delete_obj(bool old_format = false); - int rename(const string& new_name); - int update() { return store_info(false);} - int update_name() { return store_name(false);} - int read(); - int write(bool exclusive); - - virtual rgw_pool get_pool(CephContext *cct) = 0; - virtual const string get_default_oid(bool old_format = false) = 0; - virtual const string& get_names_oid_prefix() = 0; - virtual const string& get_info_oid_prefix(bool old_format = false) = 0; - virtual const string& get_predefined_name(CephContext *cct) = 0; - - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); -}; -WRITE_CLASS_ENCODER(RGWSystemMetaObj) - -struct RGWZonePlacementInfo { - rgw_pool index_pool; - rgw_pool data_pool; - rgw_pool data_extra_pool; /* if not set we should use data_pool */ - RGWBucketIndexType index_type; - std::string compression_type; - - RGWZonePlacementInfo() : index_type(RGWBIType_Normal) {} - - void encode(bufferlist& bl) const { - ENCODE_START(6, 1, bl); - encode(index_pool.to_str(), bl); - encode(data_pool.to_str(), bl); - encode(data_extra_pool.to_str(), bl); - encode((uint32_t)index_type, bl); - encode(compression_type, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) { - DECODE_START(6, bl); - string index_pool_str; - string data_pool_str; - decode(index_pool_str, bl); - index_pool = rgw_pool(index_pool_str); - decode(data_pool_str, bl); - data_pool = rgw_pool(data_pool_str); - if (struct_v >= 4) { - string data_extra_pool_str; - decode(data_extra_pool_str, bl); - data_extra_pool = rgw_pool(data_extra_pool_str); - } - if (struct_v >= 5) { - uint32_t it; - decode(it, bl); - index_type = (RGWBucketIndexType)it; - } - if (struct_v >= 6) { - decode(compression_type, bl); - } - DECODE_FINISH(bl); - } - const rgw_pool& get_data_extra_pool() const { - if (data_extra_pool.empty()) { - return data_pool; - } - return data_extra_pool; - } - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); -}; -WRITE_CLASS_ENCODER(RGWZonePlacementInfo) - -struct RGWZoneParams : RGWSystemMetaObj { - rgw_pool domain_root; - rgw_pool metadata_heap; - rgw_pool control_pool; - rgw_pool gc_pool; - rgw_pool lc_pool; - rgw_pool log_pool; - rgw_pool intent_log_pool; - rgw_pool usage_log_pool; - - rgw_pool user_keys_pool; - rgw_pool user_email_pool; - rgw_pool user_swift_pool; - rgw_pool user_uid_pool; - rgw_pool roles_pool; - rgw_pool reshard_pool; - rgw_pool otp_pool; - - RGWAccessKey system_key; - - map placement_pools; - - string realm_id; - - JSONFormattable tier_config; - - RGWZoneParams() : RGWSystemMetaObj() {} - explicit RGWZoneParams(const string& name) : RGWSystemMetaObj(name){} - RGWZoneParams(const string& id, const string& name) : RGWSystemMetaObj(id, name) {} - RGWZoneParams(const string& id, const string& name, const string& _realm_id) - : RGWSystemMetaObj(id, name), realm_id(_realm_id) {} - - rgw_pool get_pool(CephContext *cct) override; - const string get_default_oid(bool old_format = false) override; - const string& get_names_oid_prefix() override; - const string& get_info_oid_prefix(bool old_format = false) override; - const string& get_predefined_name(CephContext *cct) override; - - int init(CephContext *_cct, RGWRados *_store, bool setup_obj = true, - bool old_format = false); - using RGWSystemMetaObj::init; - int read_default_id(string& default_id, bool old_format = false) override; - int set_as_default(bool exclusive = false) override; - int create_default(bool old_format = false); - int create(bool exclusive = true) override; - int fix_pool_names(); - - const string& get_compression_type(const string& placement_rule) const; - - void encode(bufferlist& bl) const override { - ENCODE_START(12, 1, bl); - encode(domain_root, bl); - encode(control_pool, bl); - encode(gc_pool, bl); - encode(log_pool, bl); - encode(intent_log_pool, bl); - encode(usage_log_pool, bl); - encode(user_keys_pool, bl); - encode(user_email_pool, bl); - encode(user_swift_pool, bl); - encode(user_uid_pool, bl); - RGWSystemMetaObj::encode(bl); - encode(system_key, bl); - encode(placement_pools, bl); - encode(metadata_heap, bl); - encode(realm_id, bl); - encode(lc_pool, bl); - map old_tier_config; - encode(old_tier_config, bl); - encode(roles_pool, bl); - encode(reshard_pool, bl); - encode(otp_pool, bl); - encode(tier_config, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) override { - DECODE_START(12, bl); - decode(domain_root, bl); - decode(control_pool, bl); - decode(gc_pool, bl); - decode(log_pool, bl); - decode(intent_log_pool, bl); - decode(usage_log_pool, bl); - decode(user_keys_pool, bl); - decode(user_email_pool, bl); - decode(user_swift_pool, bl); - decode(user_uid_pool, bl); - if (struct_v >= 6) { - RGWSystemMetaObj::decode(bl); - } else if (struct_v >= 2) { - decode(name, bl); - id = name; - } - if (struct_v >= 3) - decode(system_key, bl); - if (struct_v >= 4) - decode(placement_pools, bl); - if (struct_v >= 5) - decode(metadata_heap, bl); - if (struct_v >= 6) { - decode(realm_id, bl); - } - if (struct_v >= 7) { - decode(lc_pool, bl); - } else { - lc_pool = log_pool.name + ":lc"; - } - map old_tier_config; - if (struct_v >= 8) { - decode(old_tier_config, bl); - } - if (struct_v >= 9) { - decode(roles_pool, bl); - } else { - roles_pool = name + ".rgw.meta:roles"; - } - if (struct_v >= 10) { - decode(reshard_pool, bl); - } else { - reshard_pool = log_pool.name + ":reshard"; - } - if (struct_v >= 11) { - ::decode(otp_pool, bl); - } else { - otp_pool = name + ".rgw.otp"; - } - if (struct_v >= 12) { - ::decode(tier_config, bl); - } else { - for (auto& kv : old_tier_config) { - tier_config.set(kv.first, kv.second); - } - } - DECODE_FINISH(bl); - } - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); - static void generate_test_instances(list& o); - - bool get_placement(const string& placement_id, RGWZonePlacementInfo *placement) const { - auto iter = placement_pools.find(placement_id); - if (iter == placement_pools.end()) { - return false; - } - *placement = iter->second; - return true; - } - - /* - * return data pool of the head object - */ - bool get_head_data_pool(const string& placement_id, const rgw_obj& obj, rgw_pool *pool) const { - const rgw_data_placement_target& explicit_placement = obj.bucket.explicit_placement; - if (!explicit_placement.data_pool.empty()) { - if (!obj.in_extra_data) { - *pool = explicit_placement.data_pool; - } else { - *pool = explicit_placement.get_data_extra_pool(); - } - return true; - } - if (placement_id.empty()) { - return false; - } - auto iter = placement_pools.find(placement_id); - if (iter == placement_pools.end()) { - return false; - } - if (!obj.in_extra_data) { - *pool = iter->second.data_pool; - } else { - *pool = iter->second.get_data_extra_pool(); - } - return true; - } -}; -WRITE_CLASS_ENCODER(RGWZoneParams) - -struct RGWZone { - string id; - string name; - list endpoints; - bool log_meta; - bool log_data; - bool read_only; - string tier_type; - - string redirect_zone; - -/** - * Represents the number of shards for the bucket index object, a value of zero - * indicates there is no sharding. By default (no sharding, the name of the object - * is '.dir.{marker}', with sharding, the name is '.dir.{marker}.{sharding_id}', - * sharding_id is zero-based value. It is not recommended to set a too large value - * (e.g. thousand) as it increases the cost for bucket listing. - */ - uint32_t bucket_index_max_shards; - - bool sync_from_all; - set sync_from; /* list of zones to sync from */ - - RGWZone() : log_meta(false), log_data(false), read_only(false), bucket_index_max_shards(0), - sync_from_all(true) {} - - void encode(bufferlist& bl) const { - ENCODE_START(7, 1, bl); - encode(name, bl); - encode(endpoints, bl); - encode(log_meta, bl); - encode(log_data, bl); - encode(bucket_index_max_shards, bl); - encode(id, bl); - encode(read_only, bl); - encode(tier_type, bl); - encode(sync_from_all, bl); - encode(sync_from, bl); - encode(redirect_zone, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) { - DECODE_START(7, bl); - decode(name, bl); - if (struct_v < 4) { - id = name; - } - decode(endpoints, bl); - if (struct_v >= 2) { - decode(log_meta, bl); - decode(log_data, bl); - } - if (struct_v >= 3) { - decode(bucket_index_max_shards, bl); - } - if (struct_v >= 4) { - decode(id, bl); - decode(read_only, bl); - } - if (struct_v >= 5) { - decode(tier_type, bl); - } - if (struct_v >= 6) { - decode(sync_from_all, bl); - decode(sync_from, bl); - } - if (struct_v >= 7) { - decode(redirect_zone, bl); - } - DECODE_FINISH(bl); - } - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); - static void generate_test_instances(list& o); - - bool is_read_only() { return read_only; } - - bool syncs_from(const string& zone_id) const { - return (sync_from_all || sync_from.find(zone_id) != sync_from.end()); - } -}; -WRITE_CLASS_ENCODER(RGWZone) - -struct RGWDefaultZoneGroupInfo { - string default_zonegroup; - - void encode(bufferlist& bl) const { - ENCODE_START(1, 1, bl); - encode(default_zonegroup, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) { - DECODE_START(1, bl); - decode(default_zonegroup, bl); - DECODE_FINISH(bl); - } - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); - //todo: implement ceph-dencoder -}; -WRITE_CLASS_ENCODER(RGWDefaultZoneGroupInfo) - -struct RGWZoneGroupPlacementTarget { - string name; - set tags; - - bool user_permitted(list& user_tags) const { - if (tags.empty()) { - return true; - } - for (auto& rule : user_tags) { - if (tags.find(rule) != tags.end()) { - return true; - } - } - return false; - } - - void encode(bufferlist& bl) const { - ENCODE_START(1, 1, bl); - encode(name, bl); - encode(tags, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) { - DECODE_START(1, bl); - decode(name, bl); - decode(tags, bl); - DECODE_FINISH(bl); - } - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); -}; -WRITE_CLASS_ENCODER(RGWZoneGroupPlacementTarget) - - -struct RGWZoneGroup : public RGWSystemMetaObj { - string api_name; - list endpoints; - bool is_master = false; - - string master_zone; - map zones; - - map placement_targets; - string default_placement; - - list hostnames; - list hostnames_s3website; - // TODO: Maybe convert hostnames to a map> for - // endpoint_type->hostnames -/* -20:05 < _robbat21irssi> maybe I do someting like: if (hostname_map.empty()) { populate all map keys from hostnames; }; -20:05 < _robbat21irssi> but that's a later compatability migration planning bit -20:06 < yehudasa> more like if (!hostnames.empty()) { -20:06 < yehudasa> for (list::iterator iter = hostnames.begin(); iter != hostnames.end(); ++iter) { -20:06 < yehudasa> hostname_map["s3"].append(iter->second); -20:07 < yehudasa> hostname_map["s3website"].append(iter->second); -20:07 < yehudasa> s/append/push_back/g -20:08 < _robbat21irssi> inner loop over APIs -20:08 < yehudasa> yeah, probably -20:08 < _robbat21irssi> s3, s3website, swift, swith_auth, swift_website -*/ - map > api_hostname_map; - map > api_endpoints_map; - - string realm_id; - - RGWZoneGroup(): is_master(false){} - RGWZoneGroup(const std::string &id, const std::string &name):RGWSystemMetaObj(id, name) {} - explicit RGWZoneGroup(const std::string &_name):RGWSystemMetaObj(_name) {} - RGWZoneGroup(const std::string &_name, bool _is_master, CephContext *cct, RGWRados* store, - const string& _realm_id, const list& _endpoints) - : RGWSystemMetaObj(_name, cct , store), endpoints(_endpoints), is_master(_is_master), - realm_id(_realm_id) {} - - bool is_master_zonegroup() const { return is_master;} - void update_master(bool _is_master) { - is_master = _is_master; - post_process_params(); - } - void post_process_params(); - - void encode(bufferlist& bl) const override { - ENCODE_START(4, 1, bl); - encode(name, bl); - encode(api_name, bl); - encode(is_master, bl); - encode(endpoints, bl); - encode(master_zone, bl); - encode(zones, bl); - encode(placement_targets, bl); - encode(default_placement, bl); - encode(hostnames, bl); - encode(hostnames_s3website, bl); - RGWSystemMetaObj::encode(bl); - encode(realm_id, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) override { - DECODE_START(4, bl); - decode(name, bl); - decode(api_name, bl); - decode(is_master, bl); - decode(endpoints, bl); - decode(master_zone, bl); - decode(zones, bl); - decode(placement_targets, bl); - decode(default_placement, bl); - if (struct_v >= 2) { - decode(hostnames, bl); - } - if (struct_v >= 3) { - decode(hostnames_s3website, bl); - } - if (struct_v >= 4) { - RGWSystemMetaObj::decode(bl); - decode(realm_id, bl); - } else { - id = name; - } - DECODE_FINISH(bl); - } - - int read_default_id(string& default_id, bool old_format = false) override; - int set_as_default(bool exclusive = false) override; - int create_default(bool old_format = false); - int equals(const string& other_zonegroup) const; - int add_zone(const RGWZoneParams& zone_params, bool *is_master, bool *read_only, - const list& endpoints, const string *ptier_type, - bool *psync_from_all, list& sync_from, list& sync_from_rm, - string *predirect_zone); - int remove_zone(const std::string& zone_id); - int rename_zone(const RGWZoneParams& zone_params); - rgw_pool get_pool(CephContext *cct) override; - const string get_default_oid(bool old_region_format = false) override; - const string& get_info_oid_prefix(bool old_region_format = false) override; - const string& get_names_oid_prefix() override; - const string& get_predefined_name(CephContext *cct) override; - - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); - static void generate_test_instances(list& o); -}; -WRITE_CLASS_ENCODER(RGWZoneGroup) - -struct RGWPeriodMap -{ - string id; - map zonegroups; - map zonegroups_by_api; - map short_zone_ids; - - string master_zonegroup; - - void encode(bufferlist& bl) const; - void decode(bufferlist::const_iterator& bl); - - int update(const RGWZoneGroup& zonegroup, CephContext *cct); - - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); - - void reset() { - zonegroups.clear(); - zonegroups_by_api.clear(); - master_zonegroup.clear(); - } - - uint32_t get_zone_short_id(const string& zone_id) const; -}; -WRITE_CLASS_ENCODER(RGWPeriodMap) - -struct RGWPeriodConfig -{ - RGWQuotaInfo bucket_quota; - RGWQuotaInfo user_quota; - - void encode(bufferlist& bl) const { - ENCODE_START(1, 1, bl); - encode(bucket_quota, bl); - encode(user_quota, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) { - DECODE_START(1, bl); - decode(bucket_quota, bl); - decode(user_quota, bl); - DECODE_FINISH(bl); - } - - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); - - // the period config must be stored in a local object outside of the period, - // so that it can be used in a default configuration where no realm/period - // exists - int read(RGWRados *store, const std::string& realm_id); - int write(RGWRados *store, const std::string& realm_id); - - static std::string get_oid(const std::string& realm_id); - static rgw_pool get_pool(CephContext *cct); -}; -WRITE_CLASS_ENCODER(RGWPeriodConfig) - -/* for backward comaptability */ -struct RGWRegionMap { - - map regions; - - string master_region; - - RGWQuotaInfo bucket_quota; - RGWQuotaInfo user_quota; - - void encode(bufferlist& bl) const; - void decode(bufferlist::const_iterator& bl); - - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); -}; -WRITE_CLASS_ENCODER(RGWRegionMap) - -struct RGWZoneGroupMap { - - map zonegroups; - map zonegroups_by_api; - - string master_zonegroup; - - RGWQuotaInfo bucket_quota; - RGWQuotaInfo user_quota; - - /* construct the map */ - int read(CephContext *cct, RGWRados *store); - - void encode(bufferlist& bl) const; - void decode(bufferlist::const_iterator& bl); - - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); -}; -WRITE_CLASS_ENCODER(RGWZoneGroupMap) - -class RGWRealm; - -struct objexp_hint_entry { - string tenant; - string bucket_name; - string bucket_id; - rgw_obj_key obj_key; - ceph::real_time exp_time; - - void encode(bufferlist& bl) const { - ENCODE_START(2, 1, bl); - encode(bucket_name, bl); - encode(bucket_id, bl); - encode(obj_key, bl); - encode(exp_time, bl); - encode(tenant, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) { - // XXX Do we want DECODE_START_LEGACY_COMPAT_LEN(2, 1, 1, bl); ? - DECODE_START(2, bl); - decode(bucket_name, bl); - decode(bucket_id, bl); - decode(obj_key, bl); - decode(exp_time, bl); - if (struct_v >= 2) { - decode(tenant, bl); - } else { - tenant.clear(); - } - DECODE_FINISH(bl); - } -}; -WRITE_CLASS_ENCODER(objexp_hint_entry) - -class RGWPeriod; - -class RGWRealm : public RGWSystemMetaObj -{ - string current_period; - epoch_t epoch{0}; //< realm epoch, incremented for each new period - - int create_control(bool exclusive); - int delete_control(); -public: - RGWRealm() {} - RGWRealm(const string& _id, const string& _name = "") : RGWSystemMetaObj(_id, _name) {} - RGWRealm(CephContext *_cct, RGWRados *_store): RGWSystemMetaObj(_cct, _store) {} - RGWRealm(const string& _name, CephContext *_cct, RGWRados *_store): RGWSystemMetaObj(_name, _cct, _store){} - - void encode(bufferlist& bl) const override { - ENCODE_START(1, 1, bl); - RGWSystemMetaObj::encode(bl); - encode(current_period, bl); - encode(epoch, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) override { - DECODE_START(1, bl); - RGWSystemMetaObj::decode(bl); - decode(current_period, bl); - decode(epoch, bl); - DECODE_FINISH(bl); - } - - int create(bool exclusive = true) override; - int delete_obj(); - rgw_pool get_pool(CephContext *cct) override; - const string get_default_oid(bool old_format = false) override; - const string& get_names_oid_prefix() override; - const string& get_info_oid_prefix(bool old_format = false) override; - const string& get_predefined_name(CephContext *cct) override; - - using RGWSystemMetaObj::read_id; // expose as public for radosgw-admin - - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); - - const string& get_current_period() const { - return current_period; - } - int set_current_period(RGWPeriod& period); - void clear_current_period_and_epoch() { - current_period.clear(); - epoch = 0; - } - epoch_t get_epoch() const { return epoch; } - - string get_control_oid(); - /// send a notify on the realm control object - int notify_zone(bufferlist& bl); - /// notify the zone of a new period - int notify_new_period(const RGWPeriod& period); -}; -WRITE_CLASS_ENCODER(RGWRealm) - -struct RGWPeriodLatestEpochInfo { - epoch_t epoch; - - void encode(bufferlist& bl) const { - ENCODE_START(1, 1, bl); - encode(epoch, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) { - DECODE_START(1, bl); - decode(epoch, bl); - DECODE_FINISH(bl); - } - - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); -}; -WRITE_CLASS_ENCODER(RGWPeriodLatestEpochInfo) - -class RGWPeriod -{ - string id; - epoch_t epoch; - string predecessor_uuid; - std::vector sync_status; - RGWPeriodMap period_map; - RGWPeriodConfig period_config; - string master_zonegroup; - string master_zone; - - string realm_id; - string realm_name; - epoch_t realm_epoch{1}; //< realm epoch when period was made current - - CephContext *cct; - RGWRados *store; - - int read_info(); - int read_latest_epoch(RGWPeriodLatestEpochInfo& epoch_info, - RGWObjVersionTracker *objv = nullptr); - int use_latest_epoch(); - int use_current_period(); - - const string get_period_oid(); - const string get_period_oid_prefix(); - - // gather the metadata sync status for each shard; only for use on master zone - int update_sync_status(const RGWPeriod ¤t_period, - std::ostream& error_stream, bool force_if_stale); - -public: - RGWPeriod() : epoch(0), cct(NULL), store(NULL) {} - - RGWPeriod(const string& period_id, epoch_t _epoch = 0) - : id(period_id), epoch(_epoch), - cct(NULL), store(NULL) {} - - const string& get_id() const { return id; } - epoch_t get_epoch() const { return epoch; } - epoch_t get_realm_epoch() const { return realm_epoch; } - const string& get_predecessor() const { return predecessor_uuid; } - const string& get_master_zone() const { return master_zone; } - const string& get_master_zonegroup() const { return master_zonegroup; } - const string& get_realm() const { return realm_id; } - const RGWPeriodMap& get_map() const { return period_map; } - RGWPeriodConfig& get_config() { return period_config; } - const RGWPeriodConfig& get_config() const { return period_config; } - const std::vector& get_sync_status() const { return sync_status; } - rgw_pool get_pool(CephContext *cct); - const string& get_latest_epoch_oid(); - const string& get_info_oid_prefix(); - - void set_user_quota(RGWQuotaInfo& user_quota) { - period_config.user_quota = user_quota; - } - - void set_bucket_quota(RGWQuotaInfo& bucket_quota) { - period_config.bucket_quota = bucket_quota; - } - - void set_id(const string& id) { - this->id = id; - period_map.id = id; - } - void set_epoch(epoch_t epoch) { this->epoch = epoch; } - void set_realm_epoch(epoch_t epoch) { realm_epoch = epoch; } - - void set_predecessor(const string& predecessor) - { - predecessor_uuid = predecessor; - } - - void set_realm_id(const string& _realm_id) { - realm_id = _realm_id; - } - - int reflect(); - - int get_zonegroup(RGWZoneGroup& zonegroup, - const string& zonegroup_id); - - bool is_single_zonegroup() const - { - return (period_map.zonegroups.size() == 1); - } - - /* - returns true if there are several zone groups with a least one zone - */ - bool is_multi_zonegroups_with_zones() - { - int count = 0; - for (const auto& zg: period_map.zonegroups) { - if (zg.second.zones.size() > 0) { - if (count++ > 0) { - return true; - } - } - } - return false; - } - - int get_latest_epoch(epoch_t& epoch); - int set_latest_epoch(epoch_t epoch, bool exclusive = false, - RGWObjVersionTracker *objv = nullptr); - // update latest_epoch if the given epoch is higher, else return -EEXIST - int update_latest_epoch(epoch_t epoch); - - int init(CephContext *_cct, RGWRados *_store, const string &period_realm_id, const string &period_realm_name = "", - bool setup_obj = true); - int init(CephContext *_cct, RGWRados *_store, bool setup_obj = true); - - int create(bool exclusive = true); - int delete_obj(); - int store_info(bool exclusive); - int add_zonegroup(const RGWZoneGroup& zonegroup); - - void fork(); - int update(); - - // commit a staging period; only for use on master zone - int commit(RGWRealm& realm, const RGWPeriod ¤t_period, - std::ostream& error_stream, bool force_if_stale = false); - - void encode(bufferlist& bl) const { - ENCODE_START(1, 1, bl); - encode(id, bl); - encode(epoch, bl); - encode(realm_epoch, bl); - encode(predecessor_uuid, bl); - encode(sync_status, bl); - encode(period_map, bl); - encode(master_zone, bl); - encode(master_zonegroup, bl); - encode(period_config, bl); - encode(realm_id, bl); - encode(realm_name, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::const_iterator& bl) { - DECODE_START(1, bl); - decode(id, bl); - decode(epoch, bl); - decode(realm_epoch, bl); - decode(predecessor_uuid, bl); - decode(sync_status, bl); - decode(period_map, bl); - decode(master_zone, bl); - decode(master_zonegroup, bl); - decode(period_config, bl); - decode(realm_id, bl); - decode(realm_name, bl); - DECODE_FINISH(bl); - } - void dump(Formatter *f) const; - void decode_json(JSONObj *obj); - - static string get_staging_id(const string& realm_id) { - return realm_id + ":staging"; - } -}; -WRITE_CLASS_ENCODER(RGWPeriod) - class RGWDataChangesLog; class RGWMetaSyncStatusManager; class RGWDataSyncStatusManager; @@ -2261,12 +1328,8 @@ protected: RGWSyncModuleInstanceRef sync_module; bool writeable_zone{false}; - RGWZoneGroup zonegroup; - RGWZone zone_public_config; /* external zone params, e.g., entrypoints, log flags, etc. */ - RGWZoneParams zone_params; /* internal zone params, e.g., rados pools */ - uint32_t zone_short_id; - RGWPeriod current_period; + std::shared_ptr zone_svc; RGWIndexCompletionManager *index_completion_manager{nullptr}; public: @@ -2287,7 +1350,6 @@ public: quota_handler(NULL), finisher(NULL), cr_registry(NULL), - zone_short_id(0), rest_master_conn(NULL), meta_mgr(NULL), data_log(NULL), reshard(NULL) {} @@ -2356,40 +1418,6 @@ public: return true; } - int get_zonegroup(const string& id, RGWZoneGroup& zonegroup) { - int ret = 0; - if (id == get_zonegroup().get_id()) { - zonegroup = get_zonegroup(); - } else if (!current_period.get_id().empty()) { - ret = current_period.get_zonegroup(zonegroup, id); - } - return ret; - } - - RGWRealm& get_realm() { - return realm; - } - - RGWZoneParams& get_zone_params() { return zone_params; } - RGWZoneGroup& get_zonegroup() { - return zonegroup; - } - RGWZone& get_zone() { - return zone_public_config; - } - - bool zone_is_writeable() { - return writeable_zone && !get_zone().is_read_only(); - } - - uint32_t get_zone_short_id() const { - return zone_short_id; - } - - bool zone_syncs_from(RGWZone& target_zone, RGWZone& source_zone); - - bool get_redirect_zone_endpoint(string *endpoint); - const RGWQuotaInfo& get_bucket_quota() { return current_period.get_config().bucket_quota; } @@ -3572,12 +2600,7 @@ public: int add_bucket_to_reshard(const RGWBucketInfo& bucket_info, uint32_t new_num_shards); uint64_t instance_id(); - const string& zone_name() { - return get_zone_params().get_name(); - } - const string& zone_id() { - return get_zone_params().get_id(); - } + string unique_id(uint64_t unique_num) { char buf[32]; snprintf(buf, sizeof(buf), ".%llu.%llu", (unsigned long long)instance_id(), (unsigned long long)unique_num); diff --git a/src/rgw/rgw_service.h b/src/rgw/rgw_service.h index 04022b358453..f77a14e949e0 100644 --- a/src/rgw/rgw_service.h +++ b/src/rgw/rgw_service.h @@ -35,7 +35,6 @@ public: const std::string& type() { return svc_type; } - virtual std::vector deps() = 0; virtual int create_instance(JSONFormattable& conf, RGWServiceInstanceRef *instance) = 0; }; @@ -52,11 +51,14 @@ protected: string svc_instance; uint64_t svc_id{0}; + virtual std::vector get_deps() { + return vector(); + } + virtual int init(JSONFormattable& conf) = 0; public: RGWServiceInstance(RGWService *svc, CephContext *_cct) : cct(_cct) {} virtual ~RGWServiceInstance(); - virtual int init(JSONFormattable& conf) = 0; string get_title() { return svc->type() + ":" + svc_instance; diff --git a/src/rgw/rgw_zone.cc b/src/rgw/rgw_zone.cc new file mode 100644 index 000000000000..ce2e95631639 --- /dev/null +++ b/src/rgw/rgw_zone.cc @@ -0,0 +1,1848 @@ +#include "rgw_zone.h" + +void RGWDefaultZoneGroupInfo::dump(Formatter *f) const { + encode_json("default_zonegroup", default_zonegroup, f); +} + +void RGWDefaultZoneGroupInfo::decode_json(JSONObj *obj) { + + JSONDecoder::decode_json("default_zonegroup", default_zonegroup, obj); + /* backward compatability with region */ + if (default_zonegroup.empty()) { + JSONDecoder::decode_json("default_region", default_zonegroup, obj); + } +} + +rgw_pool RGWZoneGroup::get_pool(CephContext *cct_) +{ + if (cct_->_conf->rgw_zonegroup_root_pool.empty()) { + return rgw_pool(RGW_DEFAULT_ZONEGROUP_ROOT_POOL); + } + + return rgw_pool(cct_->_conf->rgw_zonegroup_root_pool); +} + +int RGWZoneGroup::create_default(bool old_format) +{ + name = default_zonegroup_name; + api_name = default_zonegroup_name; + is_master = true; + + RGWZoneGroupPlacementTarget placement_target; + placement_target.name = "default-placement"; + placement_targets[placement_target.name] = placement_target; + default_placement = "default-placement"; + + RGWZoneParams zone_params(default_zone_name); + + int r = zone_params.init(cct, store, false); + if (r < 0) { + ldout(cct, 0) << "create_default: error initializing zone params: " << cpp_strerror(-r) << dendl; + return r; + } + + r = zone_params.create_default(); + if (r < 0 && r != -EEXIST) { + ldout(cct, 0) << "create_default: error in create_default zone params: " << cpp_strerror(-r) << dendl; + return r; + } else if (r == -EEXIST) { + ldout(cct, 10) << "zone_params::create_default() returned -EEXIST, we raced with another default zone_params creation" << dendl; + zone_params.clear_id(); + r = zone_params.init(cct, store); + if (r < 0) { + ldout(cct, 0) << "create_default: error in init existing zone params: " << cpp_strerror(-r) << dendl; + return r; + } + ldout(cct, 20) << "zone_params::create_default() " << zone_params.get_name() << " id " << zone_params.get_id() + << dendl; + } + + RGWZone& default_zone = zones[zone_params.get_id()]; + default_zone.name = zone_params.get_name(); + default_zone.id = zone_params.get_id(); + master_zone = default_zone.id; + + r = create(); + if (r < 0 && r != -EEXIST) { + ldout(cct, 0) << "error storing zone group info: " << cpp_strerror(-r) << dendl; + return r; + } + + if (r == -EEXIST) { + ldout(cct, 10) << "create_default() returned -EEXIST, we raced with another zonegroup creation" << dendl; + id.clear(); + r = init(cct, store); + if (r < 0) { + return r; + } + } + + if (old_format) { + name = id; + } + + post_process_params(); + + return 0; +} + +const string RGWZoneGroup::get_default_oid(bool old_region_format) +{ + if (old_region_format) { + if (cct->_conf->rgw_default_region_info_oid.empty()) { + return default_region_info_oid; + } + return cct->_conf->rgw_default_region_info_oid; + } + + string default_oid = cct->_conf->rgw_default_zonegroup_info_oid; + + if (cct->_conf->rgw_default_zonegroup_info_oid.empty()) { + default_oid = default_zone_group_info_oid; + } + + default_oid += "." + realm_id; + + return default_oid; +} + +const string& RGWZoneGroup::get_info_oid_prefix(bool old_region_format) +{ + if (old_region_format) { + return region_info_oid_prefix; + } + return zone_group_info_oid_prefix; +} + +const string& RGWZoneGroup::get_names_oid_prefix() +{ + return zonegroup_names_oid_prefix; +} + +const string& RGWZoneGroup::get_predefined_name(CephContext *cct) { + return cct->_conf->rgw_zonegroup; +} + +int RGWZoneGroup::equals(const string& other_zonegroup) const +{ + if (is_master && other_zonegroup.empty()) + return true; + + return (id == other_zonegroup); +} + +int RGWZoneGroup::add_zone(const RGWZoneParams& zone_params, bool *is_master, bool *read_only, + const list& endpoints, const string *ptier_type, + bool *psync_from_all, list& sync_from, list& sync_from_rm, + string *predirect_zone) +{ + auto& zone_id = zone_params.get_id(); + auto& zone_name = zone_params.get_name(); + + // check for duplicate zone name on insert + if (!zones.count(zone_id)) { + for (const auto& zone : zones) { + if (zone.second.name == zone_name) { + ldout(cct, 0) << "ERROR: found existing zone name " << zone_name + << " (" << zone.first << ") in zonegroup " << get_name() << dendl; + return -EEXIST; + } + } + } + + if (is_master) { + if (*is_master) { + if (!master_zone.empty() && master_zone != zone_id) { + ldout(cct, 0) << "NOTICE: overriding master zone: " << master_zone << dendl; + } + master_zone = zone_id; + } else if (master_zone == zone_id) { + master_zone.clear(); + } + } + + RGWZone& zone = zones[zone_id]; + zone.name = zone_name; + zone.id = zone_id; + if (!endpoints.empty()) { + zone.endpoints = endpoints; + } + if (read_only) { + zone.read_only = *read_only; + } + if (ptier_type) { + zone.tier_type = *ptier_type; + if (!store->get_sync_modules_manager()->get_module(*ptier_type, nullptr)) { + ldout(cct, 0) << "ERROR: could not found sync module: " << *ptier_type + << ", valid sync modules: " + << store->get_sync_modules_manager()->get_registered_module_names() + << dendl; + return -ENOENT; + } + } + + if (psync_from_all) { + zone.sync_from_all = *psync_from_all; + } + + if (predirect_zone) { + zone.redirect_zone = *predirect_zone; + } + + for (auto add : sync_from) { + zone.sync_from.insert(add); + } + + for (auto rm : sync_from_rm) { + zone.sync_from.erase(rm); + } + + post_process_params(); + + return update(); +} + + +int RGWZoneGroup::rename_zone(const RGWZoneParams& zone_params) +{ + RGWZone& zone = zones[zone_params.get_id()]; + zone.name = zone_params.get_name(); + + return update(); +} + +void RGWZoneGroup::post_process_params() +{ + bool log_data = zones.size() > 1; + + if (master_zone.empty()) { + map::iterator iter = zones.begin(); + if (iter != zones.end()) { + master_zone = iter->first; + } + } + + for (map::iterator iter = zones.begin(); iter != zones.end(); ++iter) { + RGWZone& zone = iter->second; + zone.log_data = log_data; + + RGWZoneParams zone_params(zone.id, zone.name); + int ret = zone_params.init(cct, store); + if (ret < 0) { + ldout(cct, 0) << "WARNING: could not read zone params for zone id=" << zone.id << " name=" << zone.name << dendl; + continue; + } + + for (map::iterator iter = zone_params.placement_pools.begin(); + iter != zone_params.placement_pools.end(); ++iter) { + const string& placement_name = iter->first; + if (placement_targets.find(placement_name) == placement_targets.end()) { + RGWZoneGroupPlacementTarget placement_target; + placement_target.name = placement_name; + placement_targets[placement_name] = placement_target; + } + } + } + + if (default_placement.empty() && !placement_targets.empty()) { + default_placement = placement_targets.begin()->first; + } +} + +int RGWZoneGroup::remove_zone(const std::string& zone_id) +{ + map::iterator iter = zones.find(zone_id); + if (iter == zones.end()) { + ldout(cct, 0) << "zone id " << zone_id << " is not a part of zonegroup " + << name << dendl; + return -ENOENT; + } + + zones.erase(iter); + + post_process_params(); + + return update(); +} + +int RGWZoneGroup::read_default_id(string& default_id, bool old_format) +{ + if (realm_id.empty()) { + /* try using default realm */ + RGWRealm realm; + int ret = realm.init(cct, store); + // no default realm exist + if (ret < 0) { + return read_id(default_zonegroup_name, default_id); + } + realm_id = realm.get_id(); + } + + return RGWSystemMetaObj::read_default_id(default_id, old_format); +} + +int RGWZoneGroup::set_as_default(bool exclusive) +{ + if (realm_id.empty()) { + /* try using default realm */ + RGWRealm realm; + int ret = realm.init(cct, store); + if (ret < 0) { + ldout(cct, 10) << "could not read realm id: " << cpp_strerror(-ret) << dendl; + return -EINVAL; + } + realm_id = realm.get_id(); + } + + return RGWSystemMetaObj::set_as_default(exclusive); +} + +int RGWSystemMetaObj::init(CephContext *_cct, RGWRados *_store, bool setup_obj, bool old_format) +{ + cct = _cct; + store = _store; + + if (!setup_obj) + return 0; + + if (old_format && id.empty()) { + id = name; + } + + if (id.empty()) { + int r; + if (name.empty()) { + name = get_predefined_name(cct); + } + if (name.empty()) { + r = use_default(old_format); + if (r < 0) { + return r; + } + } else if (!old_format) { + r = read_id(name, id); + if (r < 0) { + if (r != -ENOENT) { + ldout(cct, 0) << "error in read_id for object name: " << name << " : " << cpp_strerror(-r) << dendl; + } + return r; + } + } + } + + return read_info(id, old_format); +} + +int RGWSystemMetaObj::read_default(RGWDefaultSystemMetaObjInfo& default_info, const string& oid) +{ + using ceph::decode; + auto pool = get_pool(cct); + bufferlist bl; + RGWObjectCtx obj_ctx(store); + int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL); + if (ret < 0) + return ret; + + try { + auto iter = bl.cbegin(); + decode(default_info, iter); + } catch (buffer::error& err) { + ldout(cct, 0) << "error decoding data from " << pool << ":" << oid << dendl; + return -EIO; + } + + return 0; +} + +int RGWSystemMetaObj::read_default_id(string& default_id, bool old_format) +{ + RGWDefaultSystemMetaObjInfo default_info; + + int ret = read_default(default_info, get_default_oid(old_format)); + if (ret < 0) { + return ret; + } + + default_id = default_info.default_id; + + return 0; +} + +int RGWSystemMetaObj::use_default(bool old_format) +{ + return read_default_id(id, old_format); +} + +int RGWSystemMetaObj::set_as_default(bool exclusive) +{ + using ceph::encode; + string oid = get_default_oid(); + + rgw_pool pool(get_pool(cct)); + bufferlist bl; + + RGWDefaultSystemMetaObjInfo default_info; + default_info.default_id = id; + + encode(default_info, bl); + + int ret = rgw_put_system_obj(store, pool, oid, bl, + exclusive, NULL, real_time(), NULL); + if (ret < 0) + return ret; + + return 0; +} + +int RGWSystemMetaObj::read_id(const string& obj_name, string& object_id) +{ + using ceph::decode; + rgw_pool pool(get_pool(cct)); + bufferlist bl; + + string oid = get_names_oid_prefix() + obj_name; + + RGWObjectCtx obj_ctx(store); + int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL); + if (ret < 0) { + return ret; + } + + RGWNameToId nameToId; + try { + auto iter = bl.cbegin(); + decode(nameToId, iter); + } catch (buffer::error& err) { + ldout(cct, 0) << "ERROR: failed to decode obj from " << pool << ":" << oid << dendl; + return -EIO; + } + object_id = nameToId.obj_id; + return 0; +} + +int RGWSystemMetaObj::delete_obj(bool old_format) +{ + rgw_pool pool(get_pool(cct)); + + /* check to see if obj is the default */ + RGWDefaultSystemMetaObjInfo default_info; + int ret = read_default(default_info, get_default_oid(old_format)); + if (ret < 0 && ret != -ENOENT) + return ret; + if (default_info.default_id == id || (old_format && default_info.default_id == name)) { + string oid = get_default_oid(old_format); + rgw_raw_obj default_named_obj(pool, oid); + ret = store->delete_system_obj(default_named_obj); + if (ret < 0) { + ldout(cct, 0) << "Error delete default obj name " << name << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + } + if (!old_format) { + string oid = get_names_oid_prefix() + name; + rgw_raw_obj object_name(pool, oid); + ret = store->delete_system_obj(object_name); + if (ret < 0) { + ldout(cct, 0) << "Error delete obj name " << name << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + } + + string oid = get_info_oid_prefix(old_format); + if (old_format) { + oid += name; + } else { + oid += id; + } + + rgw_raw_obj object_id(pool, oid); + ret = store->delete_system_obj(object_id); + if (ret < 0) { + ldout(cct, 0) << "Error delete object id " << id << ": " << cpp_strerror(-ret) << dendl; + } + + return ret; +} + +int RGWSystemMetaObj::store_name(bool exclusive) +{ + rgw_pool pool(get_pool(cct)); + string oid = get_names_oid_prefix() + name; + + RGWNameToId nameToId; + nameToId.obj_id = id; + + bufferlist bl; + using ceph::encode; + encode(nameToId, bl); + return rgw_put_system_obj(store, pool, oid, bl, exclusive, NULL, real_time(), NULL); +} + +int RGWSystemMetaObj::rename(const string& new_name) +{ + string new_id; + int ret = read_id(new_name, new_id); + if (!ret) { + return -EEXIST; + } + if (ret < 0 && ret != -ENOENT) { + ldout(cct, 0) << "Error read_id " << new_name << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + string old_name = name; + name = new_name; + ret = update(); + if (ret < 0) { + ldout(cct, 0) << "Error storing new obj info " << new_name << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + ret = store_name(true); + if (ret < 0) { + ldout(cct, 0) << "Error storing new name " << new_name << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + /* delete old name */ + rgw_pool pool(get_pool(cct)); + string oid = get_names_oid_prefix() + old_name; + rgw_raw_obj old_name_obj(pool, oid); + ret = store->delete_system_obj(old_name_obj); + if (ret < 0) { + ldout(cct, 0) << "Error delete old obj name " << old_name << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + + return ret; +} + +int RGWSystemMetaObj::read_info(const string& obj_id, bool old_format) +{ + rgw_pool pool(get_pool(cct)); + + bufferlist bl; + + string oid = get_info_oid_prefix(old_format) + obj_id; + + RGWObjectCtx obj_ctx(store); + int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL); + if (ret < 0) { + ldout(cct, 0) << "failed reading obj info from " << pool << ":" << oid << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + using ceph::decode; + + try { + auto iter = bl.cbegin(); + decode(*this, iter); + } catch (buffer::error& err) { + ldout(cct, 0) << "ERROR: failed to decode obj from " << pool << ":" << oid << dendl; + return -EIO; + } + + return 0; +} + +int RGWSystemMetaObj::read() +{ + int ret = read_id(name, id); + if (ret < 0) { + return ret; + } + + return read_info(id); +} + +int RGWSystemMetaObj::create(bool exclusive) +{ + int ret; + + /* check to see the name is not used */ + ret = read_id(name, id); + if (exclusive && ret == 0) { + ldout(cct, 10) << "ERROR: name " << name << " already in use for obj id " << id << dendl; + return -EEXIST; + } else if ( ret < 0 && ret != -ENOENT) { + ldout(cct, 0) << "failed reading obj id " << id << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + + if (id.empty()) { + /* create unique id */ + uuid_d new_uuid; + char uuid_str[37]; + new_uuid.generate_random(); + new_uuid.print(uuid_str); + id = uuid_str; + } + + ret = store_info(exclusive); + if (ret < 0) { + ldout(cct, 0) << "ERROR: storing info for " << id << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + + return store_name(exclusive); +} + +int RGWSystemMetaObj::store_info(bool exclusive) +{ + rgw_pool pool(get_pool(cct)); + + string oid = get_info_oid_prefix() + id; + + bufferlist bl; + using ceph::encode; + encode(*this, bl); + return rgw_put_system_obj(store, pool, oid, bl, exclusive, NULL, real_time(), NULL); +} + +int RGWSystemMetaObj::write(bool exclusive) +{ + int ret = store_info(exclusive); + if (ret < 0) { + ldout(cct, 20) << __func__ << "(): store_info() returned ret=" << ret << dendl; + return ret; + } + ret = store_name(exclusive); + if (ret < 0) { + ldout(cct, 20) << __func__ << "(): store_name() returned ret=" << ret << dendl; + return ret; + } + return 0; +} + + +const string& RGWRealm::get_predefined_name(CephContext *cct) { + return cct->_conf->rgw_realm; +} + +int RGWRealm::create(bool exclusive) +{ + int ret = RGWSystemMetaObj::create(exclusive); + if (ret < 0) { + ldout(cct, 0) << "ERROR creating new realm object " << name << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + // create the control object for watch/notify + ret = create_control(exclusive); + if (ret < 0) { + ldout(cct, 0) << "ERROR creating control for new realm " << name << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + RGWPeriod period; + if (current_period.empty()) { + /* create new period for the realm */ + ret = period.init(cct, store, id, name, false); + if (ret < 0 ) { + return ret; + } + ret = period.create(true); + if (ret < 0) { + ldout(cct, 0) << "ERROR: creating new period for realm " << name << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + } else { + period = RGWPeriod(current_period, 0); + int ret = period.init(cct, store, id, name); + if (ret < 0) { + ldout(cct, 0) << "ERROR: failed to init period " << current_period << dendl; + return ret; + } + } + ret = set_current_period(period); + if (ret < 0) { + ldout(cct, 0) << "ERROR: failed set current period " << current_period << dendl; + return ret; + } + // try to set as default. may race with another create, so pass exclusive=true + // so we don't override an existing default + ret = set_as_default(true); + if (ret < 0 && ret != -EEXIST) { + ldout(cct, 0) << "WARNING: failed to set realm as default realm, ret=" << ret << dendl; + } + + return 0; +} + +int RGWRealm::delete_obj() +{ + int ret = RGWSystemMetaObj::delete_obj(); + if (ret < 0) { + return ret; + } + return delete_control(); +} + +int RGWRealm::create_control(bool exclusive) +{ + auto pool = rgw_pool{get_pool(cct)}; + auto oid = get_control_oid(); + bufferlist bl; + return rgw_put_system_obj(store, pool, oid, bl, exclusive, + nullptr, real_time(), nullptr); +} + +int RGWRealm::delete_control() +{ + auto pool = rgw_pool{get_pool(cct)}; + auto obj = rgw_raw_obj{pool, get_control_oid()}; + return store->delete_system_obj(obj); +} + +rgw_pool RGWRealm::get_pool(CephContext *cct) +{ + if (cct->_conf->rgw_realm_root_pool.empty()) { + return rgw_pool(RGW_DEFAULT_REALM_ROOT_POOL); + } + return rgw_pool(cct->_conf->rgw_realm_root_pool); +} + +const string RGWRealm::get_default_oid(bool old_format) +{ + if (cct->_conf->rgw_default_realm_info_oid.empty()) { + return default_realm_info_oid; + } + return cct->_conf->rgw_default_realm_info_oid; +} + +const string& RGWRealm::get_names_oid_prefix() +{ + return realm_names_oid_prefix; +} + +const string& RGWRealm::get_info_oid_prefix(bool old_format) +{ + return realm_info_oid_prefix; +} + +int RGWRealm::set_current_period(RGWPeriod& period) +{ + // update realm epoch to match the period's + if (epoch > period.get_realm_epoch()) { + ldout(cct, 0) << "ERROR: set_current_period with old realm epoch " + << period.get_realm_epoch() << ", current epoch=" << epoch << dendl; + return -EINVAL; + } + if (epoch == period.get_realm_epoch() && current_period != period.get_id()) { + ldout(cct, 0) << "ERROR: set_current_period with same realm epoch " + << period.get_realm_epoch() << ", but different period id " + << period.get_id() << " != " << current_period << dendl; + return -EINVAL; + } + + epoch = period.get_realm_epoch(); + current_period = period.get_id(); + + int ret = update(); + if (ret < 0) { + ldout(cct, 0) << "ERROR: period update: " << cpp_strerror(-ret) << dendl; + return ret; + } + + ret = period.reflect(); + if (ret < 0) { + ldout(cct, 0) << "ERROR: period.reflect(): " << cpp_strerror(-ret) << dendl; + return ret; + } + + return 0; +} + +string RGWRealm::get_control_oid() +{ + return get_info_oid_prefix() + id + ".control"; +} + +int RGWRealm::notify_zone(bufferlist& bl) +{ + // open a context on the realm's pool + rgw_pool pool{get_pool(cct)}; + librados::IoCtx ctx; + int r = rgw_init_ioctx(store->get_rados_handle(), pool, ctx); + if (r < 0) { + ldout(cct, 0) << "Failed to open pool " << pool << dendl; + return r; + } + // send a notify on the realm object + r = ctx.notify2(get_control_oid(), bl, 0, nullptr); + if (r < 0) { + ldout(cct, 0) << "Realm notify failed with " << r << dendl; + return r; + } + return 0; +} + +int RGWRealm::notify_new_period(const RGWPeriod& period) +{ + bufferlist bl; + using ceph::encode; + // push the period to dependent zonegroups/zones + encode(RGWRealmNotify::ZonesNeedPeriod, bl); + encode(period, bl); + // reload the gateway with the new period + encode(RGWRealmNotify::Reload, bl); + + return notify_zone(bl); +} + +std::string RGWPeriodConfig::get_oid(const std::string& realm_id) +{ + if (realm_id.empty()) { + return "period_config.default"; + } + return "period_config." + realm_id; +} + +rgw_pool RGWPeriodConfig::get_pool(CephContext *cct) +{ + const auto& pool_name = cct->_conf->rgw_period_root_pool; + if (pool_name.empty()) { + return {RGW_DEFAULT_PERIOD_ROOT_POOL}; + } + return {pool_name}; +} + +int RGWPeriodConfig::read(RGWRados *store, const std::string& realm_id) +{ + RGWObjectCtx obj_ctx(store); + const auto& pool = get_pool(store->ctx()); + const auto& oid = get_oid(realm_id); + bufferlist bl; + + int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, nullptr, nullptr); + if (ret < 0) { + return ret; + } + using ceph::decode; + try { + auto iter = bl.cbegin(); + decode(*this, iter); + } catch (buffer::error& err) { + return -EIO; + } + return 0; +} + +int RGWPeriodConfig::write(RGWRados *store, const std::string& realm_id) +{ + const auto& pool = get_pool(store->ctx()); + const auto& oid = get_oid(realm_id); + bufferlist bl; + using ceph::encode; + encode(*this, bl); + return rgw_put_system_obj(store, pool, oid, bl, + false, nullptr, real_time(), nullptr); +} + +int RGWPeriod::init(CephContext *_cct, RGWRados *_store, const string& period_realm_id, + const string& period_realm_name, bool setup_obj) +{ + cct = _cct; + store = _store; + realm_id = period_realm_id; + realm_name = period_realm_name; + + if (!setup_obj) + return 0; + + return init(_cct, _store, setup_obj); +} + + +int RGWPeriod::init(CephContext *_cct, RGWRados *_store, bool setup_obj) +{ + cct = _cct; + store = _store; + + if (!setup_obj) + return 0; + + if (id.empty()) { + RGWRealm realm(realm_id, realm_name); + int ret = realm.init(cct, store); + if (ret < 0) { + ldout(cct, 0) << "RGWPeriod::init failed to init realm " << realm_name << " id " << realm_id << " : " << + cpp_strerror(-ret) << dendl; + return ret; + } + id = realm.get_current_period(); + realm_id = realm.get_id(); + } + + if (!epoch) { + int ret = use_latest_epoch(); + if (ret < 0) { + ldout(cct, 0) << "failed to use_latest_epoch period id " << id << " realm " << realm_name << " id " << realm_id + << " : " << cpp_strerror(-ret) << dendl; + return ret; + } + } + + return read_info(); +} + + +int RGWPeriod::get_zonegroup(RGWZoneGroup& zonegroup, const string& zonegroup_id) { + map::const_iterator iter; + if (!zonegroup_id.empty()) { + iter = period_map.zonegroups.find(zonegroup_id); + } else { + iter = period_map.zonegroups.find("default"); + } + if (iter != period_map.zonegroups.end()) { + zonegroup = iter->second; + return 0; + } + + return -ENOENT; +} + +bool RGWRados::get_redirect_zone_endpoint(string *endpoint) +{ + if (zone_public_config.redirect_zone.empty()) { + return false; + } + + auto iter = zone_conn_map.find(zone_public_config.redirect_zone); + if (iter == zone_conn_map.end()) { + ldout(cct, 0) << "ERROR: cannot find entry for redirect zone: " << zone_public_config.redirect_zone << dendl; + return false; + } + + RGWRESTConn *conn = iter->second; + + int ret = conn->get_url(*endpoint); + if (ret < 0) { + ldout(cct, 0) << "ERROR: redirect zone, conn->get_endpoint() returned ret=" << ret << dendl; + return false; + } + + return true; +} + +const string& RGWPeriod::get_latest_epoch_oid() +{ + if (cct->_conf->rgw_period_latest_epoch_info_oid.empty()) { + return period_latest_epoch_info_oid; + } + return cct->_conf->rgw_period_latest_epoch_info_oid; +} + +const string& RGWPeriod::get_info_oid_prefix() +{ + return period_info_oid_prefix; +} + +const string RGWPeriod::get_period_oid_prefix() +{ + return get_info_oid_prefix() + id; +} + +const string RGWPeriod::get_period_oid() +{ + std::ostringstream oss; + oss << get_period_oid_prefix(); + // skip the epoch for the staging period + if (id != get_staging_id(realm_id)) + oss << "." << epoch; + return oss.str(); +} + +int RGWPeriod::read_latest_epoch(RGWPeriodLatestEpochInfo& info, + RGWObjVersionTracker *objv) +{ + string oid = get_period_oid_prefix() + get_latest_epoch_oid(); + + rgw_pool pool(get_pool(cct)); + bufferlist bl; + RGWObjectCtx obj_ctx(store); + int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, objv, nullptr); + if (ret < 0) { + ldout(cct, 1) << "error read_lastest_epoch " << pool << ":" << oid << dendl; + return ret; + } + try { + auto iter = bl.cbegin(); + using ceph::decode; + decode(info, iter); + } catch (buffer::error& err) { + ldout(cct, 0) << "error decoding data from " << pool << ":" << oid << dendl; + return -EIO; + } + + return 0; +} + +int RGWPeriod::get_latest_epoch(epoch_t& latest_epoch) +{ + RGWPeriodLatestEpochInfo info; + + int ret = read_latest_epoch(info); + if (ret < 0) { + return ret; + } + + latest_epoch = info.epoch; + + return 0; +} + +int RGWPeriod::use_latest_epoch() +{ + RGWPeriodLatestEpochInfo info; + int ret = read_latest_epoch(info); + if (ret < 0) { + return ret; + } + + epoch = info.epoch; + + return 0; +} + +int RGWPeriod::set_latest_epoch(epoch_t epoch, bool exclusive, + RGWObjVersionTracker *objv) +{ + string oid = get_period_oid_prefix() + get_latest_epoch_oid(); + + rgw_pool pool(get_pool(cct)); + bufferlist bl; + + RGWPeriodLatestEpochInfo info; + info.epoch = epoch; + + using ceph::encode; + encode(info, bl); + + return rgw_put_system_obj(store, pool, oid, bl, + exclusive, objv, real_time(), nullptr); +} + +int RGWPeriod::update_latest_epoch(epoch_t epoch) +{ + static constexpr int MAX_RETRIES = 20; + + for (int i = 0; i < MAX_RETRIES; i++) { + RGWPeriodLatestEpochInfo info; + RGWObjVersionTracker objv; + bool exclusive = false; + + // read existing epoch + int r = read_latest_epoch(info, &objv); + if (r == -ENOENT) { + // use an exclusive create to set the epoch atomically + exclusive = true; + ldout(cct, 20) << "creating initial latest_epoch=" << epoch + << " for period=" << id << dendl; + } else if (r < 0) { + ldout(cct, 0) << "ERROR: failed to read latest_epoch" << dendl; + return r; + } else if (epoch <= info.epoch) { + r = -EEXIST; // fail with EEXIST if epoch is not newer + ldout(cct, 1) << "found existing latest_epoch " << info.epoch + << " >= given epoch " << epoch << ", returning r=" << r << dendl; + return r; + } else { + ldout(cct, 20) << "updating latest_epoch from " << info.epoch + << " -> " << epoch << " on period=" << id << dendl; + } + + r = set_latest_epoch(epoch, exclusive, &objv); + if (r == -EEXIST) { + continue; // exclusive create raced with another update, retry + } else if (r == -ECANCELED) { + continue; // write raced with a conflicting version, retry + } + if (r < 0) { + ldout(cct, 0) << "ERROR: failed to write latest_epoch" << dendl; + return r; + } + return 0; // return success + } + + return -ECANCELED; // fail after max retries +} + +int RGWPeriod::delete_obj() +{ + rgw_pool pool(get_pool(cct)); + + // delete the object for each period epoch + for (epoch_t e = 1; e <= epoch; e++) { + RGWPeriod p{get_id(), e}; + rgw_raw_obj oid{pool, p.get_period_oid()}; + int ret = store->delete_system_obj(oid); + if (ret < 0) { + ldout(cct, 0) << "WARNING: failed to delete period object " << oid + << ": " << cpp_strerror(-ret) << dendl; + } + } + + // delete the .latest_epoch object + rgw_raw_obj oid{pool, get_period_oid_prefix() + get_latest_epoch_oid()}; + int ret = store->delete_system_obj(oid); + if (ret < 0) { + ldout(cct, 0) << "WARNING: failed to delete period object " << oid + << ": " << cpp_strerror(-ret) << dendl; + } + return ret; +} + +int RGWPeriod::read_info() +{ + rgw_pool pool(get_pool(cct)); + + bufferlist bl; + + RGWObjectCtx obj_ctx(store); + int ret = rgw_get_system_obj(store, obj_ctx, pool, get_period_oid(), bl, NULL, NULL); + if (ret < 0) { + ldout(cct, 0) << "failed reading obj info from " << pool << ":" << get_period_oid() << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + + try { + using ceph::decode; + auto iter = bl.cbegin(); + decode(*this, iter); + } catch (buffer::error& err) { + ldout(cct, 0) << "ERROR: failed to decode obj from " << pool << ":" << get_period_oid() << dendl; + return -EIO; + } + + return 0; +} + +int RGWPeriod::create(bool exclusive) +{ + int ret; + + /* create unique id */ + uuid_d new_uuid; + char uuid_str[37]; + new_uuid.generate_random(); + new_uuid.print(uuid_str); + id = uuid_str; + + epoch = FIRST_EPOCH; + + period_map.id = id; + + ret = store_info(exclusive); + if (ret < 0) { + ldout(cct, 0) << "ERROR: storing info for " << id << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + + ret = set_latest_epoch(epoch); + if (ret < 0) { + ldout(cct, 0) << "ERROR: setting latest epoch " << id << ": " << cpp_strerror(-ret) << dendl; + } + + return ret; +} + +int RGWPeriod::store_info(bool exclusive) +{ + rgw_pool pool(get_pool(cct)); + + string oid = get_period_oid(); + bufferlist bl; + using ceph::encode; + encode(*this, bl); + + return rgw_put_system_obj(store, pool, oid, bl, + exclusive, NULL, real_time(), NULL); +} + +rgw_pool RGWPeriod::get_pool(CephContext *cct) +{ + if (cct->_conf->rgw_period_root_pool.empty()) { + return rgw_pool(RGW_DEFAULT_PERIOD_ROOT_POOL); + } + return rgw_pool(cct->_conf->rgw_period_root_pool); +} + +int RGWPeriod::add_zonegroup(const RGWZoneGroup& zonegroup) +{ + if (zonegroup.realm_id != realm_id) { + return 0; + } + int ret = period_map.update(zonegroup, cct); + if (ret < 0) { + ldout(cct, 0) << "ERROR: updating period map: " << cpp_strerror(-ret) << dendl; + return ret; + } + + return store_info(false); +} + +int RGWPeriod::update() +{ + ldout(cct, 20) << __func__ << " realm " << realm_id << " period " << get_id() << dendl; + list zonegroups; + int ret = store->list_zonegroups(zonegroups); + if (ret < 0) { + ldout(cct, 0) << "ERROR: failed to list zonegroups: " << cpp_strerror(-ret) << dendl; + return ret; + } + + // clear zone short ids of removed zones. period_map.update() will add the + // remaining zones back + period_map.short_zone_ids.clear(); + + for (auto& iter : zonegroups) { + RGWZoneGroup zg(string(), iter); + ret = zg.init(cct, store); + if (ret < 0) { + ldout(cct, 0) << "WARNING: zg.init() failed: " << cpp_strerror(-ret) << dendl; + continue; + } + + if (zg.realm_id != realm_id) { + ldout(cct, 20) << "skipping zonegroup " << zg.get_name() << " zone realm id " << zg.realm_id << ", not on our realm " << realm_id << dendl; + continue; + } + + if (zg.master_zone.empty()) { + ldout(cct, 0) << "ERROR: zonegroup " << zg.get_name() << " should have a master zone " << dendl; + return -EINVAL; + } + + if (zg.is_master_zonegroup()) { + master_zonegroup = zg.get_id(); + master_zone = zg.master_zone; + } + + int ret = period_map.update(zg, cct); + if (ret < 0) { + return ret; + } + } + + ret = period_config.read(store, realm_id); + if (ret < 0 && ret != -ENOENT) { + ldout(cct, 0) << "ERROR: failed to read period config: " + << cpp_strerror(ret) << dendl; + return ret; + } + return 0; +} + +int RGWPeriod::reflect() +{ + for (auto& iter : period_map.zonegroups) { + RGWZoneGroup& zg = iter.second; + zg.reinit_instance(cct, store); + int r = zg.write(false); + if (r < 0) { + ldout(cct, 0) << "ERROR: failed to store zonegroup info for zonegroup=" << iter.first << ": " << cpp_strerror(-r) << dendl; + return r; + } + if (zg.is_master_zonegroup()) { + // set master as default if no default exists + r = zg.set_as_default(true); + if (r == 0) { + ldout(cct, 1) << "Set the period's master zonegroup " << zg.get_id() + << " as the default" << dendl; + } + } + } + + int r = period_config.write(store, realm_id); + if (r < 0) { + ldout(cct, 0) << "ERROR: failed to store period config: " + << cpp_strerror(-r) << dendl; + return r; + } + return 0; +} + +void RGWPeriod::fork() +{ + ldout(cct, 20) << __func__ << " realm " << realm_id << " period " << id << dendl; + predecessor_uuid = id; + id = get_staging_id(realm_id); + period_map.reset(); + realm_epoch++; +} + +static int read_sync_status(RGWRados *store, rgw_meta_sync_status *sync_status) +{ + // initialize a sync status manager to read the status + RGWMetaSyncStatusManager mgr(store, store->get_async_rados()); + int r = mgr.init(); + if (r < 0) { + return r; + } + r = mgr.read_sync_status(sync_status); + mgr.stop(); + return r; +} + +int RGWPeriod::update_sync_status(const RGWPeriod ¤t_period, + std::ostream& error_stream, + bool force_if_stale) +{ + rgw_meta_sync_status status; + int r = read_sync_status(store, &status); + if (r < 0) { + ldout(cct, 0) << "period failed to read sync status: " + << cpp_strerror(-r) << dendl; + return r; + } + + std::vector markers; + + const auto current_epoch = current_period.get_realm_epoch(); + if (current_epoch != status.sync_info.realm_epoch) { + // no sync status markers for the current period + ceph_assert(current_epoch > status.sync_info.realm_epoch); + const int behind = current_epoch - status.sync_info.realm_epoch; + if (!force_if_stale && current_epoch > 1) { + error_stream << "ERROR: This zone is " << behind << " period(s) behind " + "the current master zone in metadata sync. If this zone is promoted " + "to master, any metadata changes during that time are likely to " + "be lost.\n" + "Waiting for this zone to catch up on metadata sync (see " + "'radosgw-admin sync status') is recommended.\n" + "To promote this zone to master anyway, add the flag " + "--yes-i-really-mean-it." << std::endl; + return -EINVAL; + } + // empty sync status markers - other zones will skip this period during + // incremental metadata sync + markers.resize(status.sync_info.num_shards); + } else { + markers.reserve(status.sync_info.num_shards); + for (auto& i : status.sync_markers) { + auto& marker = i.second; + // filter out markers from other periods + if (marker.realm_epoch != current_epoch) { + marker.marker.clear(); + } + markers.emplace_back(std::move(marker.marker)); + } + } + + std::swap(sync_status, markers); + return 0; +} + +int RGWPeriod::commit(RGWRealm& realm, const RGWPeriod& current_period, + std::ostream& error_stream, bool force_if_stale) +{ + ldout(cct, 20) << __func__ << " realm " << realm.get_id() << " period " << current_period.get_id() << dendl; + // gateway must be in the master zone to commit + if (master_zone != store->get_zone_params().get_id()) { + error_stream << "Cannot commit period on zone " + << store->get_zone_params().get_id() << ", it must be sent to " + "the period's master zone " << master_zone << '.' << std::endl; + return -EINVAL; + } + // period predecessor must match current period + if (predecessor_uuid != current_period.get_id()) { + error_stream << "Period predecessor " << predecessor_uuid + << " does not match current period " << current_period.get_id() + << ". Use 'period pull' to get the latest period from the master, " + "reapply your changes, and try again." << std::endl; + return -EINVAL; + } + // realm epoch must be 1 greater than current period + if (realm_epoch != current_period.get_realm_epoch() + 1) { + error_stream << "Period's realm epoch " << realm_epoch + << " does not come directly after current realm epoch " + << current_period.get_realm_epoch() << ". Use 'realm pull' to get the " + "latest realm and period from the master zone, reapply your changes, " + "and try again." << std::endl; + return -EINVAL; + } + // did the master zone change? + if (master_zone != current_period.get_master_zone()) { + // store the current metadata sync status in the period + int r = update_sync_status(current_period, error_stream, force_if_stale); + if (r < 0) { + ldout(cct, 0) << "failed to update metadata sync status: " + << cpp_strerror(-r) << dendl; + return r; + } + // create an object with a new period id + r = create(true); + if (r < 0) { + ldout(cct, 0) << "failed to create new period: " << cpp_strerror(-r) << dendl; + return r; + } + // set as current period + r = realm.set_current_period(*this); + if (r < 0) { + ldout(cct, 0) << "failed to update realm's current period: " + << cpp_strerror(-r) << dendl; + return r; + } + ldout(cct, 4) << "Promoted to master zone and committed new period " + << id << dendl; + realm.notify_new_period(*this); + return 0; + } + // period must be based on current epoch + if (epoch != current_period.get_epoch()) { + error_stream << "Period epoch " << epoch << " does not match " + "predecessor epoch " << current_period.get_epoch() + << ". Use 'period pull' to get the latest epoch from the master zone, " + "reapply your changes, and try again." << std::endl; + return -EINVAL; + } + // set period as next epoch + set_id(current_period.get_id()); + set_epoch(current_period.get_epoch() + 1); + set_predecessor(current_period.get_predecessor()); + realm_epoch = current_period.get_realm_epoch(); + // write the period to rados + int r = store_info(false); + if (r < 0) { + ldout(cct, 0) << "failed to store period: " << cpp_strerror(-r) << dendl; + return r; + } + // set as latest epoch + r = update_latest_epoch(epoch); + if (r == -EEXIST) { + // already have this epoch (or a more recent one) + return 0; + } + if (r < 0) { + ldout(cct, 0) << "failed to set latest epoch: " << cpp_strerror(-r) << dendl; + return r; + } + r = reflect(); + if (r < 0) { + ldout(cct, 0) << "failed to update local objects: " << cpp_strerror(-r) << dendl; + return r; + } + ldout(cct, 4) << "Committed new epoch " << epoch + << " for period " << id << dendl; + realm.notify_new_period(*this); + return 0; +} + +int RGWZoneParams::create_default(bool old_format) +{ + name = default_zone_name; + + int r = create(); + if (r < 0) { + return r; + } + + if (old_format) { + name = id; + } + + return r; +} + + +int get_zones_pool_set(CephContext* cct, + RGWRados* store, + const list& zones, + const string& my_zone_id, + set& pool_names) +{ + for(auto const& iter : zones) { + RGWZoneParams zone(iter); + int r = zone.init(cct, store); + if (r < 0) { + ldout(cct, 0) << "Error: init zone " << iter << ":" << cpp_strerror(-r) << dendl; + return r; + } + if (zone.get_id() != my_zone_id) { + pool_names.insert(zone.domain_root); + pool_names.insert(zone.metadata_heap); + pool_names.insert(zone.control_pool); + pool_names.insert(zone.gc_pool); + pool_names.insert(zone.log_pool); + pool_names.insert(zone.intent_log_pool); + pool_names.insert(zone.usage_log_pool); + pool_names.insert(zone.user_keys_pool); + pool_names.insert(zone.user_email_pool); + pool_names.insert(zone.user_swift_pool); + pool_names.insert(zone.user_uid_pool); + pool_names.insert(zone.otp_pool); + pool_names.insert(zone.roles_pool); + pool_names.insert(zone.reshard_pool); + for(auto& iter : zone.placement_pools) { + pool_names.insert(iter.second.index_pool); + pool_names.insert(iter.second.data_pool); + pool_names.insert(iter.second.data_extra_pool); + } + } + } + return 0; +} + +rgw_pool fix_zone_pool_dup(set pools, + const string& default_prefix, + const string& default_suffix, + const rgw_pool& suggested_pool) +{ + string suggested_name = suggested_pool.to_str(); + + string prefix = default_prefix; + string suffix = default_suffix; + + if (!suggested_pool.empty()) { + prefix = suggested_name.substr(0, suggested_name.find(".")); + suffix = suggested_name.substr(prefix.length()); + } + + rgw_pool pool(prefix + suffix); + + if (pools.find(pool) == pools.end()) { + return pool; + } else { + while(true) { + pool = prefix + "_" + std::to_string(std::rand()) + suffix; + if (pools.find(pool) == pools.end()) { + return pool; + } + } + } +} + +int RGWZoneParams::fix_pool_names() +{ + + list zones; + int r = store->list_zones(zones); + if (r < 0) { + ldout(cct, 10) << "WARNING: store->list_zones() returned r=" << r << dendl; + } + + set pools; + r = get_zones_pool_set(cct, store, zones, id, pools); + if (r < 0) { + ldout(cct, 0) << "Error: get_zones_pool_names" << r << dendl; + return r; + } + + domain_root = fix_zone_pool_dup(pools, name, ".rgw.meta:root", domain_root); + if (!metadata_heap.name.empty()) { + metadata_heap = fix_zone_pool_dup(pools, name, ".rgw.meta:heap", metadata_heap); + } + control_pool = fix_zone_pool_dup(pools, name, ".rgw.control", control_pool); + gc_pool = fix_zone_pool_dup(pools, name ,".rgw.log:gc", gc_pool); + lc_pool = fix_zone_pool_dup(pools, name ,".rgw.log:lc", lc_pool); + log_pool = fix_zone_pool_dup(pools, name, ".rgw.log", log_pool); + intent_log_pool = fix_zone_pool_dup(pools, name, ".rgw.log:intent", intent_log_pool); + usage_log_pool = fix_zone_pool_dup(pools, name, ".rgw.log:usage", usage_log_pool); + user_keys_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.keys", user_keys_pool); + user_email_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.email", user_email_pool); + user_swift_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.swift", user_swift_pool); + user_uid_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:users.uid", user_uid_pool); + roles_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:roles", roles_pool); + reshard_pool = fix_zone_pool_dup(pools, name, ".rgw.log:reshard", reshard_pool); + otp_pool = fix_zone_pool_dup(pools, name, ".rgw.otp", otp_pool); + + for(auto& iter : placement_pools) { + iter.second.index_pool = fix_zone_pool_dup(pools, name, "." + default_bucket_index_pool_suffix, + iter.second.index_pool); + iter.second.data_pool = fix_zone_pool_dup(pools, name, "." + default_storage_pool_suffix, + iter.second.data_pool); + iter.second.data_extra_pool= fix_zone_pool_dup(pools, name, "." + default_storage_extra_pool_suffix, + iter.second.data_extra_pool); + } + + return 0; +} + +int RGWZoneParams::create(bool exclusive) +{ + /* check for old pools config */ + rgw_raw_obj obj(domain_root, avail_pools); + int r = store->raw_obj_stat(obj, NULL, NULL, NULL, NULL, NULL, NULL); + if (r < 0) { + ldout(store->ctx(), 10) << "couldn't find old data placement pools config, setting up new ones for the zone" << dendl; + /* a new system, let's set new placement info */ + RGWZonePlacementInfo default_placement; + default_placement.index_pool = name + "." + default_bucket_index_pool_suffix; + default_placement.data_pool = name + "." + default_storage_pool_suffix; + default_placement.data_extra_pool = name + "." + default_storage_extra_pool_suffix; + placement_pools["default-placement"] = default_placement; + } + + r = fix_pool_names(); + if (r < 0) { + ldout(cct, 0) << "ERROR: fix_pool_names returned r=" << r << dendl; + return r; + } + + r = RGWSystemMetaObj::create(exclusive); + if (r < 0) { + return r; + } + + // try to set as default. may race with another create, so pass exclusive=true + // so we don't override an existing default + r = set_as_default(true); + if (r < 0 && r != -EEXIST) { + ldout(cct, 10) << "WARNING: failed to set zone as default, r=" << r << dendl; + } + + return 0; +} + +rgw_pool RGWZoneParams::get_pool(CephContext *cct) +{ + if (cct->_conf->rgw_zone_root_pool.empty()) { + return rgw_pool(RGW_DEFAULT_ZONE_ROOT_POOL); + } + + return rgw_pool(cct->_conf->rgw_zone_root_pool); +} + +const string RGWZoneParams::get_default_oid(bool old_format) +{ + if (old_format) { + return cct->_conf->rgw_default_zone_info_oid; + } + + return cct->_conf->rgw_default_zone_info_oid + "." + realm_id; +} + +const string& RGWZoneParams::get_names_oid_prefix() +{ + return zone_names_oid_prefix; +} + +const string& RGWZoneParams::get_info_oid_prefix(bool old_format) +{ + return zone_info_oid_prefix; +} + +const string& RGWZoneParams::get_predefined_name(CephContext *cct) { + return cct->_conf->rgw_zone; +} + +int RGWZoneParams::init(CephContext *cct, RGWRados *store, bool setup_obj, bool old_format) +{ + if (name.empty()) { + name = cct->_conf->rgw_zone; + } + + return RGWSystemMetaObj::init(cct, store, setup_obj, old_format); +} + +int RGWZoneParams::read_default_id(string& default_id, bool old_format) +{ + if (realm_id.empty()) { + /* try using default realm */ + RGWRealm realm; + int ret = realm.init(cct, store); + //no default realm exist + if (ret < 0) { + return read_id(default_zone_name, default_id); + } + realm_id = realm.get_id(); + } + + return RGWSystemMetaObj::read_default_id(default_id, old_format); +} + + +int RGWZoneParams::set_as_default(bool exclusive) +{ + if (realm_id.empty()) { + /* try using default realm */ + RGWRealm realm; + int ret = realm.init(cct, store); + if (ret < 0) { + ldout(cct, 10) << "could not read realm id: " << cpp_strerror(-ret) << dendl; + return -EINVAL; + } + realm_id = realm.get_id(); + } + + return RGWSystemMetaObj::set_as_default(exclusive); +} + +const string& RGWZoneParams::get_compression_type(const string& placement_rule) const +{ + static const std::string NONE{"none"}; + auto p = placement_pools.find(placement_rule); + if (p == placement_pools.end()) { + return NONE; + } + const auto& type = p->second.compression_type; + return !type.empty() ? type : NONE; +} + +void RGWPeriodMap::encode(bufferlist& bl) const { + ENCODE_START(2, 1, bl); + encode(id, bl); + encode(zonegroups, bl); + encode(master_zonegroup, bl); + encode(short_zone_ids, bl); + ENCODE_FINISH(bl); +} + +void RGWPeriodMap::decode(bufferlist::const_iterator& bl) { + DECODE_START(2, bl); + decode(id, bl); + decode(zonegroups, bl); + decode(master_zonegroup, bl); + if (struct_v >= 2) { + decode(short_zone_ids, bl); + } + DECODE_FINISH(bl); + + zonegroups_by_api.clear(); + for (map::iterator iter = zonegroups.begin(); + iter != zonegroups.end(); ++iter) { + RGWZoneGroup& zonegroup = iter->second; + zonegroups_by_api[zonegroup.api_name] = zonegroup; + if (zonegroup.is_master_zonegroup()) { + master_zonegroup = zonegroup.get_id(); + } + } +} + +// run an MD5 hash on the zone_id and return the first 32 bits +static uint32_t gen_short_zone_id(const std::string zone_id) +{ + unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE]; + MD5 hash; + hash.Update((const unsigned char *)zone_id.c_str(), zone_id.size()); + hash.Final(md5); + + uint32_t short_id; + memcpy((char *)&short_id, md5, sizeof(short_id)); + return std::max(short_id, 1u); +} + +int RGWPeriodMap::update(const RGWZoneGroup& zonegroup, CephContext *cct) +{ + if (zonegroup.is_master_zonegroup() && (!master_zonegroup.empty() && zonegroup.get_id() != master_zonegroup)) { + ldout(cct,0) << "Error updating periodmap, multiple master zonegroups configured "<< dendl; + ldout(cct,0) << "master zonegroup: " << master_zonegroup << " and " << zonegroup.get_id() <::iterator iter = zonegroups.find(zonegroup.get_id()); + if (iter != zonegroups.end()) { + RGWZoneGroup& old_zonegroup = iter->second; + if (!old_zonegroup.api_name.empty()) { + zonegroups_by_api.erase(old_zonegroup.api_name); + } + } + zonegroups[zonegroup.get_id()] = zonegroup; + + if (!zonegroup.api_name.empty()) { + zonegroups_by_api[zonegroup.api_name] = zonegroup; + } + + if (zonegroup.is_master_zonegroup()) { + master_zonegroup = zonegroup.get_id(); + } else if (master_zonegroup == zonegroup.get_id()) { + master_zonegroup = ""; + } + + for (auto& i : zonegroup.zones) { + auto& zone = i.second; + if (short_zone_ids.find(zone.id) != short_zone_ids.end()) { + continue; + } + // calculate the zone's short id + uint32_t short_id = gen_short_zone_id(zone.id); + + // search for an existing zone with the same short id + for (auto& s : short_zone_ids) { + if (s.second == short_id) { + ldout(cct, 0) << "New zone '" << zone.name << "' (" << zone.id + << ") generates the same short_zone_id " << short_id + << " as existing zone id " << s.first << dendl; + return -EEXIST; + } + } + + short_zone_ids[zone.id] = short_id; + } + + return 0; +} + +uint32_t RGWPeriodMap::get_zone_short_id(const string& zone_id) const +{ + auto i = short_zone_ids.find(zone_id); + if (i == short_zone_ids.end()) { + return 0; + } + return i->second; +} + +int RGWZoneGroupMap::read(CephContext *cct, RGWRados *store) +{ + + RGWPeriod period; + int ret = period.init(cct, store); + if (ret < 0) { + cerr << "failed to read current period info: " << cpp_strerror(ret); + return ret; + } + + bucket_quota = period.get_config().bucket_quota; + user_quota = period.get_config().user_quota; + zonegroups = period.get_map().zonegroups; + zonegroups_by_api = period.get_map().zonegroups_by_api; + master_zonegroup = period.get_map().master_zonegroup; + + return 0; +} + +void RGWRegionMap::encode(bufferlist& bl) const { + ENCODE_START( 3, 1, bl); + encode(regions, bl); + encode(master_region, bl); + encode(bucket_quota, bl); + encode(user_quota, bl); + ENCODE_FINISH(bl); +} + +void RGWRegionMap::decode(bufferlist::const_iterator& bl) { + DECODE_START(3, bl); + decode(regions, bl); + decode(master_region, bl); + if (struct_v >= 2) + decode(bucket_quota, bl); + if (struct_v >= 3) + decode(user_quota, bl); + DECODE_FINISH(bl); +} + +void RGWZoneGroupMap::encode(bufferlist& bl) const { + ENCODE_START( 3, 1, bl); + encode(zonegroups, bl); + encode(master_zonegroup, bl); + encode(bucket_quota, bl); + encode(user_quota, bl); + ENCODE_FINISH(bl); +} + +void RGWZoneGroupMap::decode(bufferlist::const_iterator& bl) { + DECODE_START(3, bl); + decode(zonegroups, bl); + decode(master_zonegroup, bl); + if (struct_v >= 2) + decode(bucket_quota, bl); + if (struct_v >= 3) + decode(user_quota, bl); + DECODE_FINISH(bl); + + zonegroups_by_api.clear(); + for (map::iterator iter = zonegroups.begin(); + iter != zonegroups.end(); ++iter) { + RGWZoneGroup& zonegroup = iter->second; + zonegroups_by_api[zonegroup.api_name] = zonegroup; + if (zonegroup.is_master_zonegroup()) { + master_zonegroup = zonegroup.get_name(); + } + } +} + + diff --git a/src/rgw/rgw_zone.h b/src/rgw/rgw_zone.h new file mode 100644 index 000000000000..e66d4ab945b8 --- /dev/null +++ b/src/rgw/rgw_zone.h @@ -0,0 +1,941 @@ +#ifndef CEPH_RGW_ZONE_H +#define CEPH_RGW_ZONE_H + +class RGWSystemMetaObj { +protected: + string id; + string name; + + CephContext *cct; + RGWRados *store; + + int store_name(bool exclusive); + int store_info(bool exclusive); + int read_info(const string& obj_id, bool old_format = false); + int read_id(const string& obj_name, string& obj_id); + int read_default(RGWDefaultSystemMetaObjInfo& default_info, + const string& oid); + /* read and use default id */ + int use_default(bool old_format = false); + +public: + RGWSystemMetaObj() : cct(NULL), store(NULL) {} + RGWSystemMetaObj(const string& _name): name(_name), cct(NULL), store(NULL) {} + RGWSystemMetaObj(const string& _id, const string& _name) : id(_id), name(_name), cct(NULL), store(NULL) {} + RGWSystemMetaObj(CephContext *_cct, RGWRados *_store): cct(_cct), store(_store){} + RGWSystemMetaObj(const string& _name, CephContext *_cct, RGWRados *_store): name(_name), cct(_cct), store(_store){} + const string& get_name() const { return name; } + const string& get_id() const { return id; } + + void set_name(const string& _name) { name = _name;} + void set_id(const string& _id) { id = _id;} + void clear_id() { id.clear(); } + + virtual ~RGWSystemMetaObj() {} + + virtual void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(id, bl); + encode(name, bl); + ENCODE_FINISH(bl); + } + + virtual void decode(bufferlist::const_iterator& bl) { + DECODE_START(1, bl); + decode(id, bl); + decode(name, bl); + DECODE_FINISH(bl); + } + + void reinit_instance(CephContext *_cct, RGWRados *_store) { + cct = _cct; + store = _store; + } + int init(CephContext *_cct, RGWRados *_store, bool setup_obj = true, bool old_format = false); + virtual int read_default_id(string& default_id, bool old_format = false); + virtual int set_as_default(bool exclusive = false); + int delete_default(); + virtual int create(bool exclusive = true); + int delete_obj(bool old_format = false); + int rename(const string& new_name); + int update() { return store_info(false);} + int update_name() { return store_name(false);} + int read(); + int write(bool exclusive); + + virtual rgw_pool get_pool(CephContext *cct) = 0; + virtual const string get_default_oid(bool old_format = false) = 0; + virtual const string& get_names_oid_prefix() = 0; + virtual const string& get_info_oid_prefix(bool old_format = false) = 0; + virtual const string& get_predefined_name(CephContext *cct) = 0; + + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); +}; +WRITE_CLASS_ENCODER(RGWSystemMetaObj) + +struct RGWZonePlacementInfo { + rgw_pool index_pool; + rgw_pool data_pool; + rgw_pool data_extra_pool; /* if not set we should use data_pool */ + RGWBucketIndexType index_type; + std::string compression_type; + + RGWZonePlacementInfo() : index_type(RGWBIType_Normal) {} + + void encode(bufferlist& bl) const { + ENCODE_START(6, 1, bl); + encode(index_pool.to_str(), bl); + encode(data_pool.to_str(), bl); + encode(data_extra_pool.to_str(), bl); + encode((uint32_t)index_type, bl); + encode(compression_type, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + DECODE_START(6, bl); + string index_pool_str; + string data_pool_str; + decode(index_pool_str, bl); + index_pool = rgw_pool(index_pool_str); + decode(data_pool_str, bl); + data_pool = rgw_pool(data_pool_str); + if (struct_v >= 4) { + string data_extra_pool_str; + decode(data_extra_pool_str, bl); + data_extra_pool = rgw_pool(data_extra_pool_str); + } + if (struct_v >= 5) { + uint32_t it; + decode(it, bl); + index_type = (RGWBucketIndexType)it; + } + if (struct_v >= 6) { + decode(compression_type, bl); + } + DECODE_FINISH(bl); + } + const rgw_pool& get_data_extra_pool() const { + if (data_extra_pool.empty()) { + return data_pool; + } + return data_extra_pool; + } + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); +}; +WRITE_CLASS_ENCODER(RGWZonePlacementInfo) + +struct RGWZoneParams : RGWSystemMetaObj { + rgw_pool domain_root; + rgw_pool metadata_heap; + rgw_pool control_pool; + rgw_pool gc_pool; + rgw_pool lc_pool; + rgw_pool log_pool; + rgw_pool intent_log_pool; + rgw_pool usage_log_pool; + + rgw_pool user_keys_pool; + rgw_pool user_email_pool; + rgw_pool user_swift_pool; + rgw_pool user_uid_pool; + rgw_pool roles_pool; + rgw_pool reshard_pool; + rgw_pool otp_pool; + + RGWAccessKey system_key; + + map placement_pools; + + string realm_id; + + JSONFormattable tier_config; + + RGWZoneParams() : RGWSystemMetaObj() {} + explicit RGWZoneParams(const string& name) : RGWSystemMetaObj(name){} + RGWZoneParams(const string& id, const string& name) : RGWSystemMetaObj(id, name) {} + RGWZoneParams(const string& id, const string& name, const string& _realm_id) + : RGWSystemMetaObj(id, name), realm_id(_realm_id) {} + + rgw_pool get_pool(CephContext *cct) override; + const string get_default_oid(bool old_format = false) override; + const string& get_names_oid_prefix() override; + const string& get_info_oid_prefix(bool old_format = false) override; + const string& get_predefined_name(CephContext *cct) override; + + int init(CephContext *_cct, RGWRados *_store, bool setup_obj = true, + bool old_format = false); + using RGWSystemMetaObj::init; + int read_default_id(string& default_id, bool old_format = false) override; + int set_as_default(bool exclusive = false) override; + int create_default(bool old_format = false); + int create(bool exclusive = true) override; + int fix_pool_names(); + + const string& get_compression_type(const string& placement_rule) const; + + void encode(bufferlist& bl) const override { + ENCODE_START(12, 1, bl); + encode(domain_root, bl); + encode(control_pool, bl); + encode(gc_pool, bl); + encode(log_pool, bl); + encode(intent_log_pool, bl); + encode(usage_log_pool, bl); + encode(user_keys_pool, bl); + encode(user_email_pool, bl); + encode(user_swift_pool, bl); + encode(user_uid_pool, bl); + RGWSystemMetaObj::encode(bl); + encode(system_key, bl); + encode(placement_pools, bl); + encode(metadata_heap, bl); + encode(realm_id, bl); + encode(lc_pool, bl); + map old_tier_config; + encode(old_tier_config, bl); + encode(roles_pool, bl); + encode(reshard_pool, bl); + encode(otp_pool, bl); + encode(tier_config, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) override { + DECODE_START(12, bl); + decode(domain_root, bl); + decode(control_pool, bl); + decode(gc_pool, bl); + decode(log_pool, bl); + decode(intent_log_pool, bl); + decode(usage_log_pool, bl); + decode(user_keys_pool, bl); + decode(user_email_pool, bl); + decode(user_swift_pool, bl); + decode(user_uid_pool, bl); + if (struct_v >= 6) { + RGWSystemMetaObj::decode(bl); + } else if (struct_v >= 2) { + decode(name, bl); + id = name; + } + if (struct_v >= 3) + decode(system_key, bl); + if (struct_v >= 4) + decode(placement_pools, bl); + if (struct_v >= 5) + decode(metadata_heap, bl); + if (struct_v >= 6) { + decode(realm_id, bl); + } + if (struct_v >= 7) { + decode(lc_pool, bl); + } else { + lc_pool = log_pool.name + ":lc"; + } + map old_tier_config; + if (struct_v >= 8) { + decode(old_tier_config, bl); + } + if (struct_v >= 9) { + decode(roles_pool, bl); + } else { + roles_pool = name + ".rgw.meta:roles"; + } + if (struct_v >= 10) { + decode(reshard_pool, bl); + } else { + reshard_pool = log_pool.name + ":reshard"; + } + if (struct_v >= 11) { + ::decode(otp_pool, bl); + } else { + otp_pool = name + ".rgw.otp"; + } + if (struct_v >= 12) { + ::decode(tier_config, bl); + } else { + for (auto& kv : old_tier_config) { + tier_config.set(kv.first, kv.second); + } + } + DECODE_FINISH(bl); + } + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); + static void generate_test_instances(list& o); + + bool get_placement(const string& placement_id, RGWZonePlacementInfo *placement) const { + auto iter = placement_pools.find(placement_id); + if (iter == placement_pools.end()) { + return false; + } + *placement = iter->second; + return true; + } + + /* + * return data pool of the head object + */ + bool get_head_data_pool(const string& placement_id, const rgw_obj& obj, rgw_pool *pool) const { + const rgw_data_placement_target& explicit_placement = obj.bucket.explicit_placement; + if (!explicit_placement.data_pool.empty()) { + if (!obj.in_extra_data) { + *pool = explicit_placement.data_pool; + } else { + *pool = explicit_placement.get_data_extra_pool(); + } + return true; + } + if (placement_id.empty()) { + return false; + } + auto iter = placement_pools.find(placement_id); + if (iter == placement_pools.end()) { + return false; + } + if (!obj.in_extra_data) { + *pool = iter->second.data_pool; + } else { + *pool = iter->second.get_data_extra_pool(); + } + return true; + } +}; +WRITE_CLASS_ENCODER(RGWZoneParams) + +struct RGWZone { + string id; + string name; + list endpoints; + bool log_meta; + bool log_data; + bool read_only; + string tier_type; + + string redirect_zone; + +/** + * Represents the number of shards for the bucket index object, a value of zero + * indicates there is no sharding. By default (no sharding, the name of the object + * is '.dir.{marker}', with sharding, the name is '.dir.{marker}.{sharding_id}', + * sharding_id is zero-based value. It is not recommended to set a too large value + * (e.g. thousand) as it increases the cost for bucket listing. + */ + uint32_t bucket_index_max_shards; + + bool sync_from_all; + set sync_from; /* list of zones to sync from */ + + RGWZone() : log_meta(false), log_data(false), read_only(false), bucket_index_max_shards(0), + sync_from_all(true) {} + + void encode(bufferlist& bl) const { + ENCODE_START(7, 1, bl); + encode(name, bl); + encode(endpoints, bl); + encode(log_meta, bl); + encode(log_data, bl); + encode(bucket_index_max_shards, bl); + encode(id, bl); + encode(read_only, bl); + encode(tier_type, bl); + encode(sync_from_all, bl); + encode(sync_from, bl); + encode(redirect_zone, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + DECODE_START(7, bl); + decode(name, bl); + if (struct_v < 4) { + id = name; + } + decode(endpoints, bl); + if (struct_v >= 2) { + decode(log_meta, bl); + decode(log_data, bl); + } + if (struct_v >= 3) { + decode(bucket_index_max_shards, bl); + } + if (struct_v >= 4) { + decode(id, bl); + decode(read_only, bl); + } + if (struct_v >= 5) { + decode(tier_type, bl); + } + if (struct_v >= 6) { + decode(sync_from_all, bl); + decode(sync_from, bl); + } + if (struct_v >= 7) { + decode(redirect_zone, bl); + } + DECODE_FINISH(bl); + } + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); + static void generate_test_instances(list& o); + + bool is_read_only() { return read_only; } + + bool syncs_from(const string& zone_id) const { + return (sync_from_all || sync_from.find(zone_id) != sync_from.end()); + } +}; +WRITE_CLASS_ENCODER(RGWZone) + +struct RGWDefaultZoneGroupInfo { + string default_zonegroup; + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(default_zonegroup, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + DECODE_START(1, bl); + decode(default_zonegroup, bl); + DECODE_FINISH(bl); + } + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); + //todo: implement ceph-dencoder +}; +WRITE_CLASS_ENCODER(RGWDefaultZoneGroupInfo) + +struct RGWZoneGroupPlacementTarget { + string name; + set tags; + + bool user_permitted(list& user_tags) const { + if (tags.empty()) { + return true; + } + for (auto& rule : user_tags) { + if (tags.find(rule) != tags.end()) { + return true; + } + } + return false; + } + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(name, bl); + encode(tags, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + DECODE_START(1, bl); + decode(name, bl); + decode(tags, bl); + DECODE_FINISH(bl); + } + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); +}; +WRITE_CLASS_ENCODER(RGWZoneGroupPlacementTarget) + + +struct RGWZoneGroup : public RGWSystemMetaObj { + string api_name; + list endpoints; + bool is_master = false; + + string master_zone; + map zones; + + map placement_targets; + string default_placement; + + list hostnames; + list hostnames_s3website; + // TODO: Maybe convert hostnames to a map> for + // endpoint_type->hostnames +/* +20:05 < _robbat21irssi> maybe I do someting like: if (hostname_map.empty()) { populate all map keys from hostnames; }; +20:05 < _robbat21irssi> but that's a later compatability migration planning bit +20:06 < yehudasa> more like if (!hostnames.empty()) { +20:06 < yehudasa> for (list::iterator iter = hostnames.begin(); iter != hostnames.end(); ++iter) { +20:06 < yehudasa> hostname_map["s3"].append(iter->second); +20:07 < yehudasa> hostname_map["s3website"].append(iter->second); +20:07 < yehudasa> s/append/push_back/g +20:08 < _robbat21irssi> inner loop over APIs +20:08 < yehudasa> yeah, probably +20:08 < _robbat21irssi> s3, s3website, swift, swith_auth, swift_website +*/ + map > api_hostname_map; + map > api_endpoints_map; + + string realm_id; + + RGWZoneGroup(): is_master(false){} + RGWZoneGroup(const std::string &id, const std::string &name):RGWSystemMetaObj(id, name) {} + explicit RGWZoneGroup(const std::string &_name):RGWSystemMetaObj(_name) {} + RGWZoneGroup(const std::string &_name, bool _is_master, CephContext *cct, RGWRados* store, + const string& _realm_id, const list& _endpoints) + : RGWSystemMetaObj(_name, cct , store), endpoints(_endpoints), is_master(_is_master), + realm_id(_realm_id) {} + + bool is_master_zonegroup() const { return is_master;} + void update_master(bool _is_master) { + is_master = _is_master; + post_process_params(); + } + void post_process_params(); + + void encode(bufferlist& bl) const override { + ENCODE_START(4, 1, bl); + encode(name, bl); + encode(api_name, bl); + encode(is_master, bl); + encode(endpoints, bl); + encode(master_zone, bl); + encode(zones, bl); + encode(placement_targets, bl); + encode(default_placement, bl); + encode(hostnames, bl); + encode(hostnames_s3website, bl); + RGWSystemMetaObj::encode(bl); + encode(realm_id, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) override { + DECODE_START(4, bl); + decode(name, bl); + decode(api_name, bl); + decode(is_master, bl); + decode(endpoints, bl); + decode(master_zone, bl); + decode(zones, bl); + decode(placement_targets, bl); + decode(default_placement, bl); + if (struct_v >= 2) { + decode(hostnames, bl); + } + if (struct_v >= 3) { + decode(hostnames_s3website, bl); + } + if (struct_v >= 4) { + RGWSystemMetaObj::decode(bl); + decode(realm_id, bl); + } else { + id = name; + } + DECODE_FINISH(bl); + } + + int read_default_id(string& default_id, bool old_format = false) override; + int set_as_default(bool exclusive = false) override; + int create_default(bool old_format = false); + int equals(const string& other_zonegroup) const; + int add_zone(const RGWZoneParams& zone_params, bool *is_master, bool *read_only, + const list& endpoints, const string *ptier_type, + bool *psync_from_all, list& sync_from, list& sync_from_rm, + string *predirect_zone); + int remove_zone(const std::string& zone_id); + int rename_zone(const RGWZoneParams& zone_params); + rgw_pool get_pool(CephContext *cct) override; + const string get_default_oid(bool old_region_format = false) override; + const string& get_info_oid_prefix(bool old_region_format = false) override; + const string& get_names_oid_prefix() override; + const string& get_predefined_name(CephContext *cct) override; + + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); + static void generate_test_instances(list& o); +}; +WRITE_CLASS_ENCODER(RGWZoneGroup) + +struct RGWPeriodMap +{ + string id; + map zonegroups; + map zonegroups_by_api; + map short_zone_ids; + + string master_zonegroup; + + void encode(bufferlist& bl) const; + void decode(bufferlist::const_iterator& bl); + + int update(const RGWZoneGroup& zonegroup, CephContext *cct); + + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); + + void reset() { + zonegroups.clear(); + zonegroups_by_api.clear(); + master_zonegroup.clear(); + } + + uint32_t get_zone_short_id(const string& zone_id) const; +}; +WRITE_CLASS_ENCODER(RGWPeriodMap) + +struct RGWPeriodConfig +{ + RGWQuotaInfo bucket_quota; + RGWQuotaInfo user_quota; + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(bucket_quota, bl); + encode(user_quota, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + DECODE_START(1, bl); + decode(bucket_quota, bl); + decode(user_quota, bl); + DECODE_FINISH(bl); + } + + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); + + // the period config must be stored in a local object outside of the period, + // so that it can be used in a default configuration where no realm/period + // exists + int read(RGWRados *store, const std::string& realm_id); + int write(RGWRados *store, const std::string& realm_id); + + static std::string get_oid(const std::string& realm_id); + static rgw_pool get_pool(CephContext *cct); +}; +WRITE_CLASS_ENCODER(RGWPeriodConfig) + +/* for backward comaptability */ +struct RGWRegionMap { + + map regions; + + string master_region; + + RGWQuotaInfo bucket_quota; + RGWQuotaInfo user_quota; + + void encode(bufferlist& bl) const; + void decode(bufferlist::const_iterator& bl); + + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); +}; +WRITE_CLASS_ENCODER(RGWRegionMap) + +struct RGWZoneGroupMap { + + map zonegroups; + map zonegroups_by_api; + + string master_zonegroup; + + RGWQuotaInfo bucket_quota; + RGWQuotaInfo user_quota; + + /* construct the map */ + int read(CephContext *cct, RGWRados *store); + + void encode(bufferlist& bl) const; + void decode(bufferlist::const_iterator& bl); + + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); +}; +WRITE_CLASS_ENCODER(RGWZoneGroupMap) + +class RGWRealm; + +struct objexp_hint_entry { + string tenant; + string bucket_name; + string bucket_id; + rgw_obj_key obj_key; + ceph::real_time exp_time; + + void encode(bufferlist& bl) const { + ENCODE_START(2, 1, bl); + encode(bucket_name, bl); + encode(bucket_id, bl); + encode(obj_key, bl); + encode(exp_time, bl); + encode(tenant, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + // XXX Do we want DECODE_START_LEGACY_COMPAT_LEN(2, 1, 1, bl); ? + DECODE_START(2, bl); + decode(bucket_name, bl); + decode(bucket_id, bl); + decode(obj_key, bl); + decode(exp_time, bl); + if (struct_v >= 2) { + decode(tenant, bl); + } else { + tenant.clear(); + } + DECODE_FINISH(bl); + } +}; +WRITE_CLASS_ENCODER(objexp_hint_entry) + +class RGWPeriod; + +class RGWRealm : public RGWSystemMetaObj +{ + string current_period; + epoch_t epoch{0}; //< realm epoch, incremented for each new period + + int create_control(bool exclusive); + int delete_control(); +public: + RGWRealm() {} + RGWRealm(const string& _id, const string& _name = "") : RGWSystemMetaObj(_id, _name) {} + RGWRealm(CephContext *_cct, RGWRados *_store): RGWSystemMetaObj(_cct, _store) {} + RGWRealm(const string& _name, CephContext *_cct, RGWRados *_store): RGWSystemMetaObj(_name, _cct, _store){} + + void encode(bufferlist& bl) const override { + ENCODE_START(1, 1, bl); + RGWSystemMetaObj::encode(bl); + encode(current_period, bl); + encode(epoch, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) override { + DECODE_START(1, bl); + RGWSystemMetaObj::decode(bl); + decode(current_period, bl); + decode(epoch, bl); + DECODE_FINISH(bl); + } + + int create(bool exclusive = true) override; + int delete_obj(); + rgw_pool get_pool(CephContext *cct) override; + const string get_default_oid(bool old_format = false) override; + const string& get_names_oid_prefix() override; + const string& get_info_oid_prefix(bool old_format = false) override; + const string& get_predefined_name(CephContext *cct) override; + + using RGWSystemMetaObj::read_id; // expose as public for radosgw-admin + + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); + + const string& get_current_period() const { + return current_period; + } + int set_current_period(RGWPeriod& period); + void clear_current_period_and_epoch() { + current_period.clear(); + epoch = 0; + } + epoch_t get_epoch() const { return epoch; } + + string get_control_oid(); + /// send a notify on the realm control object + int notify_zone(bufferlist& bl); + /// notify the zone of a new period + int notify_new_period(const RGWPeriod& period); +}; +WRITE_CLASS_ENCODER(RGWRealm) + +struct RGWPeriodLatestEpochInfo { + epoch_t epoch; + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(epoch, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + DECODE_START(1, bl); + decode(epoch, bl); + DECODE_FINISH(bl); + } + + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); +}; +WRITE_CLASS_ENCODER(RGWPeriodLatestEpochInfo) + +class RGWPeriod +{ + string id; + epoch_t epoch; + string predecessor_uuid; + std::vector sync_status; + RGWPeriodMap period_map; + RGWPeriodConfig period_config; + string master_zonegroup; + string master_zone; + + string realm_id; + string realm_name; + epoch_t realm_epoch{1}; //< realm epoch when period was made current + + CephContext *cct; + RGWRados *store; + + int read_info(); + int read_latest_epoch(RGWPeriodLatestEpochInfo& epoch_info, + RGWObjVersionTracker *objv = nullptr); + int use_latest_epoch(); + int use_current_period(); + + const string get_period_oid(); + const string get_period_oid_prefix(); + + // gather the metadata sync status for each shard; only for use on master zone + int update_sync_status(const RGWPeriod ¤t_period, + std::ostream& error_stream, bool force_if_stale); + +public: + RGWPeriod() : epoch(0), cct(NULL), store(NULL) {} + + RGWPeriod(const string& period_id, epoch_t _epoch = 0) + : id(period_id), epoch(_epoch), + cct(NULL), store(NULL) {} + + const string& get_id() const { return id; } + epoch_t get_epoch() const { return epoch; } + epoch_t get_realm_epoch() const { return realm_epoch; } + const string& get_predecessor() const { return predecessor_uuid; } + const string& get_master_zone() const { return master_zone; } + const string& get_master_zonegroup() const { return master_zonegroup; } + const string& get_realm() const { return realm_id; } + const RGWPeriodMap& get_map() const { return period_map; } + RGWPeriodConfig& get_config() { return period_config; } + const RGWPeriodConfig& get_config() const { return period_config; } + const std::vector& get_sync_status() const { return sync_status; } + rgw_pool get_pool(CephContext *cct); + const string& get_latest_epoch_oid(); + const string& get_info_oid_prefix(); + + void set_user_quota(RGWQuotaInfo& user_quota) { + period_config.user_quota = user_quota; + } + + void set_bucket_quota(RGWQuotaInfo& bucket_quota) { + period_config.bucket_quota = bucket_quota; + } + + void set_id(const string& id) { + this->id = id; + period_map.id = id; + } + void set_epoch(epoch_t epoch) { this->epoch = epoch; } + void set_realm_epoch(epoch_t epoch) { realm_epoch = epoch; } + + void set_predecessor(const string& predecessor) + { + predecessor_uuid = predecessor; + } + + void set_realm_id(const string& _realm_id) { + realm_id = _realm_id; + } + + int reflect(); + + int get_zonegroup(RGWZoneGroup& zonegroup, + const string& zonegroup_id); + + bool is_single_zonegroup() const + { + return (period_map.zonegroups.size() == 1); + } + + /* + returns true if there are several zone groups with a least one zone + */ + bool is_multi_zonegroups_with_zones() + { + int count = 0; + for (const auto& zg: period_map.zonegroups) { + if (zg.second.zones.size() > 0) { + if (count++ > 0) { + return true; + } + } + } + return false; + } + + int get_latest_epoch(epoch_t& epoch); + int set_latest_epoch(epoch_t epoch, bool exclusive = false, + RGWObjVersionTracker *objv = nullptr); + // update latest_epoch if the given epoch is higher, else return -EEXIST + int update_latest_epoch(epoch_t epoch); + + int init(CephContext *_cct, RGWRados *_store, const string &period_realm_id, const string &period_realm_name = "", + bool setup_obj = true); + int init(CephContext *_cct, RGWRados *_store, bool setup_obj = true); + + int create(bool exclusive = true); + int delete_obj(); + int store_info(bool exclusive); + int add_zonegroup(const RGWZoneGroup& zonegroup); + + void fork(); + int update(); + + // commit a staging period; only for use on master zone + int commit(RGWRealm& realm, const RGWPeriod ¤t_period, + std::ostream& error_stream, bool force_if_stale = false); + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(id, bl); + encode(epoch, bl); + encode(realm_epoch, bl); + encode(predecessor_uuid, bl); + encode(sync_status, bl); + encode(period_map, bl); + encode(master_zone, bl); + encode(master_zonegroup, bl); + encode(period_config, bl); + encode(realm_id, bl); + encode(realm_name, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + DECODE_START(1, bl); + decode(id, bl); + decode(epoch, bl); + decode(realm_epoch, bl); + decode(predecessor_uuid, bl); + decode(sync_status, bl); + decode(period_map, bl); + decode(master_zone, bl); + decode(master_zonegroup, bl); + decode(period_config, bl); + decode(realm_id, bl); + decode(realm_name, bl); + DECODE_FINISH(bl); + } + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); + + static string get_staging_id(const string& realm_id) { + return realm_id + ":staging"; + } +}; +WRITE_CLASS_ENCODER(RGWPeriod) + +#endif diff --git a/src/rgw/services/svc_rados.h b/src/rgw/services/svc_rados.h index a53efdda0786..15e68cf3613b 100644 --- a/src/rgw/services/svc_rados.h +++ b/src/rgw/services/svc_rados.h @@ -7,10 +7,10 @@ class RGWS_RADOS : public RGWService { + std::vector get_deps(); public: RGWS_RADOS(CephContext *cct) : RGWService(cct, "rados") {} - std::vector deps(); int create_instance(JSONFormattable& conf, RGWServiceInstanceRef *instance); }; diff --git a/src/rgw/services/svc_zone.cc b/src/rgw/services/svc_zone.cc new file mode 100644 index 000000000000..73e099e2340f --- /dev/null +++ b/src/rgw/services/svc_zone.cc @@ -0,0 +1,52 @@ +#include "svc_zone.h" +#include "rgw_zone.h" + +RGWZoneParams& RGWSI_Zone::get_zone_params() +{ + return *zone_params; +} + +RGWZone& RGWSI_Zone::get_zone() +{ + return *zone_public_config; +} + +RGWZoneGroup& RGWSI_Zone::get_zonegroup() +{ + return *zonegroup; +} + +int RGWSI_Zone::get_zonegroup(const string& id, RGWZoneGroup& zonegroup) +{ + int ret = 0; + if (id == get_zonegroup().get_id()) { + zonegroup = get_zonegroup(); + } else if (!current_period->get_id().empty()) { + ret = current_period->get_zonegroup(zonegroup, id); + } + return ret; +} + +RGWRealm& RGWSI_Zone::get_realm() +{ + return realm; +} + +bool RGWSI_Zone::zone_is_writeable() +{ + return writeable_zone && !get_zone().is_read_only(); +} + +uint32_t RGWSI_Zone::get_zone_short_id() const +{ + return zone_short_id; +} + +const string& RGWSI_Zone::zone_name() +{ + return get_zone_params().get_name(); +} +const string& RGWSI_Zone::zone_id() +{ + return get_zone_params().get_id(); +} diff --git a/src/rgw/services/svc_zone.h b/src/rgw/services/svc_zone.h new file mode 100644 index 000000000000..f3c041067950 --- /dev/null +++ b/src/rgw/services/svc_zone.h @@ -0,0 +1,54 @@ +#ifndef CEPH_RGW_SERVICES_ZONE_H +#define CEPH_RGW_SERVICES_ZONE_H + + +#include "rgw/rgw_service.h" + + +struct RGWZoneGroup; +struct RGWZone; +struct RGWZoneParams; +struct RGWPeriod; + +class RGWS_Zone : public RGWService +{ +public: + RGWS_Zone(CephContext *cct) : RGWService(cct, "zone") {} + + int create_instance(JSONFormattable& conf, RGWServiceInstanceRef *instance); +}; + +class RGWSI_Zone : public RGWServiceInstance +{ + std::unique_ptr zonegroup; + std::unique_ptr zone_public_config; /* external zone params, e.g., entrypoints, log flags, etc. */ + std::unique_ptr zone_params; /* internal zone params, e.g., rados pools */ + std::unique_ptr current_period; + uint32_t zone_short_id{0}; + + std::vector svci_deps = { "sys_obj" }; + std::vector get_deps() { + return svci_deps; + } + + RGWServiceInstanceRef svc_rados; +public: + RGWSI_Zone(RGWService *svc, CephContext *cct): RGWServiceInstance(svc, cct) {} + + RGWZoneParams& get_zone_params(); + RGWRealm& get_realm(); + RGWZoneGroup& get_zonegroup(); + RGWZone& get_zone(); + + const string& zone_name(); + const string& zone_id(); + uint32_t get_zone_short_id() const; + + int get_zonegroup(const string& id, RGWZoneGroup& zonegroup); + + bool zone_is_writeable(); + bool zone_syncs_from(RGWZone& target_zone, RGWZone& source_zone); + bool get_redirect_zone_endpoint(string *endpoint); +}; + +#endif