]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: add rgw::sal::ImmutableConfigStore for json-based config
authorCasey Bodley <cbodley@redhat.com>
Tue, 13 Sep 2022 15:47:46 +0000 (11:47 -0400)
committerCasey Bodley <cbodley@redhat.com>
Wed, 28 Sep 2022 21:48:00 +0000 (17:48 -0400)
Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/rgw/CMakeLists.txt
src/rgw/store/immutable_config/store.cc [new file with mode: 0644]
src/rgw/store/immutable_config/store.h [new file with mode: 0644]
src/rgw/store/json_config/store.cc [new file with mode: 0644]
src/rgw/store/json_config/store.h [new file with mode: 0644]

index 6713512d6777b9874b933d8888ad23d37354a01f..02c1fa575583adf03756ce7309129b56dd3f44ab 100644 (file)
@@ -176,6 +176,8 @@ set(librgw_common_srcs
   rgw_lua_background.cc)
 
 list(APPEND librgw_common_srcs
+  store/immutable_config/store.cc
+  store/json_config/store.cc
   store/rados/config/impl.cc
   store/rados/config/period.cc
   store/rados/config/period_config.cc
diff --git a/src/rgw/store/immutable_config/store.cc b/src/rgw/store/immutable_config/store.cc
new file mode 100644 (file)
index 0000000..8d3e076
--- /dev/null
@@ -0,0 +1,422 @@
+// 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 "store.h"
+
+namespace rgw::sal {
+
+ImmutableConfigStore::ImmutableConfigStore(const RGWZoneGroup& zonegroup,
+                                           const RGWZoneParams& zone,
+                                           const RGWPeriodConfig& period_config)
+    : zonegroup(zonegroup), zone(zone), period_config(period_config)
+{
+}
+
+// Realm
+int ImmutableConfigStore::write_default_realm_id(const DoutPrefixProvider* dpp,
+                                                 optional_yield y, bool exclusive,
+                                                 std::string_view realm_id)
+{
+  return -EROFS;
+}
+
+int ImmutableConfigStore::read_default_realm_id(const DoutPrefixProvider* dpp,
+                                                optional_yield y,
+                                                std::string& realm_id)
+{
+  return -ENOENT;
+}
+
+int ImmutableConfigStore::delete_default_realm_id(const DoutPrefixProvider* dpp,
+                                                  optional_yield y)
+{
+  return -EROFS;
+}
+
+
+int ImmutableConfigStore::create_realm(const DoutPrefixProvider* dpp,
+                                       optional_yield y, bool exclusive,
+                                       const RGWRealm& info,
+                                       std::unique_ptr<RealmWriter>* writer)
+{
+  return -EROFS;
+}
+
+int ImmutableConfigStore::read_realm_by_id(const DoutPrefixProvider* dpp,
+                                           optional_yield y,
+                                           std::string_view realm_id,
+                                           RGWRealm& info,
+                                           std::unique_ptr<RealmWriter>* writer)
+{
+  return -ENOENT;
+}
+
+int ImmutableConfigStore::read_realm_by_name(const DoutPrefixProvider* dpp,
+                                             optional_yield y,
+                                             std::string_view realm_name,
+                                             RGWRealm& info,
+                                             std::unique_ptr<RealmWriter>* writer)
+{
+  return -ENOENT;
+}
+
+int ImmutableConfigStore::read_default_realm(const DoutPrefixProvider* dpp,
+                                             optional_yield y,
+                                             RGWRealm& info,
+                                             std::unique_ptr<RealmWriter>* writer)
+{
+  return -ENOENT;
+}
+
+int ImmutableConfigStore::read_realm_id(const DoutPrefixProvider* dpp,
+                                        optional_yield y, std::string_view realm_name,
+                                        std::string& realm_id)
+{
+  return -ENOENT;
+}
+
+int ImmutableConfigStore::realm_notify_new_period(const DoutPrefixProvider* dpp,
+                                                  optional_yield y,
+                                                  const RGWPeriod& period)
+{
+  return -ENOTSUP;
+}
+
+int ImmutableConfigStore::list_realm_names(const DoutPrefixProvider* dpp,
+                                           optional_yield y, const std::string& marker,
+                                           std::span<std::string> entries,
+                                           ListResult<std::string>& result)
+{
+  result.next.clear();
+  result.entries = entries.first(0);
+  return 0;
+}
+
+
+// Period
+int ImmutableConfigStore::create_period(const DoutPrefixProvider* dpp,
+                                        optional_yield y, bool exclusive,
+                                        const RGWPeriod& info)
+{
+  return -EROFS;
+}
+
+int ImmutableConfigStore::read_period(const DoutPrefixProvider* dpp,
+                                      optional_yield y, std::string_view period_id,
+                                      std::optional<uint32_t> epoch, RGWPeriod& info)
+{
+  return -ENOENT;
+}
+
+int ImmutableConfigStore::delete_period(const DoutPrefixProvider* dpp,
+                                        optional_yield y,
+                                        std::string_view period_id)
+{
+  return -EROFS;
+}
+
+int ImmutableConfigStore::list_period_ids(const DoutPrefixProvider* dpp,
+                                          optional_yield y, const std::string& marker,
+                                          std::span<std::string> entries,
+                                          ListResult<std::string>& result)
+{
+  result.next.clear();
+  result.entries = entries.first(0);
+  return 0;
+}
+
+
+// ZoneGroup
+
+class ImmutableZoneGroupWriter : public ZoneGroupWriter {
+ public:
+  int write(const DoutPrefixProvider* dpp, optional_yield y,
+            const RGWZoneGroup& info) override
+  {
+    return -EROFS;
+  }
+  int rename(const DoutPrefixProvider* dpp, optional_yield y,
+             RGWZoneGroup& info, std::string_view new_name) override
+  {
+    return -EROFS;
+  }
+  int remove(const DoutPrefixProvider* dpp, optional_yield y) override
+  {
+    return -EROFS;
+  }
+};
+
+int ImmutableConfigStore::write_default_zonegroup_id(const DoutPrefixProvider* dpp,
+                                                     optional_yield y, bool exclusive,
+                                                     std::string_view realm_id,
+                                                     std::string_view zonegroup_id)
+{
+  return -EROFS;
+}
+
+int ImmutableConfigStore::read_default_zonegroup_id(const DoutPrefixProvider* dpp,
+                                                    optional_yield y,
+                                                    std::string_view realm_id,
+                                                    std::string& zonegroup_id)
+{
+  if (!realm_id.empty()) {
+    return -ENOENT;
+  }
+  zonegroup_id = zonegroup.id;
+  return 0;
+}
+
+int ImmutableConfigStore::delete_default_zonegroup_id(const DoutPrefixProvider* dpp,
+                                                      optional_yield y,
+                                                      std::string_view realm_id)
+{
+  return -EROFS;
+}
+
+
+int ImmutableConfigStore::create_zonegroup(const DoutPrefixProvider* dpp,
+                                           optional_yield y, bool exclusive,
+                                           const RGWZoneGroup& info,
+                                           std::unique_ptr<ZoneGroupWriter>* writer)
+{
+  return -EROFS;
+}
+
+int ImmutableConfigStore::read_zonegroup_by_id(const DoutPrefixProvider* dpp,
+                                               optional_yield y,
+                                               std::string_view zonegroup_id,
+                                               RGWZoneGroup& info,
+                                               std::unique_ptr<ZoneGroupWriter>* writer)
+{
+  if (zonegroup_id != zonegroup.id) {
+    return -ENOENT;
+  }
+
+  info = zonegroup;
+
+  if (writer) {
+    *writer = std::make_unique<ImmutableZoneGroupWriter>();
+  }
+  return 0;
+}
+int ImmutableConfigStore::read_zonegroup_by_name(const DoutPrefixProvider* dpp,
+                                                 optional_yield y,
+                                                 std::string_view zonegroup_name,
+                                                 RGWZoneGroup& info,
+                                                 std::unique_ptr<ZoneGroupWriter>* writer)
+{
+  if (zonegroup_name != zonegroup.name) {
+    return -ENOENT;
+  }
+
+  info = zonegroup;
+
+  if (writer) {
+    *writer = std::make_unique<ImmutableZoneGroupWriter>();
+  }
+  return 0;
+}
+
+int ImmutableConfigStore::read_default_zonegroup(const DoutPrefixProvider* dpp,
+                                                 optional_yield y,
+                                                 std::string_view realm_id,
+                                                 RGWZoneGroup& info,
+                                                 std::unique_ptr<ZoneGroupWriter>* writer)
+{
+  info = zonegroup;
+
+  if (writer) {
+    *writer = std::make_unique<ImmutableZoneGroupWriter>();
+  }
+  return 0;
+}
+
+int ImmutableConfigStore::list_zonegroup_names(const DoutPrefixProvider* dpp,
+                                               optional_yield y, const std::string& marker,
+                                               std::span<std::string> entries,
+                                               ListResult<std::string>& result)
+{
+  if (marker < zonegroup.name) {
+    entries[0] = zonegroup.name;
+    result.next = zonegroup.name;
+    result.entries = entries.first(1);
+  } else {
+    result.next.clear();
+    result.entries = entries.first(0);
+  }
+  return 0;
+}
+
+// Zone
+
+class ImmutableZoneWriter : public ZoneWriter {
+ public:
+  int write(const DoutPrefixProvider* dpp, optional_yield y,
+            const RGWZoneParams& info) override
+  {
+    return -EROFS;
+  }
+  int rename(const DoutPrefixProvider* dpp, optional_yield y,
+             RGWZoneParams& info, std::string_view new_name) override
+  {
+    return -EROFS;
+  }
+  int remove(const DoutPrefixProvider* dpp, optional_yield y) override
+  {
+    return -EROFS;
+  }
+};
+
+int ImmutableConfigStore::write_default_zone_id(const DoutPrefixProvider* dpp,
+                                                optional_yield y, bool exclusive,
+                                                std::string_view realm_id,
+                                                std::string_view zone_id)
+{
+  return -EROFS;
+}
+
+int ImmutableConfigStore::read_default_zone_id(const DoutPrefixProvider* dpp,
+                                               optional_yield y,
+                                               std::string_view realm_id,
+                                               std::string& zone_id)
+{
+  if (realm_id.empty()) {
+    return -ENOENT;
+  }
+  zone_id = zone.id;
+  return 0;
+}
+
+int ImmutableConfigStore::delete_default_zone_id(const DoutPrefixProvider* dpp,
+                                                 optional_yield y,
+                                                 std::string_view realm_id)
+{
+  return -EROFS;
+}
+
+
+int ImmutableConfigStore::create_zone(const DoutPrefixProvider* dpp,
+                                      optional_yield y, bool exclusive,
+                                      const RGWZoneParams& info,
+                                      std::unique_ptr<ZoneWriter>* writer)
+{
+  return -EROFS;
+}
+
+int ImmutableConfigStore::read_zone_by_id(const DoutPrefixProvider* dpp,
+                                          optional_yield y,
+                                          std::string_view zone_id,
+                                          RGWZoneParams& info,
+                                          std::unique_ptr<ZoneWriter>* writer)
+{
+  if (zone_id != zone.id) {
+    return -ENOENT;
+  }
+
+  info = zone;
+
+  if (writer) {
+    *writer = std::make_unique<ImmutableZoneWriter>();
+  }
+  return 0;
+}
+
+int ImmutableConfigStore::read_zone_by_name(const DoutPrefixProvider* dpp,
+                                            optional_yield y,
+                                            std::string_view zone_name,
+                                            RGWZoneParams& info,
+                                            std::unique_ptr<ZoneWriter>* writer)
+{
+  if (zone_name != zone.name) {
+    return -ENOENT;
+  }
+
+  info = zone;
+
+  if (writer) {
+    *writer = std::make_unique<ImmutableZoneWriter>();
+  }
+  return 0;
+}
+
+int ImmutableConfigStore::read_default_zone(const DoutPrefixProvider* dpp,
+                                            optional_yield y,
+                                            std::string_view realm_id,
+                                            RGWZoneParams& info,
+                                            std::unique_ptr<ZoneWriter>* writer)
+{
+  if (!realm_id.empty()) {
+    return -ENOENT;
+  }
+
+  info = zone;
+
+  if (writer) {
+    *writer = std::make_unique<ImmutableZoneWriter>();
+  }
+  return 0;
+}
+
+int ImmutableConfigStore::list_zone_names(const DoutPrefixProvider* dpp,
+                                          optional_yield y, const std::string& marker,
+                                          std::span<std::string> entries,
+                                          ListResult<std::string>& result)
+{
+  if (marker < zone.name) {
+    entries[0] = zone.name;
+    result.next = zone.name;
+    result.entries = entries.first(1);
+  } else {
+    result.next.clear();
+    result.entries = entries.first(0);
+  }
+  return 0;
+}
+
+
+// PeriodConfig
+int ImmutableConfigStore::read_period_config(const DoutPrefixProvider* dpp,
+                                             optional_yield y,
+                                             std::string_view realm_id,
+                                             RGWPeriodConfig& info)
+{
+  if (!realm_id.empty()) {
+    return -ENOENT;
+  }
+
+  info = period_config;
+  return 0;
+}
+
+int ImmutableConfigStore::write_period_config(const DoutPrefixProvider* dpp,
+                                              optional_yield y, bool exclusive,
+                                              std::string_view realm_id,
+                                              const RGWPeriodConfig& info)
+{
+  return -EROFS;
+}
+
+
+/// ImmutableConfigStore factory function
+auto create_immutable_config_store(const DoutPrefixProvider* dpp,
+                                   const RGWZoneGroup& zonegroup,
+                                   const RGWZoneParams& zone,
+                                   const RGWPeriodConfig& period_config)
+  -> std::unique_ptr<ConfigStore>
+{
+  return std::make_unique<ImmutableConfigStore>(zonegroup, zone, period_config);
+}
+
+} // namespace rgw::sal
diff --git a/src/rgw/store/immutable_config/store.h b/src/rgw/store/immutable_config/store.h
new file mode 100644 (file)
index 0000000..9a1ac5f
--- /dev/null
@@ -0,0 +1,180 @@
+// 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 "rgw_sal_config.h"
+
+namespace rgw::sal {
+
+/// A read-only ConfigStore that serves the given default zonegroup and zone.
+class ImmutableConfigStore : public ConfigStore {
+ public:
+  explicit ImmutableConfigStore(const RGWZoneGroup& zonegroup,
+                                const RGWZoneParams& zone,
+                                const RGWPeriodConfig& period_config);
+
+  // 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<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<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<RealmWriter>* writer) override;
+  virtual int read_default_realm(const DoutPrefixProvider* dpp,
+                                 optional_yield y,
+                                 RGWRealm& info,
+                                 std::unique_ptr<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,
+                               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,
+                              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<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<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<ZoneGroupWriter>* writer) override;
+  virtual int read_default_zonegroup(const DoutPrefixProvider* dpp,
+                                     optional_yield y,
+                                     std::string_view realm_id,
+                                     RGWZoneGroup& info,
+                                     std::unique_ptr<ZoneGroupWriter>* writer) override;
+  virtual int list_zonegroup_names(const DoutPrefixProvider* dpp,
+                                   optional_yield y, const std::string& marker,
+                                   std::span<std::string> entries,
+                                   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<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<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<ZoneWriter>* writer) override;
+  virtual int read_default_zone(const DoutPrefixProvider* dpp,
+                                optional_yield y,
+                                std::string_view realm_id,
+                                RGWZoneParams& info,
+                                std::unique_ptr<ZoneWriter>* writer) override;
+  virtual int list_zone_names(const DoutPrefixProvider* dpp,
+                              optional_yield y, const std::string& marker,
+                              std::span<std::string> entries,
+                              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:
+  const RGWZoneGroup zonegroup;
+  const RGWZoneParams zone;
+  const RGWPeriodConfig period_config;
+}; // ImmutableConfigStore
+
+
+/// ImmutableConfigStore factory function
+auto create_immutable_config_store(const DoutPrefixProvider* dpp,
+                                   const RGWZoneGroup& zonegroup,
+                                   const RGWZoneParams& zone,
+                                   const RGWPeriodConfig& period_config)
+  -> std::unique_ptr<ConfigStore>;
+
+} // namespace rgw::sal
diff --git a/src/rgw/store/json_config/store.cc b/src/rgw/store/json_config/store.cc
new file mode 100644 (file)
index 0000000..49837a8
--- /dev/null
@@ -0,0 +1,176 @@
+// 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 <system_error>
+#include "include/buffer.h"
+#include "common/errno.h"
+#include "common/ceph_json.h"
+#include "rgw_zone.h"
+#include "store/immutable_config/store.h"
+#include "store.h"
+
+namespace rgw::sal {
+
+namespace {
+
+struct DecodedConfig {
+  RGWZoneGroup zonegroup;
+  RGWZoneParams zone;
+  RGWPeriodConfig period_config;
+
+  void decode_json(JSONObj *obj)
+  {
+    JSONDecoder::decode_json("zonegroup", zonegroup, obj);
+    JSONDecoder::decode_json("zone", zone, obj);
+    JSONDecoder::decode_json("period_config", period_config, obj);
+  }
+};
+
+static void parse_config(const DoutPrefixProvider* dpp, const char* filename)
+{
+  bufferlist bl;
+  std::string errmsg;
+  int r = bl.read_file(filename, &errmsg);
+  if (r < 0) {
+    ldpp_dout(dpp, 0) << "failed to read json config file '" << filename
+        << "': " << errmsg << dendl;
+    throw std::system_error(-r, std::system_category());
+  }
+
+  JSONParser p;
+  if (!p.parse(bl.c_str(), bl.length())) {
+    ldpp_dout(dpp, 0) << "failed to parse json config file" << dendl;
+    throw std::system_error(make_error_code(std::errc::invalid_argument));
+  }
+
+  DecodedConfig config;
+  try {
+    decode_json_obj(config, &p);
+  } catch (const JSONDecoder::err& e) {
+    ldpp_dout(dpp, 0) << "failed to decode JSON input: " << e.what() << dendl;
+    throw std::system_error(make_error_code(std::errc::invalid_argument));
+  }
+}
+
+void sanity_check_config(const DoutPrefixProvider* dpp, DecodedConfig& config)
+{
+  if (config.zonegroup.id.empty()) {
+    config.zonegroup.id = "default";
+  }
+  if (config.zonegroup.name.empty()) {
+    config.zonegroup.name = "default";
+  }
+  if (config.zonegroup.api_name.empty()) {
+    config.zonegroup.api_name = config.zonegroup.name;
+  }
+
+  if (config.zone.id.empty()) {
+    config.zone.id = "default";
+  }
+  if (config.zone.name.empty()) {
+    config.zone.name = "default";
+  }
+
+  // add default placement if it doesn't exist
+  rgw_pool pool;
+  RGWZonePlacementInfo placement;
+  placement.storage_classes.set_storage_class(
+      RGW_STORAGE_CLASS_STANDARD, &pool, nullptr);
+  config.zone.placement_pools.emplace("default-placement",
+                                      std::move(placement));
+
+  std::set<rgw_pool> pools;
+  int r = rgw::init_zone_pool_names(dpp, null_yield, pools, config.zone);
+  if (r < 0) {
+    ldpp_dout(dpp, 0) << "failed to set default zone pool names" << dendl;
+    throw std::system_error(-r, std::system_category());
+  }
+
+  // verify that config.zonegroup only contains config.zone
+  if (config.zonegroup.zones.size() > 1) {
+    ldpp_dout(dpp, 0) << "zonegroup cannot contain multiple zones" << dendl;
+    throw std::system_error(make_error_code(std::errc::invalid_argument));
+  }
+
+  if (config.zonegroup.zones.size() == 1) {
+    auto z = config.zonegroup.zones.begin();
+    if (z->first != config.zone.id) {
+      ldpp_dout(dpp, 0) << "zonegroup contains unknown zone id="
+          << z->first << dendl;
+      throw std::system_error(make_error_code(std::errc::invalid_argument));
+    }
+    if (z->second.id != config.zone.id) {
+      ldpp_dout(dpp, 0) << "zonegroup contains unknown zone id="
+          << z->second.id << dendl;
+      throw std::system_error(make_error_code(std::errc::invalid_argument));
+    }
+    if (z->second.name != config.zone.name) {
+      ldpp_dout(dpp, 0) << "zonegroup contains unknown zone name="
+          << z->second.name << dendl;
+      throw std::system_error(make_error_code(std::errc::invalid_argument));
+    }
+    if (config.zonegroup.master_zone != config.zone.id) {
+      ldpp_dout(dpp, 0) << "zonegroup contains unknown master_zone="
+          << config.zonegroup.master_zone << dendl;
+      throw std::system_error(make_error_code(std::errc::invalid_argument));
+    }
+  } else {
+    // add the zone to the group
+    const bool is_master = true;
+    const bool read_only = false;
+    std::list<std::string> endpoints;
+    std::list<std::string> sync_from;
+    std::list<std::string> sync_from_rm;
+    rgw::zone_features::set enable_features;
+    rgw::zone_features::set disable_features;
+
+    enable_features.insert(rgw::zone_features::supported.begin(),
+                           rgw::zone_features::supported.end());
+
+    int r = rgw::add_zone_to_group(dpp, config.zonegroup, config.zone,
+                                   &is_master, &read_only, endpoints,
+                                   nullptr, nullptr, sync_from, sync_from_rm,
+                                   nullptr, std::nullopt,
+                                   enable_features, disable_features);
+    if (r < 0) {
+      ldpp_dout(dpp, 0) << "failed to add zone to zonegroup: "
+          << cpp_strerror(r) << dendl;
+      throw std::system_error(-r, std::system_category());
+    }
+
+    config.zonegroup.enabled_features = std::move(enable_features);
+  }
+
+  // insert the default placement target if it doesn't exist
+  auto target = RGWZoneGroupPlacementTarget{.name = "default-placement"};
+  config.zonegroup.placement_targets.emplace(target.name, target);
+  if (config.zonegroup.default_placement.name.empty()) {
+    config.zonegroup.default_placement.name = target.name;
+  }
+}
+
+} // anonymous namespace
+
+auto create_json_config_store(const DoutPrefixProvider* dpp,
+                              const std::string& filename)
+    -> std::unique_ptr<ConfigStore>
+{
+  DecodedConfig config;
+  parse_config(dpp, filename.c_str());
+  sanity_check_config(dpp, config);
+  return create_immutable_config_store(dpp, config.zonegroup, config.zone,
+                                       config.period_config);
+}
+
+} // namespace rgw::sal
diff --git a/src/rgw/store/json_config/store.h b/src/rgw/store/json_config/store.h
new file mode 100644 (file)
index 0000000..63ddf6f
--- /dev/null
@@ -0,0 +1,27 @@
+// 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 "store/immutable_config/store.h"
+
+namespace rgw::sal {
+
+/// Create an immutable ConfigStore by parsing the zonegroup and zone from the
+/// given json filename.
+auto create_json_config_store(const DoutPrefixProvider* dpp,
+                              const std::string& filename)
+    -> std::unique_ptr<ConfigStore>;
+
+} // namespace rgw::sal