]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/driver/json_config/store.cc
330aa344dc522b98678598e0116b90a6e7408d51
[ceph.git] / ceph / src / rgw / driver / json_config / store.cc
1 // vim: ts=8 sw=2 smarttab ft=cpp
2
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2022 Red Hat, Inc.
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include <system_error>
16 #include "include/buffer.h"
17 #include "common/errno.h"
18 #include "common/ceph_json.h"
19 #include "rgw_zone.h"
20 #include "driver/immutable_config/store.h"
21 #include "store.h"
22
23 namespace rgw::sal {
24
25 namespace {
26
27 struct DecodedConfig {
28 RGWZoneGroup zonegroup;
29 RGWZoneParams zone;
30 RGWPeriodConfig period_config;
31
32 void decode_json(JSONObj *obj)
33 {
34 JSONDecoder::decode_json("zonegroup", zonegroup, obj);
35 JSONDecoder::decode_json("zone", zone, obj);
36 JSONDecoder::decode_json("period_config", period_config, obj);
37 }
38 };
39
40 static void parse_config(const DoutPrefixProvider* dpp, const char* filename)
41 {
42 bufferlist bl;
43 std::string errmsg;
44 int r = bl.read_file(filename, &errmsg);
45 if (r < 0) {
46 ldpp_dout(dpp, 0) << "failed to read json config file '" << filename
47 << "': " << errmsg << dendl;
48 throw std::system_error(-r, std::system_category());
49 }
50
51 JSONParser p;
52 if (!p.parse(bl.c_str(), bl.length())) {
53 ldpp_dout(dpp, 0) << "failed to parse json config file" << dendl;
54 throw std::system_error(make_error_code(std::errc::invalid_argument));
55 }
56
57 DecodedConfig config;
58 try {
59 decode_json_obj(config, &p);
60 } catch (const JSONDecoder::err& e) {
61 ldpp_dout(dpp, 0) << "failed to decode JSON input: " << e.what() << dendl;
62 throw std::system_error(make_error_code(std::errc::invalid_argument));
63 }
64 }
65
66 void sanity_check_config(const DoutPrefixProvider* dpp, DecodedConfig& config)
67 {
68 if (config.zonegroup.id.empty()) {
69 config.zonegroup.id = "default";
70 }
71 if (config.zonegroup.name.empty()) {
72 config.zonegroup.name = "default";
73 }
74 if (config.zonegroup.api_name.empty()) {
75 config.zonegroup.api_name = config.zonegroup.name;
76 }
77
78 if (config.zone.id.empty()) {
79 config.zone.id = "default";
80 }
81 if (config.zone.name.empty()) {
82 config.zone.name = "default";
83 }
84
85 // add default placement if it doesn't exist
86 rgw_pool pool;
87 RGWZonePlacementInfo placement;
88 placement.storage_classes.set_storage_class(
89 RGW_STORAGE_CLASS_STANDARD, &pool, nullptr);
90 config.zone.placement_pools.emplace("default-placement",
91 std::move(placement));
92
93 std::set<rgw_pool> pools;
94 int r = rgw::init_zone_pool_names(dpp, null_yield, pools, config.zone);
95 if (r < 0) {
96 ldpp_dout(dpp, 0) << "failed to set default zone pool names" << dendl;
97 throw std::system_error(-r, std::system_category());
98 }
99
100 // verify that config.zonegroup only contains config.zone
101 if (config.zonegroup.zones.size() > 1) {
102 ldpp_dout(dpp, 0) << "zonegroup cannot contain multiple zones" << dendl;
103 throw std::system_error(make_error_code(std::errc::invalid_argument));
104 }
105
106 if (config.zonegroup.zones.size() == 1) {
107 auto z = config.zonegroup.zones.begin();
108 if (z->first != config.zone.id) {
109 ldpp_dout(dpp, 0) << "zonegroup contains unknown zone id="
110 << z->first << dendl;
111 throw std::system_error(make_error_code(std::errc::invalid_argument));
112 }
113 if (z->second.id != config.zone.id) {
114 ldpp_dout(dpp, 0) << "zonegroup contains unknown zone id="
115 << z->second.id << dendl;
116 throw std::system_error(make_error_code(std::errc::invalid_argument));
117 }
118 if (z->second.name != config.zone.name) {
119 ldpp_dout(dpp, 0) << "zonegroup contains unknown zone name="
120 << z->second.name << dendl;
121 throw std::system_error(make_error_code(std::errc::invalid_argument));
122 }
123 if (config.zonegroup.master_zone != config.zone.id) {
124 ldpp_dout(dpp, 0) << "zonegroup contains unknown master_zone="
125 << config.zonegroup.master_zone << dendl;
126 throw std::system_error(make_error_code(std::errc::invalid_argument));
127 }
128 } else {
129 // add the zone to the group
130 const bool is_master = true;
131 const bool read_only = false;
132 std::list<std::string> endpoints;
133 std::list<std::string> sync_from;
134 std::list<std::string> sync_from_rm;
135 rgw::zone_features::set enable_features;
136 rgw::zone_features::set disable_features;
137
138 enable_features.insert(rgw::zone_features::supported.begin(),
139 rgw::zone_features::supported.end());
140
141 int r = rgw::add_zone_to_group(dpp, config.zonegroup, config.zone,
142 &is_master, &read_only, endpoints,
143 nullptr, nullptr, sync_from, sync_from_rm,
144 nullptr, std::nullopt,
145 enable_features, disable_features);
146 if (r < 0) {
147 ldpp_dout(dpp, 0) << "failed to add zone to zonegroup: "
148 << cpp_strerror(r) << dendl;
149 throw std::system_error(-r, std::system_category());
150 }
151
152 config.zonegroup.enabled_features = std::move(enable_features);
153 }
154
155 // insert the default placement target if it doesn't exist
156 auto target = RGWZoneGroupPlacementTarget{.name = "default-placement"};
157 config.zonegroup.placement_targets.emplace(target.name, target);
158 if (config.zonegroup.default_placement.name.empty()) {
159 config.zonegroup.default_placement.name = target.name;
160 }
161 }
162
163 } // anonymous namespace
164
165 auto create_json_config_store(const DoutPrefixProvider* dpp,
166 const std::string& filename)
167 -> std::unique_ptr<ConfigStore>
168 {
169 DecodedConfig config;
170 parse_config(dpp, filename.c_str());
171 sanity_check_config(dpp, config);
172 return create_immutable_config_store(dpp, config.zonegroup, config.zone,
173 config.period_config);
174 }
175
176 } // namespace rgw::sal