diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/rgw/driver/rados/config | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/rgw/driver/rados/config')
-rw-r--r-- | src/rgw/driver/rados/config/impl.cc | 129 | ||||
-rw-r--r-- | src/rgw/driver/rados/config/impl.h | 139 | ||||
-rw-r--r-- | src/rgw/driver/rados/config/period.cc | 230 | ||||
-rw-r--r-- | src/rgw/driver/rados/config/period_config.cc | 55 | ||||
-rw-r--r-- | src/rgw/driver/rados/config/realm.cc | 364 | ||||
-rw-r--r-- | src/rgw/driver/rados/config/store.cc | 52 | ||||
-rw-r--r-- | src/rgw/driver/rados/config/store.h | 182 | ||||
-rw-r--r-- | src/rgw/driver/rados/config/zone.cc | 312 | ||||
-rw-r--r-- | src/rgw/driver/rados/config/zonegroup.cc | 315 |
9 files changed, 1778 insertions, 0 deletions
diff --git a/src/rgw/driver/rados/config/impl.cc b/src/rgw/driver/rados/config/impl.cc new file mode 100644 index 000000000..f1b2befad --- /dev/null +++ b/src/rgw/driver/rados/config/impl.cc @@ -0,0 +1,129 @@ +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "impl.h" + +#include "common/async/yield_context.h" +#include "common/errno.h" +#include "rgw_string.h" +#include "rgw_zone.h" + +namespace rgw::rados { + +// default pool names +constexpr std::string_view default_zone_root_pool = "rgw.root"; +constexpr std::string_view default_zonegroup_root_pool = "rgw.root"; +constexpr std::string_view default_realm_root_pool = "rgw.root"; +constexpr std::string_view default_period_root_pool = "rgw.root"; + +static rgw_pool default_pool(std::string_view name, + std::string_view default_name) +{ + return std::string{name_or_default(name, default_name)}; +} + +ConfigImpl::ConfigImpl(const ceph::common::ConfigProxy& conf) + : realm_pool(default_pool(conf->rgw_realm_root_pool, + default_realm_root_pool)), + period_pool(default_pool(conf->rgw_period_root_pool, + default_period_root_pool)), + zonegroup_pool(default_pool(conf->rgw_zonegroup_root_pool, + default_zonegroup_root_pool)), + zone_pool(default_pool(conf->rgw_zone_root_pool, + default_zone_root_pool)) +{ +} + +int ConfigImpl::read(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, + bufferlist& bl, RGWObjVersionTracker* objv) +{ + librados::IoCtx ioctx; + int r = rgw_init_ioctx(dpp, &rados, pool, ioctx, true, false); + if (r < 0) { + return r; + } + librados::ObjectReadOperation op; + if (objv) { + objv->prepare_op_for_read(&op); + } + op.read(0, 0, &bl, nullptr); + return rgw_rados_operate(dpp, ioctx, oid, &op, nullptr, y); +} + +int ConfigImpl::write(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, + Create create, const bufferlist& bl, + RGWObjVersionTracker* objv) +{ + librados::IoCtx ioctx; + int r = rgw_init_ioctx(dpp, &rados, pool, ioctx, true, false); + if (r < 0) { + return r; + } + + librados::ObjectWriteOperation op; + switch (create) { + case Create::MustNotExist: op.create(true); break; + case Create::MayExist: op.create(false); break; + case Create::MustExist: op.assert_exists(); break; + } + if (objv) { + objv->prepare_op_for_write(&op); + } + op.write_full(bl); + + r = rgw_rados_operate(dpp, ioctx, oid, &op, y); + if (r >= 0 && objv) { + objv->apply_write(); + } + return r; +} + +int ConfigImpl::remove(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, + RGWObjVersionTracker* objv) +{ + librados::IoCtx ioctx; + int r = rgw_init_ioctx(dpp, &rados, pool, ioctx, true, false); + if (r < 0) { + return r; + } + + librados::ObjectWriteOperation op; + if (objv) { + objv->prepare_op_for_write(&op); + } + op.remove(); + + r = rgw_rados_operate(dpp, ioctx, oid, &op, y); + if (r >= 0 && objv) { + objv->apply_write(); + } + return r; +} + +int ConfigImpl::notify(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, + bufferlist& bl, uint64_t timeout_ms) +{ + librados::IoCtx ioctx; + int r = rgw_init_ioctx(dpp, &rados, pool, ioctx, true, false); + if (r < 0) { + return r; + } + return rgw_rados_notify(dpp, ioctx, oid, bl, timeout_ms, nullptr, y); +} + +} // namespace rgw::rados diff --git a/src/rgw/driver/rados/config/impl.h b/src/rgw/driver/rados/config/impl.h new file mode 100644 index 000000000..3aed451f9 --- /dev/null +++ b/src/rgw/driver/rados/config/impl.h @@ -0,0 +1,139 @@ +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#pragma once + +#include "include/rados/librados.hpp" +#include "common/dout.h" +#include "rgw_basic_types.h" +#include "rgw_tools.h" +#include "rgw_sal_config.h" + +namespace rgw::rados { + +// write options that control object creation +enum class Create { + MustNotExist, // fail with EEXIST if the object already exists + MayExist, // create if the object didn't exist, overwrite if it did + MustExist, // fail with ENOENT if the object doesn't exist +}; + +struct ConfigImpl { + librados::Rados rados; + + const rgw_pool realm_pool; + const rgw_pool period_pool; + const rgw_pool zonegroup_pool; + const rgw_pool zone_pool; + + ConfigImpl(const ceph::common::ConfigProxy& conf); + + int read(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, + bufferlist& bl, RGWObjVersionTracker* objv); + + template <typename T> + int read(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, + T& data, RGWObjVersionTracker* objv) + { + bufferlist bl; + int r = read(dpp, y, pool, oid, bl, objv); + if (r < 0) { + return r; + } + try { + auto p = bl.cbegin(); + decode(data, p); + } catch (const buffer::error& err) { + ldpp_dout(dpp, 0) << "ERROR: failed to decode obj from " + << pool << ":" << oid << dendl; + return -EIO; + } + return 0; + } + + int write(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, Create create, + const bufferlist& bl, RGWObjVersionTracker* objv); + + template <typename T> + int write(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, Create create, + const T& data, RGWObjVersionTracker* objv) + { + bufferlist bl; + encode(data, bl); + + return write(dpp, y, pool, oid, create, bl, objv); + } + + int remove(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, + RGWObjVersionTracker* objv); + + int list(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& marker, + std::regular_invocable<std::string> auto filter, + std::span<std::string> entries, + sal::ListResult<std::string>& result) + { + librados::IoCtx ioctx; + int r = rgw_init_ioctx(dpp, &rados, pool, ioctx, true, false); + if (r < 0) { + return r; + } + librados::ObjectCursor oc; + if (!oc.from_str(marker)) { + ldpp_dout(dpp, 10) << "failed to parse cursor: " << marker << dendl; + return -EINVAL; + } + std::size_t count = 0; + try { + auto iter = ioctx.nobjects_begin(oc); + const auto end = ioctx.nobjects_end(); + for (; count < entries.size() && iter != end; ++iter) { + std::string entry = filter(iter->get_oid()); + if (!entry.empty()) { + entries[count++] = std::move(entry); + } + } + if (iter == end) { + result.next.clear(); + } else { + result.next = iter.get_cursor().to_str(); + } + } catch (const std::exception& e) { + ldpp_dout(dpp, 10) << "NObjectIterator exception " << e.what() << dendl; + return -EIO; + } + result.entries = entries.first(count); + return 0; + } + + int notify(const DoutPrefixProvider* dpp, optional_yield y, + const rgw_pool& pool, const std::string& oid, + bufferlist& bl, uint64_t timeout_ms); +}; + +inline std::string_view name_or_default(std::string_view name, + std::string_view default_name) +{ + if (!name.empty()) { + return name; + } + return default_name; +} + +} // namespace rgw::rados diff --git a/src/rgw/driver/rados/config/period.cc b/src/rgw/driver/rados/config/period.cc new file mode 100644 index 000000000..bc3fa27e7 --- /dev/null +++ b/src/rgw/driver/rados/config/period.cc @@ -0,0 +1,230 @@ +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/dout.h" +#include "common/errno.h" +#include "rgw_zone.h" +#include "driver/rados/config/store.h" + +#include "impl.h" + +namespace rgw::rados { + +// period oids +constexpr std::string_view period_info_oid_prefix = "periods."; +constexpr std::string_view period_latest_epoch_info_oid = ".latest_epoch"; +constexpr std::string_view period_staging_suffix = ":staging"; + +static std::string period_oid(std::string_view period_id, uint32_t epoch) +{ + // omit the epoch for the staging period + if (period_id.ends_with(period_staging_suffix)) { + return string_cat_reserve(period_info_oid_prefix, period_id); + } + return fmt::format("{}{}.{}", period_info_oid_prefix, period_id, epoch); +} + +static std::string latest_epoch_oid(const ceph::common::ConfigProxy& conf, + std::string_view period_id) +{ + return string_cat_reserve( + period_info_oid_prefix, period_id, + name_or_default(conf->rgw_period_latest_epoch_info_oid, + period_latest_epoch_info_oid)); +} + +static int read_latest_epoch(const DoutPrefixProvider* dpp, optional_yield y, + ConfigImpl* impl, std::string_view period_id, + uint32_t& epoch, RGWObjVersionTracker* objv) +{ + const auto& pool = impl->period_pool; + const auto latest_oid = latest_epoch_oid(dpp->get_cct()->_conf, period_id); + RGWPeriodLatestEpochInfo latest; + int r = impl->read(dpp, y, pool, latest_oid, latest, objv); + if (r >= 0) { + epoch = latest.epoch; + } + return r; +} + +static int write_latest_epoch(const DoutPrefixProvider* dpp, optional_yield y, + ConfigImpl* impl, bool exclusive, + std::string_view period_id, uint32_t epoch, + RGWObjVersionTracker* objv) +{ + const auto& pool = impl->period_pool; + const auto latest_oid = latest_epoch_oid(dpp->get_cct()->_conf, period_id); + const auto create = exclusive ? Create::MustNotExist : Create::MayExist; + RGWPeriodLatestEpochInfo latest{epoch}; + return impl->write(dpp, y, pool, latest_oid, create, latest, objv); +} + +static int delete_latest_epoch(const DoutPrefixProvider* dpp, optional_yield y, + ConfigImpl* impl, std::string_view period_id, + RGWObjVersionTracker* objv) +{ + const auto& pool = impl->period_pool; + const auto latest_oid = latest_epoch_oid(dpp->get_cct()->_conf, period_id); + return impl->remove(dpp, y, pool, latest_oid, objv); +} + +static int update_latest_epoch(const DoutPrefixProvider* dpp, optional_yield y, + ConfigImpl* impl, std::string_view period_id, + uint32_t epoch) +{ + static constexpr int MAX_RETRIES = 20; + + for (int i = 0; i < MAX_RETRIES; i++) { + uint32_t existing_epoch = 0; + RGWObjVersionTracker objv; + bool exclusive = false; + + // read existing epoch + int r = read_latest_epoch(dpp, y, impl, period_id, existing_epoch, &objv); + if (r == -ENOENT) { + // use an exclusive create to set the epoch atomically + exclusive = true; + objv.generate_new_write_ver(dpp->get_cct()); + ldpp_dout(dpp, 20) << "creating initial latest_epoch=" << epoch + << " for period=" << period_id << dendl; + } else if (r < 0) { + ldpp_dout(dpp, 0) << "ERROR: failed to read latest_epoch" << dendl; + return r; + } else if (epoch <= existing_epoch) { + r = -EEXIST; // fail with EEXIST if epoch is not newer + ldpp_dout(dpp, 10) << "found existing latest_epoch " << existing_epoch + << " >= given epoch " << epoch << ", returning r=" << r << dendl; + return r; + } else { + ldpp_dout(dpp, 20) << "updating latest_epoch from " << existing_epoch + << " -> " << epoch << " on period=" << period_id << dendl; + } + + r = write_latest_epoch(dpp, y, impl, exclusive, period_id, epoch, &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) { + ldpp_dout(dpp, 0) << "ERROR: failed to write latest_epoch" << dendl; + return r; + } + return 0; // return success + } + + return -ECANCELED; // fail after max retries +} + +int RadosConfigStore::create_period(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + const RGWPeriod& info) +{ + if (info.get_id().empty()) { + ldpp_dout(dpp, 0) << "period cannot have an empty id" << dendl; + return -EINVAL; + } + if (info.get_epoch() == 0) { + ldpp_dout(dpp, 0) << "period cannot have an empty epoch" << dendl; + return -EINVAL; + } + const auto& pool = impl->period_pool; + const auto info_oid = period_oid(info.get_id(), info.get_epoch()); + const auto create = exclusive ? Create::MustNotExist : Create::MayExist; + RGWObjVersionTracker objv; + objv.generate_new_write_ver(dpp->get_cct()); + int r = impl->write(dpp, y, pool, info_oid, create, info, &objv); + if (r < 0) { + return r; + } + + (void) update_latest_epoch(dpp, y, impl.get(), info.get_id(), info.get_epoch()); + return 0; +} + +int RadosConfigStore::read_period(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view period_id, + std::optional<uint32_t> epoch, + RGWPeriod& info) +{ + int r = 0; + if (!epoch) { + epoch = 0; + r = read_latest_epoch(dpp, y, impl.get(), period_id, *epoch, nullptr); + if (r < 0) { + return r; + } + } + + const auto& pool = impl->period_pool; + const auto info_oid = period_oid(period_id, *epoch); + return impl->read(dpp, y, pool, info_oid, info, nullptr); +} + +int RadosConfigStore::delete_period(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view period_id) +{ + const auto& pool = impl->period_pool; + + // read the latest_epoch + uint32_t latest_epoch = 0; + RGWObjVersionTracker latest_objv; + int r = read_latest_epoch(dpp, y, impl.get(), period_id, + latest_epoch, &latest_objv); + if (r < 0 && r != -ENOENT) { // just delete epoch=0 on ENOENT + ldpp_dout(dpp, 0) << "failed to read latest epoch for period " + << period_id << ": " << cpp_strerror(r) << dendl; + return r; + } + + for (uint32_t epoch = 0; epoch <= latest_epoch; epoch++) { + const auto info_oid = period_oid(period_id, epoch); + r = impl->remove(dpp, y, pool, info_oid, nullptr); + if (r < 0 && r != -ENOENT) { // ignore ENOENT + ldpp_dout(dpp, 0) << "failed to delete period " << info_oid + << ": " << cpp_strerror(r) << dendl; + return r; + } + } + + return delete_latest_epoch(dpp, y, impl.get(), period_id, &latest_objv); +} + +int RadosConfigStore::list_period_ids(const DoutPrefixProvider* dpp, + optional_yield y, + const std::string& marker, + std::span<std::string> entries, + sal::ListResult<std::string>& result) +{ + const auto& pool = impl->period_pool; + constexpr auto prefix = [] (std::string oid) -> std::string { + if (!oid.starts_with(period_info_oid_prefix)) { + return {}; + } + if (!oid.ends_with(period_latest_epoch_info_oid)) { + return {}; + } + // trim the prefix and suffix + const std::size_t count = oid.size() - + period_info_oid_prefix.size() - + period_latest_epoch_info_oid.size(); + return oid.substr(period_info_oid_prefix.size(), count); + }; + + return impl->list(dpp, y, pool, marker, prefix, entries, result); +} + +} // namespace rgw::rados diff --git a/src/rgw/driver/rados/config/period_config.cc b/src/rgw/driver/rados/config/period_config.cc new file mode 100644 index 000000000..ec984ebdc --- /dev/null +++ b/src/rgw/driver/rados/config/period_config.cc @@ -0,0 +1,55 @@ +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "rgw_zone.h" +#include "driver/rados/config/store.h" + +#include "impl.h" + +namespace rgw::rados { + +// period config oids +constexpr std::string_view period_config_prefix = "period_config."; +constexpr std::string_view period_config_realm_default = "default"; + +std::string period_config_oid(std::string_view realm_id) +{ + if (realm_id.empty()) { + realm_id = period_config_realm_default; + } + return string_cat_reserve(period_config_prefix, realm_id); +} + +int RadosConfigStore::read_period_config(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + RGWPeriodConfig& info) +{ + const auto& pool = impl->period_pool; + const auto oid = period_config_oid(realm_id); + return impl->read(dpp, y, pool, oid, info, nullptr); +} + +int RadosConfigStore::write_period_config(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + std::string_view realm_id, + const RGWPeriodConfig& info) +{ + const auto& pool = impl->period_pool; + const auto oid = period_config_oid(realm_id); + const auto create = exclusive ? Create::MustNotExist : Create::MayExist; + return impl->write(dpp, y, pool, oid, create, info, nullptr); +} + +} // namespace rgw::rados diff --git a/src/rgw/driver/rados/config/realm.cc b/src/rgw/driver/rados/config/realm.cc new file mode 100644 index 000000000..331e0ffd2 --- /dev/null +++ b/src/rgw/driver/rados/config/realm.cc @@ -0,0 +1,364 @@ +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/dout.h" +#include "common/errno.h" +#include "rgw_realm_watcher.h" +#include "rgw_zone.h" +#include "driver/rados/config/store.h" + +#include "impl.h" + +namespace rgw::rados { + +// realm oids +constexpr std::string_view realm_names_oid_prefix = "realms_names."; +constexpr std::string_view realm_info_oid_prefix = "realms."; +constexpr std::string_view realm_control_oid_suffix = ".control"; +constexpr std::string_view default_realm_info_oid = "default.realm"; + +static std::string realm_info_oid(std::string_view realm_id) +{ + return string_cat_reserve(realm_info_oid_prefix, realm_id); +} +static std::string realm_name_oid(std::string_view realm_id) +{ + return string_cat_reserve(realm_names_oid_prefix, realm_id); +} +static std::string realm_control_oid(std::string_view realm_id) +{ + return string_cat_reserve(realm_info_oid_prefix, realm_id, + realm_control_oid_suffix); +} +static std::string default_realm_oid(const ceph::common::ConfigProxy& conf) +{ + return std::string{name_or_default(conf->rgw_default_realm_info_oid, + default_realm_info_oid)}; +} + + +int RadosConfigStore::write_default_realm_id(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + std::string_view realm_id) +{ + const auto& pool = impl->realm_pool; + const auto oid = default_realm_oid(dpp->get_cct()->_conf); + const auto create = exclusive ? Create::MustNotExist : Create::MayExist; + + RGWDefaultSystemMetaObjInfo default_info; + default_info.default_id = realm_id; + + return impl->write(dpp, y, pool, oid, create, default_info, nullptr); +} + +int RadosConfigStore::read_default_realm_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string& realm_id) +{ + const auto& pool = impl->realm_pool; + const auto oid = default_realm_oid(dpp->get_cct()->_conf); + + RGWDefaultSystemMetaObjInfo default_info; + int r = impl->read(dpp, y, pool, oid, default_info, nullptr); + if (r >= 0) { + realm_id = default_info.default_id; + } + return r; +} + +int RadosConfigStore::delete_default_realm_id(const DoutPrefixProvider* dpp, + optional_yield y) +{ + const auto& pool = impl->realm_pool; + const auto oid = default_realm_oid(dpp->get_cct()->_conf); + + return impl->remove(dpp, y, pool, oid, nullptr); +} + + +class RadosRealmWriter : public sal::RealmWriter { + ConfigImpl* impl; + RGWObjVersionTracker objv; + std::string realm_id; + std::string realm_name; + public: + RadosRealmWriter(ConfigImpl* impl, RGWObjVersionTracker objv, + std::string_view realm_id, std::string_view realm_name) + : impl(impl), objv(std::move(objv)), + realm_id(realm_id), realm_name(realm_name) + { + } + + int write(const DoutPrefixProvider* dpp, optional_yield y, + const RGWRealm& info) override + { + if (realm_id != info.get_id() || realm_name != info.get_name()) { + return -EINVAL; // can't modify realm id or name directly + } + + const auto& pool = impl->realm_pool; + const auto info_oid = realm_info_oid(info.get_id()); + return impl->write(dpp, y, pool, info_oid, Create::MustExist, info, &objv); + } + + int rename(const DoutPrefixProvider* dpp, optional_yield y, + RGWRealm& info, std::string_view new_name) override + { + if (realm_id != info.get_id() || realm_name != info.get_name()) { + return -EINVAL; // can't modify realm id or name directly + } + if (new_name.empty()) { + ldpp_dout(dpp, 0) << "realm cannot have an empty name" << dendl; + return -EINVAL; + } + + const auto& pool = impl->realm_pool; + const auto name = RGWNameToId{info.get_id()}; + const auto info_oid = realm_info_oid(info.get_id()); + const auto old_oid = realm_name_oid(info.get_name()); + const auto new_oid = realm_name_oid(new_name); + + // link the new name + RGWObjVersionTracker new_objv; + new_objv.generate_new_write_ver(dpp->get_cct()); + int r = impl->write(dpp, y, pool, new_oid, Create::MustNotExist, + name, &new_objv); + if (r < 0) { + return r; + } + + // write the info with updated name + info.set_name(std::string{new_name}); + r = impl->write(dpp, y, pool, info_oid, Create::MustExist, info, &objv); + if (r < 0) { + // on failure, unlink the new name + (void) impl->remove(dpp, y, pool, new_oid, &new_objv); + return r; + } + + // unlink the old name + (void) impl->remove(dpp, y, pool, old_oid, nullptr); + + realm_name = new_name; + return 0; + } + + int remove(const DoutPrefixProvider* dpp, optional_yield y) override + { + const auto& pool = impl->realm_pool; + const auto info_oid = realm_info_oid(realm_id); + int r = impl->remove(dpp, y, pool, info_oid, &objv); + if (r < 0) { + return r; + } + const auto name_oid = realm_name_oid(realm_name); + (void) impl->remove(dpp, y, pool, name_oid, nullptr); + const auto control_oid = realm_control_oid(realm_id); + (void) impl->remove(dpp, y, pool, control_oid, nullptr); + return 0; + } +}; // RadosRealmWriter + + +int RadosConfigStore::create_realm(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + const RGWRealm& info, + std::unique_ptr<sal::RealmWriter>* writer) +{ + if (info.get_id().empty()) { + ldpp_dout(dpp, 0) << "realm cannot have an empty id" << dendl; + return -EINVAL; + } + if (info.get_name().empty()) { + ldpp_dout(dpp, 0) << "realm cannot have an empty name" << dendl; + return -EINVAL; + } + + const auto& pool = impl->realm_pool; + const auto create = exclusive ? Create::MustNotExist : Create::MayExist; + + // write the realm info + const auto info_oid = realm_info_oid(info.get_id()); + RGWObjVersionTracker objv; + objv.generate_new_write_ver(dpp->get_cct()); + + int r = impl->write(dpp, y, pool, info_oid, create, info, &objv); + if (r < 0) { + return r; + } + + // write the realm name + const auto name_oid = realm_name_oid(info.get_name()); + const auto name = RGWNameToId{info.get_id()}; + RGWObjVersionTracker name_objv; + name_objv.generate_new_write_ver(dpp->get_cct()); + + r = impl->write(dpp, y, pool, name_oid, create, name, &name_objv); + if (r < 0) { + (void) impl->remove(dpp, y, pool, info_oid, &objv); + return r; + } + + // create control object for watch/notify + const auto control_oid = realm_control_oid(info.get_id()); + bufferlist empty_bl; + r = impl->write(dpp, y, pool, control_oid, Create::MayExist, + empty_bl, nullptr); + if (r < 0) { + (void) impl->remove(dpp, y, pool, name_oid, &name_objv); + (void) impl->remove(dpp, y, pool, info_oid, &objv); + return r; + } + + if (writer) { + *writer = std::make_unique<RadosRealmWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_realm_by_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + RGWRealm& info, + std::unique_ptr<sal::RealmWriter>* writer) +{ + const auto& pool = impl->realm_pool; + const auto info_oid = realm_info_oid(realm_id); + RGWObjVersionTracker objv; + int r = impl->read(dpp, y, pool, info_oid, info, &objv); + if (r < 0) { + return r; + } + + if (writer) { + *writer = std::make_unique<RadosRealmWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_realm_by_name(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_name, + RGWRealm& info, + std::unique_ptr<sal::RealmWriter>* writer) +{ + const auto& pool = impl->realm_pool; + + // look up realm id by name + RGWNameToId name; + const auto name_oid = realm_name_oid(realm_name); + int r = impl->read(dpp, y, pool, name_oid, name, nullptr); + if (r < 0) { + return r; + } + + const auto info_oid = realm_info_oid(name.obj_id); + RGWObjVersionTracker objv; + r = impl->read(dpp, y, pool, info_oid, info, &objv); + if (r < 0) { + return r; + } + + if (writer) { + *writer = std::make_unique<RadosRealmWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_default_realm(const DoutPrefixProvider* dpp, + optional_yield y, + RGWRealm& info, + std::unique_ptr<sal::RealmWriter>* writer) +{ + const auto& pool = impl->realm_pool; + + // read default realm id + RGWDefaultSystemMetaObjInfo default_info; + const auto default_oid = default_realm_oid(dpp->get_cct()->_conf); + int r = impl->read(dpp, y, pool, default_oid, default_info, nullptr); + if (r < 0) { + return r; + } + + const auto info_oid = realm_info_oid(default_info.default_id); + RGWObjVersionTracker objv; + r = impl->read(dpp, y, pool, info_oid, info, &objv); + if (r < 0) { + return r; + } + + if (writer) { + *writer = std::make_unique<RadosRealmWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_realm_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_name, + std::string& realm_id) +{ + const auto& pool = impl->realm_pool; + RGWNameToId name; + + // look up realm id by name + const auto name_oid = realm_name_oid(realm_name); + int r = impl->read(dpp, y, pool, name_oid, name, nullptr); + if (r < 0) { + return r; + } + realm_id = std::move(name.obj_id); + return 0; +} + +int RadosConfigStore::realm_notify_new_period(const DoutPrefixProvider* dpp, + optional_yield y, + const RGWPeriod& period) +{ + const auto& pool = impl->realm_pool; + const auto control_oid = realm_control_oid(period.get_realm()); + + 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); + + constexpr uint64_t timeout_ms = 0; + return impl->notify(dpp, y, pool, control_oid, bl, timeout_ms); +} + +int RadosConfigStore::list_realm_names(const DoutPrefixProvider* dpp, + optional_yield y, + const std::string& marker, + std::span<std::string> entries, + sal::ListResult<std::string>& result) +{ + const auto& pool = impl->realm_pool; + constexpr auto prefix = [] (std::string oid) -> std::string { + if (!oid.starts_with(realm_names_oid_prefix)) { + return {}; + } + return oid.substr(realm_names_oid_prefix.size()); + }; + return impl->list(dpp, y, pool, marker, prefix, entries, result); +} + +} // namespace rgw::rados diff --git a/src/rgw/driver/rados/config/store.cc b/src/rgw/driver/rados/config/store.cc new file mode 100644 index 000000000..ec2b034a8 --- /dev/null +++ b/src/rgw/driver/rados/config/store.cc @@ -0,0 +1,52 @@ +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "include/rados/librados.hpp" +#include "common/errno.h" +#include "impl.h" +#include "store.h" + +namespace rgw::rados { + +RadosConfigStore::RadosConfigStore(std::unique_ptr<ConfigImpl> impl) + : impl(std::move(impl)) +{ +} + +RadosConfigStore::~RadosConfigStore() = default; + + +auto create_config_store(const DoutPrefixProvider* dpp) + -> std::unique_ptr<RadosConfigStore> +{ + auto impl = std::make_unique<ConfigImpl>(dpp->get_cct()->_conf); + + // initialize a Rados client + int r = impl->rados.init_with_context(dpp->get_cct()); + if (r < 0) { + ldpp_dout(dpp, -1) << "Rados client initialization failed with " + << cpp_strerror(-r) << dendl; + return nullptr; + } + r = impl->rados.connect(); + if (r < 0) { + ldpp_dout(dpp, -1) << "Rados client connection failed with " + << cpp_strerror(-r) << dendl; + return nullptr; + } + + return std::make_unique<RadosConfigStore>(std::move(impl)); +} + +} // namespace rgw::rados diff --git a/src/rgw/driver/rados/config/store.h b/src/rgw/driver/rados/config/store.h new file mode 100644 index 000000000..1b93a803d --- /dev/null +++ b/src/rgw/driver/rados/config/store.h @@ -0,0 +1,182 @@ +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#pragma once + +#include <list> +#include <memory> +#include <string> +#include "rgw_common.h" +#include "rgw_sal_config.h" + +class DoutPrefixProvider; +class optional_yield; + +namespace rgw::rados { + +struct ConfigImpl; + +class RadosConfigStore : public sal::ConfigStore { + public: + explicit RadosConfigStore(std::unique_ptr<ConfigImpl> impl); + virtual ~RadosConfigStore() override; + + // Realm + virtual int write_default_realm_id(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + std::string_view realm_id) override; + virtual int read_default_realm_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string& realm_id) override; + virtual int delete_default_realm_id(const DoutPrefixProvider* dpp, + optional_yield y) override; + + virtual int create_realm(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + const RGWRealm& info, + std::unique_ptr<sal::RealmWriter>* writer) override; + virtual int read_realm_by_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + RGWRealm& info, + std::unique_ptr<sal::RealmWriter>* writer) override; + virtual int read_realm_by_name(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_name, + RGWRealm& info, + std::unique_ptr<sal::RealmWriter>* writer) override; + virtual int read_default_realm(const DoutPrefixProvider* dpp, + optional_yield y, + RGWRealm& info, + std::unique_ptr<sal::RealmWriter>* writer) override; + virtual int read_realm_id(const DoutPrefixProvider* dpp, + optional_yield y, std::string_view realm_name, + std::string& realm_id) override; + virtual int realm_notify_new_period(const DoutPrefixProvider* dpp, + optional_yield y, + const RGWPeriod& period) override; + virtual int list_realm_names(const DoutPrefixProvider* dpp, + optional_yield y, const std::string& marker, + std::span<std::string> entries, + sal::ListResult<std::string>& result) override; + + // Period + virtual int create_period(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + const RGWPeriod& info) override; + virtual int read_period(const DoutPrefixProvider* dpp, + optional_yield y, std::string_view period_id, + std::optional<uint32_t> epoch, RGWPeriod& info) override; + virtual int delete_period(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view period_id) override; + virtual int list_period_ids(const DoutPrefixProvider* dpp, + optional_yield y, const std::string& marker, + std::span<std::string> entries, + sal::ListResult<std::string>& result) override; + + // ZoneGroup + virtual int write_default_zonegroup_id(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + std::string_view realm_id, + std::string_view zonegroup_id) override; + virtual int read_default_zonegroup_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + std::string& zonegroup_id) override; + virtual int delete_default_zonegroup_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id) override; + + virtual int create_zonegroup(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + const RGWZoneGroup& info, + std::unique_ptr<sal::ZoneGroupWriter>* writer) override; + virtual int read_zonegroup_by_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view zonegroup_id, + RGWZoneGroup& info, + std::unique_ptr<sal::ZoneGroupWriter>* writer) override; + virtual int read_zonegroup_by_name(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view zonegroup_name, + RGWZoneGroup& info, + std::unique_ptr<sal::ZoneGroupWriter>* writer) override; + virtual int read_default_zonegroup(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + RGWZoneGroup& info, + std::unique_ptr<sal::ZoneGroupWriter>* writer) override; + virtual int list_zonegroup_names(const DoutPrefixProvider* dpp, + optional_yield y, const std::string& marker, + std::span<std::string> entries, + sal::ListResult<std::string>& result) override; + + // Zone + virtual int write_default_zone_id(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + std::string_view realm_id, + std::string_view zone_id) override; + virtual int read_default_zone_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + std::string& zone_id) override; + virtual int delete_default_zone_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id) override; + + virtual int create_zone(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + const RGWZoneParams& info, + std::unique_ptr<sal::ZoneWriter>* writer) override; + virtual int read_zone_by_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view zone_id, + RGWZoneParams& info, + std::unique_ptr<sal::ZoneWriter>* writer) override; + virtual int read_zone_by_name(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view zone_name, + RGWZoneParams& info, + std::unique_ptr<sal::ZoneWriter>* writer) override; + virtual int read_default_zone(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + RGWZoneParams& info, + std::unique_ptr<sal::ZoneWriter>* writer) override; + virtual int list_zone_names(const DoutPrefixProvider* dpp, + optional_yield y, const std::string& marker, + std::span<std::string> entries, + sal::ListResult<std::string>& result) override; + + // PeriodConfig + virtual int read_period_config(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + RGWPeriodConfig& info) override; + virtual int write_period_config(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + std::string_view realm_id, + const RGWPeriodConfig& info) override; + + private: + std::unique_ptr<ConfigImpl> impl; +}; // RadosConfigStore + + +/// RadosConfigStore factory function +auto create_config_store(const DoutPrefixProvider* dpp) + -> std::unique_ptr<RadosConfigStore>; + +} // namespace rgw::rados diff --git a/src/rgw/driver/rados/config/zone.cc b/src/rgw/driver/rados/config/zone.cc new file mode 100644 index 000000000..e06c1606c --- /dev/null +++ b/src/rgw/driver/rados/config/zone.cc @@ -0,0 +1,312 @@ +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/dout.h" +#include "common/errno.h" +#include "rgw_zone.h" +#include "driver/rados/config/store.h" + +#include "impl.h" + +namespace rgw::rados { + +// zone oids +constexpr std::string_view zone_info_oid_prefix = "zone_info."; +constexpr std::string_view zone_names_oid_prefix = "zone_names."; + +std::string zone_info_oid(std::string_view zone_id) +{ + return string_cat_reserve(zone_info_oid_prefix, zone_id); +} +std::string zone_name_oid(std::string_view zone_id) +{ + return string_cat_reserve(zone_names_oid_prefix, zone_id); +} +std::string default_zone_oid(const ceph::common::ConfigProxy& conf, + std::string_view realm_id) +{ + return fmt::format("{}.{}", conf->rgw_default_zone_info_oid, realm_id); +} + + +int RadosConfigStore::write_default_zone_id(const DoutPrefixProvider* dpp, + optional_yield y, + bool exclusive, + std::string_view realm_id, + std::string_view zone_id) +{ + const auto& pool = impl->zone_pool; + const auto default_oid = default_zone_oid(dpp->get_cct()->_conf, realm_id); + const auto create = exclusive ? Create::MustNotExist : Create::MayExist; + + RGWDefaultSystemMetaObjInfo default_info; + default_info.default_id = zone_id; + + return impl->write(dpp, y, pool, default_oid, create, default_info, nullptr); +} + +int RadosConfigStore::read_default_zone_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + std::string& zone_id) +{ + const auto& pool = impl->zone_pool; + const auto default_oid = default_zone_oid(dpp->get_cct()->_conf, realm_id); + + RGWDefaultSystemMetaObjInfo default_info; + int r = impl->read(dpp, y, pool, default_oid, default_info, nullptr); + if (r >= 0) { + zone_id = default_info.default_id; + } + return r; +} + +int RadosConfigStore::delete_default_zone_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id) +{ + const auto& pool = impl->zone_pool; + const auto default_oid = default_zone_oid(dpp->get_cct()->_conf, realm_id); + + return impl->remove(dpp, y, pool, default_oid, nullptr); +} + + +class RadosZoneWriter : public sal::ZoneWriter { + ConfigImpl* impl; + RGWObjVersionTracker objv; + std::string zone_id; + std::string zone_name; + public: + RadosZoneWriter(ConfigImpl* impl, RGWObjVersionTracker objv, + std::string_view zone_id, std::string_view zone_name) + : impl(impl), objv(std::move(objv)), + zone_id(zone_id), zone_name(zone_name) + { + } + + int write(const DoutPrefixProvider* dpp, optional_yield y, + const RGWZoneParams& info) override + { + if (zone_id != info.get_id() || zone_name != info.get_name()) { + return -EINVAL; // can't modify zone id or name directly + } + + const auto& pool = impl->zone_pool; + const auto info_oid = zone_info_oid(info.get_id()); + return impl->write(dpp, y, pool, info_oid, Create::MustExist, info, &objv); + } + + int rename(const DoutPrefixProvider* dpp, optional_yield y, + RGWZoneParams& info, std::string_view new_name) override + { + if (zone_id != info.get_id() || zone_name != info.get_name()) { + return -EINVAL; // can't modify zone id or name directly + } + if (new_name.empty()) { + ldpp_dout(dpp, 0) << "zone cannot have an empty name" << dendl; + return -EINVAL; + } + + const auto& pool = impl->zone_pool; + const auto name = RGWNameToId{info.get_id()}; + const auto info_oid = zone_info_oid(info.get_id()); + const auto old_oid = zone_name_oid(info.get_name()); + const auto new_oid = zone_name_oid(new_name); + + // link the new name + RGWObjVersionTracker new_objv; + new_objv.generate_new_write_ver(dpp->get_cct()); + int r = impl->write(dpp, y, pool, new_oid, Create::MustNotExist, + name, &new_objv); + if (r < 0) { + return r; + } + + // write the info with updated name + info.set_name(std::string{new_name}); + r = impl->write(dpp, y, pool, info_oid, Create::MustExist, info, &objv); + if (r < 0) { + // on failure, unlink the new name + (void) impl->remove(dpp, y, pool, new_oid, &new_objv); + return r; + } + + // unlink the old name + (void) impl->remove(dpp, y, pool, old_oid, nullptr); + + zone_name = new_name; + return 0; + } + + int remove(const DoutPrefixProvider* dpp, optional_yield y) override + { + const auto& pool = impl->zone_pool; + const auto info_oid = zone_info_oid(zone_id); + int r = impl->remove(dpp, y, pool, info_oid, &objv); + if (r < 0) { + return r; + } + const auto name_oid = zone_name_oid(zone_name); + (void) impl->remove(dpp, y, pool, name_oid, nullptr); + return 0; + } +}; // RadosZoneWriter + + +int RadosConfigStore::create_zone(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + const RGWZoneParams& info, + std::unique_ptr<sal::ZoneWriter>* writer) +{ + if (info.get_id().empty()) { + ldpp_dout(dpp, 0) << "zone cannot have an empty id" << dendl; + return -EINVAL; + } + if (info.get_name().empty()) { + ldpp_dout(dpp, 0) << "zone cannot have an empty name" << dendl; + return -EINVAL; + } + + const auto& pool = impl->zone_pool; + const auto create = exclusive ? Create::MustNotExist : Create::MayExist; + + // write the zone info + const auto info_oid = zone_info_oid(info.get_id()); + RGWObjVersionTracker objv; + objv.generate_new_write_ver(dpp->get_cct()); + + int r = impl->write(dpp, y, pool, info_oid, create, info, &objv); + if (r < 0) { + return r; + } + + // write the zone name + const auto name_oid = zone_name_oid(info.get_name()); + const auto name = RGWNameToId{info.get_id()}; + RGWObjVersionTracker name_objv; + name_objv.generate_new_write_ver(dpp->get_cct()); + + r = impl->write(dpp, y, pool, name_oid, create, name, &name_objv); + if (r < 0) { + (void) impl->remove(dpp, y, pool, info_oid, &objv); + return r; + } + + if (writer) { + *writer = std::make_unique<RadosZoneWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_zone_by_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view zone_id, + RGWZoneParams& info, + std::unique_ptr<sal::ZoneWriter>* writer) +{ + const auto& pool = impl->zone_pool; + const auto info_oid = zone_info_oid(zone_id); + RGWObjVersionTracker objv; + + int r = impl->read(dpp, y, pool, info_oid, info, &objv); + if (r < 0) { + return r; + } + + if (writer) { + *writer = std::make_unique<RadosZoneWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_zone_by_name(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view zone_name, + RGWZoneParams& info, + std::unique_ptr<sal::ZoneWriter>* writer) +{ + const auto& pool = impl->zone_pool; + + // look up zone id by name + const auto name_oid = zone_name_oid(zone_name); + RGWNameToId name; + int r = impl->read(dpp, y, pool, name_oid, name, nullptr); + if (r < 0) { + return r; + } + + const auto info_oid = zone_info_oid(name.obj_id); + RGWObjVersionTracker objv; + r = impl->read(dpp, y, pool, info_oid, info, &objv); + if (r < 0) { + return r; + } + + if (writer) { + *writer = std::make_unique<RadosZoneWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_default_zone(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + RGWZoneParams& info, + std::unique_ptr<sal::ZoneWriter>* writer) +{ + const auto& pool = impl->zone_pool; + + // read default zone id + const auto default_oid = default_zone_oid(dpp->get_cct()->_conf, realm_id); + RGWDefaultSystemMetaObjInfo default_info; + int r = impl->read(dpp, y, pool, default_oid, default_info, nullptr); + if (r < 0) { + return r; + } + + const auto info_oid = zone_info_oid(default_info.default_id); + RGWObjVersionTracker objv; + r = impl->read(dpp, y, pool, info_oid, info, &objv); + if (r < 0) { + return r; + } + + if (writer) { + *writer = std::make_unique<RadosZoneWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::list_zone_names(const DoutPrefixProvider* dpp, + optional_yield y, + const std::string& marker, + std::span<std::string> entries, + sal::ListResult<std::string>& result) +{ + const auto& pool = impl->zone_pool; + constexpr auto prefix = [] (std::string oid) -> std::string { + if (!oid.starts_with(zone_names_oid_prefix)) { + return {}; + } + return oid.substr(zone_names_oid_prefix.size()); + }; + return impl->list(dpp, y, pool, marker, prefix, entries, result); +} + +} // namespace rgw::rados diff --git a/src/rgw/driver/rados/config/zonegroup.cc b/src/rgw/driver/rados/config/zonegroup.cc new file mode 100644 index 000000000..1766a68ce --- /dev/null +++ b/src/rgw/driver/rados/config/zonegroup.cc @@ -0,0 +1,315 @@ +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/dout.h" +#include "common/errno.h" +#include "rgw_zone.h" +#include "driver/rados/config/store.h" + +#include "impl.h" + +namespace rgw::rados { + +// zonegroup oids +constexpr std::string_view zonegroup_names_oid_prefix = "zonegroups_names."; +constexpr std::string_view zonegroup_info_oid_prefix = "zonegroup_info."; +constexpr std::string_view default_zonegroup_info_oid = "default.zonegroup"; + +static std::string zonegroup_info_oid(std::string_view zonegroup_id) +{ + return string_cat_reserve(zonegroup_info_oid_prefix, zonegroup_id); +} +static std::string zonegroup_name_oid(std::string_view zonegroup_id) +{ + return string_cat_reserve(zonegroup_names_oid_prefix, zonegroup_id); +} +static std::string default_zonegroup_oid(const ceph::common::ConfigProxy& conf, + std::string_view realm_id) +{ + const auto prefix = name_or_default(conf->rgw_default_zonegroup_info_oid, + default_zonegroup_info_oid); + return fmt::format("{}.{}", prefix, realm_id); +} + + +int RadosConfigStore::write_default_zonegroup_id(const DoutPrefixProvider* dpp, + optional_yield y, + bool exclusive, + std::string_view realm_id, + std::string_view zonegroup_id) +{ + const auto& pool = impl->zonegroup_pool; + const auto oid = default_zonegroup_oid(dpp->get_cct()->_conf, realm_id); + const auto create = exclusive ? Create::MustNotExist : Create::MayExist; + + RGWDefaultSystemMetaObjInfo default_info; + default_info.default_id = zonegroup_id; + + return impl->write(dpp, y, pool, oid, create, default_info, nullptr); +} + +int RadosConfigStore::read_default_zonegroup_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + std::string& zonegroup_id) +{ + const auto& pool = impl->zonegroup_pool; + const auto oid = default_zonegroup_oid(dpp->get_cct()->_conf, realm_id); + + RGWDefaultSystemMetaObjInfo default_info; + int r = impl->read(dpp, y, pool, oid, default_info, nullptr); + if (r >= 0) { + zonegroup_id = default_info.default_id; + } + return r; +} + +int RadosConfigStore::delete_default_zonegroup_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id) +{ + const auto& pool = impl->zonegroup_pool; + const auto oid = default_zonegroup_oid(dpp->get_cct()->_conf, realm_id); + return impl->remove(dpp, y, pool, oid, nullptr); +} + + +class RadosZoneGroupWriter : public sal::ZoneGroupWriter { + ConfigImpl* impl; + RGWObjVersionTracker objv; + std::string zonegroup_id; + std::string zonegroup_name; + public: + RadosZoneGroupWriter(ConfigImpl* impl, RGWObjVersionTracker objv, + std::string_view zonegroup_id, + std::string_view zonegroup_name) + : impl(impl), objv(std::move(objv)), + zonegroup_id(zonegroup_id), zonegroup_name(zonegroup_name) + { + } + + int write(const DoutPrefixProvider* dpp, optional_yield y, + const RGWZoneGroup& info) override + { + if (zonegroup_id != info.get_id() || zonegroup_name != info.get_name()) { + return -EINVAL; // can't modify zonegroup id or name directly + } + + const auto& pool = impl->zonegroup_pool; + const auto info_oid = zonegroup_info_oid(info.get_id()); + return impl->write(dpp, y, pool, info_oid, Create::MustExist, info, &objv); + } + + int rename(const DoutPrefixProvider* dpp, optional_yield y, + RGWZoneGroup& info, std::string_view new_name) override + { + if (zonegroup_id != info.get_id() || zonegroup_name != info.get_name()) { + return -EINVAL; // can't modify zonegroup id or name directly + } + if (new_name.empty()) { + ldpp_dout(dpp, 0) << "zonegroup cannot have an empty name" << dendl; + return -EINVAL; + } + + const auto& pool = impl->zonegroup_pool; + const auto name = RGWNameToId{info.get_id()}; + const auto info_oid = zonegroup_info_oid(info.get_id()); + const auto old_oid = zonegroup_name_oid(info.get_name()); + const auto new_oid = zonegroup_name_oid(new_name); + + // link the new name + RGWObjVersionTracker new_objv; + new_objv.generate_new_write_ver(dpp->get_cct()); + int r = impl->write(dpp, y, pool, new_oid, Create::MustNotExist, + name, &new_objv); + if (r < 0) { + return r; + } + + // write the info with updated name + info.set_name(std::string{new_name}); + r = impl->write(dpp, y, pool, info_oid, Create::MustExist, info, &objv); + if (r < 0) { + // on failure, unlink the new name + (void) impl->remove(dpp, y, pool, new_oid, &new_objv); + return r; + } + + // unlink the old name + (void) impl->remove(dpp, y, pool, old_oid, nullptr); + + zonegroup_name = new_name; + return 0; + } + + int remove(const DoutPrefixProvider* dpp, optional_yield y) override + { + const auto& pool = impl->zonegroup_pool; + const auto info_oid = zonegroup_info_oid(zonegroup_id); + int r = impl->remove(dpp, y, pool, info_oid, &objv); + if (r < 0) { + return r; + } + const auto name_oid = zonegroup_name_oid(zonegroup_name); + (void) impl->remove(dpp, y, pool, name_oid, nullptr); + return 0; + } +}; // RadosZoneGroupWriter + + +int RadosConfigStore::create_zonegroup(const DoutPrefixProvider* dpp, + optional_yield y, bool exclusive, + const RGWZoneGroup& info, + std::unique_ptr<sal::ZoneGroupWriter>* writer) +{ + if (info.get_id().empty()) { + ldpp_dout(dpp, 0) << "zonegroup cannot have an empty id" << dendl; + return -EINVAL; + } + if (info.get_name().empty()) { + ldpp_dout(dpp, 0) << "zonegroup cannot have an empty name" << dendl; + return -EINVAL; + } + + const auto& pool = impl->zonegroup_pool; + const auto create = exclusive ? Create::MustNotExist : Create::MayExist; + + // write the zonegroup info + const auto info_oid = zonegroup_info_oid(info.get_id()); + RGWObjVersionTracker objv; + objv.generate_new_write_ver(dpp->get_cct()); + + int r = impl->write(dpp, y, pool, info_oid, create, info, &objv); + if (r < 0) { + return r; + } + + // write the zonegroup name + const auto name_oid = zonegroup_name_oid(info.get_name()); + const auto name = RGWNameToId{info.get_id()}; + RGWObjVersionTracker name_objv; + name_objv.generate_new_write_ver(dpp->get_cct()); + + r = impl->write(dpp, y, pool, name_oid, create, name, &name_objv); + if (r < 0) { + (void) impl->remove(dpp, y, pool, info_oid, &objv); + return r; + } + + if (writer) { + *writer = std::make_unique<RadosZoneGroupWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_zonegroup_by_id(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view zonegroup_id, + RGWZoneGroup& info, + std::unique_ptr<sal::ZoneGroupWriter>* writer) +{ + const auto& pool = impl->zonegroup_pool; + const auto info_oid = zonegroup_info_oid(zonegroup_id); + RGWObjVersionTracker objv; + + int r = impl->read(dpp, y, pool, info_oid, info, &objv); + if (r < 0) { + return r; + } + + if (writer) { + *writer = std::make_unique<RadosZoneGroupWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_zonegroup_by_name(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view zonegroup_name, + RGWZoneGroup& info, + std::unique_ptr<sal::ZoneGroupWriter>* writer) +{ + const auto& pool = impl->zonegroup_pool; + + // look up zonegroup id by name + RGWNameToId name; + const auto name_oid = zonegroup_name_oid(zonegroup_name); + int r = impl->read(dpp, y, pool, name_oid, name, nullptr); + if (r < 0) { + return r; + } + + const auto info_oid = zonegroup_info_oid(name.obj_id); + RGWObjVersionTracker objv; + r = impl->read(dpp, y, pool, info_oid, info, &objv); + if (r < 0) { + return r; + } + + if (writer) { + *writer = std::make_unique<RadosZoneGroupWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::read_default_zonegroup(const DoutPrefixProvider* dpp, + optional_yield y, + std::string_view realm_id, + RGWZoneGroup& info, + std::unique_ptr<sal::ZoneGroupWriter>* writer) +{ + const auto& pool = impl->zonegroup_pool; + + // read default zonegroup id + RGWDefaultSystemMetaObjInfo default_info; + const auto default_oid = default_zonegroup_oid(dpp->get_cct()->_conf, realm_id); + int r = impl->read(dpp, y, pool, default_oid, default_info, nullptr); + if (r < 0) { + return r; + } + + const auto info_oid = zonegroup_info_oid(default_info.default_id); + RGWObjVersionTracker objv; + r = impl->read(dpp, y, pool, info_oid, info, &objv); + if (r < 0) { + return r; + } + + if (writer) { + *writer = std::make_unique<RadosZoneGroupWriter>( + impl.get(), std::move(objv), info.get_id(), info.get_name()); + } + return 0; +} + +int RadosConfigStore::list_zonegroup_names(const DoutPrefixProvider* dpp, + optional_yield y, + const std::string& marker, + std::span<std::string> entries, + sal::ListResult<std::string>& result) +{ + const auto& pool = impl->zonegroup_pool; + constexpr auto prefix = [] (std::string oid) -> std::string { + if (!oid.starts_with(zonegroup_names_oid_prefix)) { + return {}; + } + return oid.substr(zonegroup_names_oid_prefix.size()); + }; + return impl->list(dpp, y, pool, marker, prefix, entries, result); +} + +} // namespace rgw::rados |