summaryrefslogtreecommitdiffstats
path: root/src/rgw/driver/rados/config
diff options
context:
space:
mode:
Diffstat (limited to 'src/rgw/driver/rados/config')
-rw-r--r--src/rgw/driver/rados/config/impl.cc129
-rw-r--r--src/rgw/driver/rados/config/impl.h139
-rw-r--r--src/rgw/driver/rados/config/period.cc230
-rw-r--r--src/rgw/driver/rados/config/period_config.cc55
-rw-r--r--src/rgw/driver/rados/config/realm.cc364
-rw-r--r--src/rgw/driver/rados/config/store.cc52
-rw-r--r--src/rgw/driver/rados/config/store.h182
-rw-r--r--src/rgw/driver/rados/config/zone.cc312
-rw-r--r--src/rgw/driver/rados/config/zonegroup.cc315
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