]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
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 |