]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/services/svc_zone.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rgw / services / svc_zone.cc
1 #include "svc_zone.h"
2 #include "svc_rados.h"
3 #include "svc_sys_obj.h"
4 #include "svc_sync_modules.h"
5
6 #include "rgw/rgw_zone.h"
7 #include "rgw/rgw_rest_conn.h"
8
9 #include "common/errno.h"
10 #include "include/random.h"
11
12 #define dout_subsys ceph_subsys_rgw
13
14 using namespace rgw_zone_defaults;
15
16 RGWSI_Zone::RGWSI_Zone(CephContext *cct) : RGWServiceInstance(cct)
17 {
18 }
19
20 void RGWSI_Zone::init(RGWSI_SysObj *_sysobj_svc,
21 RGWSI_RADOS * _rados_svc,
22 RGWSI_SyncModules * _sync_modules_svc)
23 {
24 sysobj_svc = _sysobj_svc;
25 rados_svc = _rados_svc;
26 sync_modules_svc = _sync_modules_svc;
27
28 realm = new RGWRealm();
29 zonegroup = new RGWZoneGroup();
30 zone_public_config = new RGWZone();
31 zone_params = new RGWZoneParams();
32 current_period = new RGWPeriod();
33 }
34
35 RGWSI_Zone::~RGWSI_Zone()
36 {
37 delete realm;
38 delete zonegroup;
39 delete zone_public_config;
40 delete zone_params;
41 delete current_period;
42 }
43
44 bool RGWSI_Zone::zone_syncs_from(const RGWZone& target_zone, const RGWZone& source_zone) const
45 {
46 return target_zone.syncs_from(source_zone.name) &&
47 sync_modules_svc->get_manager()->supports_data_export(source_zone.tier_type);
48 }
49
50 int RGWSI_Zone::do_start()
51 {
52 int ret = sysobj_svc->start();
53 if (ret < 0) {
54 return ret;
55 }
56
57 assert(sysobj_svc->is_started()); /* if not then there's ordering issue */
58
59 ret = rados_svc->start();
60 if (ret < 0) {
61 return ret;
62 }
63 ret = sync_modules_svc->start();
64 if (ret < 0) {
65 return ret;
66 }
67 ret = realm->init(cct, sysobj_svc);
68 if (ret < 0 && ret != -ENOENT) {
69 ldout(cct, 0) << "failed reading realm info: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
70 return ret;
71 } else if (ret != -ENOENT) {
72 ldout(cct, 20) << "realm " << realm->get_name() << " " << realm->get_id() << dendl;
73 ret = current_period->init(cct, sysobj_svc, realm->get_id(), realm->get_name());
74 if (ret < 0 && ret != -ENOENT) {
75 ldout(cct, 0) << "failed reading current period info: " << " " << cpp_strerror(-ret) << dendl;
76 return ret;
77 }
78 ldout(cct, 20) << "current period " << current_period->get_id() << dendl;
79 }
80
81 ret = replace_region_with_zonegroup();
82 if (ret < 0) {
83 lderr(cct) << "failed converting region to zonegroup : ret "<< ret << " " << cpp_strerror(-ret) << dendl;
84 return ret;
85 }
86
87 ret = convert_regionmap();
88 if (ret < 0) {
89 lderr(cct) << "failed converting regionmap: " << cpp_strerror(-ret) << dendl;
90 return ret;
91 }
92
93 bool zg_initialized = false;
94
95 if (!current_period->get_id().empty()) {
96 ret = init_zg_from_period(&zg_initialized);
97 if (ret < 0) {
98 return ret;
99 }
100 }
101
102 bool creating_defaults = false;
103 bool using_local = (!zg_initialized);
104 if (using_local) {
105 ldout(cct, 10) << " cannot find current period zonegroup using local zonegroup" << dendl;
106 ret = init_zg_from_local(&creating_defaults);
107 if (ret < 0) {
108 return ret;
109 }
110 // read period_config into current_period
111 auto& period_config = current_period->get_config();
112 ret = period_config.read(sysobj_svc, zonegroup->realm_id);
113 if (ret < 0 && ret != -ENOENT) {
114 ldout(cct, 0) << "ERROR: failed to read period config: "
115 << cpp_strerror(ret) << dendl;
116 return ret;
117 }
118 }
119
120 ldout(cct, 10) << "Cannot find current period zone using local zone" << dendl;
121 if (creating_defaults && cct->_conf->rgw_zone.empty()) {
122 ldout(cct, 10) << " Using default name "<< default_zone_name << dendl;
123 zone_params->set_name(default_zone_name);
124 }
125
126 ret = zone_params->init(cct, sysobj_svc);
127 if (ret < 0 && ret != -ENOENT) {
128 lderr(cct) << "failed reading zone info: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
129 return ret;
130 }
131 auto zone_iter = zonegroup->zones.find(zone_params->get_id());
132 if (zone_iter == zonegroup->zones.end()) {
133 if (using_local) {
134 lderr(cct) << "Cannot find zone id=" << zone_params->get_id() << " (name=" << zone_params->get_name() << ")" << dendl;
135 return -EINVAL;
136 }
137 ldout(cct, 1) << "Cannot find zone id=" << zone_params->get_id() << " (name=" << zone_params->get_name() << "), switching to local zonegroup configuration" << dendl;
138 ret = init_zg_from_local(&creating_defaults);
139 if (ret < 0) {
140 return ret;
141 }
142 zone_iter = zonegroup->zones.find(zone_params->get_id());
143 }
144 if (zone_iter != zonegroup->zones.end()) {
145 *zone_public_config = zone_iter->second;
146 ldout(cct, 20) << "zone " << zone_params->get_name() << dendl;
147 } else {
148 lderr(cct) << "Cannot find zone id=" << zone_params->get_id() << " (name=" << zone_params->get_name() << ")" << dendl;
149 return -EINVAL;
150 }
151
152 zone_short_id = current_period->get_map().get_zone_short_id(zone_params->get_id());
153
154 RGWSyncModuleRef sm;
155 if (!sync_modules_svc->get_manager()->get_module(zone_public_config->tier_type, &sm)) {
156 lderr(cct) << "ERROR: tier type not found: " << zone_public_config->tier_type << dendl;
157 return -EINVAL;
158 }
159
160 writeable_zone = sm->supports_writes();
161
162 /* first build all zones index */
163 for (auto ziter : zonegroup->zones) {
164 const string& id = ziter.first;
165 RGWZone& z = ziter.second;
166 zone_id_by_name[z.name] = id;
167 zone_by_id[id] = z;
168 }
169
170 if (zone_by_id.find(zone_id()) == zone_by_id.end()) {
171 ldout(cct, 0) << "WARNING: could not find zone config in zonegroup for local zone (" << zone_id() << "), will use defaults" << dendl;
172 }
173 *zone_public_config = zone_by_id[zone_id()];
174 for (auto ziter : zonegroup->zones) {
175 const string& id = ziter.first;
176 RGWZone& z = ziter.second;
177 if (id == zone_id()) {
178 continue;
179 }
180 if (z.endpoints.empty()) {
181 ldout(cct, 0) << "WARNING: can't generate connection for zone " << z.id << " id " << z.name << ": no endpoints defined" << dendl;
182 continue;
183 }
184 ldout(cct, 20) << "generating connection object for zone " << z.name << " id " << z.id << dendl;
185 RGWRESTConn *conn = new RGWRESTConn(cct, this, z.id, z.endpoints);
186 zone_conn_map[id] = conn;
187 if (zone_syncs_from(*zone_public_config, z) ||
188 zone_syncs_from(z, *zone_public_config)) {
189 if (zone_syncs_from(*zone_public_config, z)) {
190 zone_data_sync_from_map[id] = conn;
191 }
192 if (zone_syncs_from(z, *zone_public_config)) {
193 zone_data_notify_to_map[id] = conn;
194 }
195 } else {
196 ldout(cct, 20) << "NOTICE: not syncing to/from zone " << z.name << " id " << z.id << dendl;
197 }
198 }
199
200 return 0;
201 }
202
203 void RGWSI_Zone::shutdown()
204 {
205 delete rest_master_conn;
206
207 map<string, RGWRESTConn *>::iterator iter;
208 for (iter = zone_conn_map.begin(); iter != zone_conn_map.end(); ++iter) {
209 RGWRESTConn *conn = iter->second;
210 delete conn;
211 }
212
213 for (iter = zonegroup_conn_map.begin(); iter != zonegroup_conn_map.end(); ++iter) {
214 RGWRESTConn *conn = iter->second;
215 delete conn;
216 }
217 }
218
219 int RGWSI_Zone::list_regions(list<string>& regions)
220 {
221 RGWZoneGroup zonegroup;
222 RGWSI_SysObj::Pool syspool = sysobj_svc->get_pool(zonegroup.get_pool(cct));
223
224 return syspool.op().list_prefixed_objs(region_info_oid_prefix, &regions);
225 }
226
227 int RGWSI_Zone::list_zonegroups(list<string>& zonegroups)
228 {
229 RGWZoneGroup zonegroup;
230 RGWSI_SysObj::Pool syspool = sysobj_svc->get_pool(zonegroup.get_pool(cct));
231
232 return syspool.op().list_prefixed_objs(zonegroup_names_oid_prefix, &zonegroups);
233 }
234
235 int RGWSI_Zone::list_zones(list<string>& zones)
236 {
237 RGWZoneParams zoneparams;
238 RGWSI_SysObj::Pool syspool = sysobj_svc->get_pool(zoneparams.get_pool(cct));
239
240 return syspool.op().list_prefixed_objs(zone_names_oid_prefix, &zones);
241 }
242
243 int RGWSI_Zone::list_realms(list<string>& realms)
244 {
245 RGWRealm realm(cct, sysobj_svc);
246 RGWSI_SysObj::Pool syspool = sysobj_svc->get_pool(realm.get_pool(cct));
247
248 return syspool.op().list_prefixed_objs(realm_names_oid_prefix, &realms);
249 }
250
251 int RGWSI_Zone::list_periods(list<string>& periods)
252 {
253 RGWPeriod period;
254 list<string> raw_periods;
255 RGWSI_SysObj::Pool syspool = sysobj_svc->get_pool(period.get_pool(cct));
256 int ret = syspool.op().list_prefixed_objs(period.get_info_oid_prefix(), &raw_periods);
257 if (ret < 0) {
258 return ret;
259 }
260 for (const auto& oid : raw_periods) {
261 size_t pos = oid.find(".");
262 if (pos != std::string::npos) {
263 periods.push_back(oid.substr(0, pos));
264 } else {
265 periods.push_back(oid);
266 }
267 }
268 periods.sort(); // unique() only detects duplicates if they're adjacent
269 periods.unique();
270 return 0;
271 }
272
273
274 int RGWSI_Zone::list_periods(const string& current_period, list<string>& periods)
275 {
276 int ret = 0;
277 string period_id = current_period;
278 while(!period_id.empty()) {
279 RGWPeriod period(period_id);
280 ret = period.init(cct, sysobj_svc);
281 if (ret < 0) {
282 return ret;
283 }
284 periods.push_back(period.get_id());
285 period_id = period.get_predecessor();
286 }
287
288 return ret;
289 }
290
291 /**
292 * Replace all region configuration with zonegroup for
293 * backward compatability
294 * Returns 0 on success, -ERR# on failure.
295 */
296 int RGWSI_Zone::replace_region_with_zonegroup()
297 {
298 /* copy default region */
299 /* convert default region to default zonegroup */
300 string default_oid = cct->_conf->rgw_default_region_info_oid;
301 if (default_oid.empty()) {
302 default_oid = default_region_info_oid;
303 }
304
305 RGWZoneGroup default_zonegroup;
306 rgw_pool pool{default_zonegroup.get_pool(cct)};
307 string oid = "converted";
308 bufferlist bl;
309
310 RGWSysObjectCtx obj_ctx = sysobj_svc->init_obj_ctx();
311 RGWSysObj sysobj = sysobj_svc->get_obj(obj_ctx, rgw_raw_obj(pool, oid));
312
313 int ret = sysobj.rop().read(&bl);
314 if (ret < 0 && ret != -ENOENT) {
315 ldout(cct, 0) << __func__ << " failed to read converted: ret "<< ret << " " << cpp_strerror(-ret)
316 << dendl;
317 return ret;
318 } else if (ret != -ENOENT) {
319 ldout(cct, 20) << "System already converted " << dendl;
320 return 0;
321 }
322
323 string default_region;
324 ret = default_zonegroup.init(cct, sysobj_svc, false, true);
325 if (ret < 0) {
326 ldout(cct, 0) << __func__ << " failed init default region: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
327 return ret;
328 }
329 ret = default_zonegroup.read_default_id(default_region, true);
330 if (ret < 0 && ret != -ENOENT) {
331 ldout(cct, 0) << __func__ << " failed reading old default region: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
332 return ret;
333 }
334
335 /* convert regions to zonegroups */
336 list<string> regions;
337 ret = list_regions(regions);
338 if (ret < 0 && ret != -ENOENT) {
339 ldout(cct, 0) << __func__ << " failed to list regions: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
340 return ret;
341 } else if (ret == -ENOENT || regions.empty()) {
342 RGWZoneParams zoneparams(default_zone_name);
343 int ret = zoneparams.init(cct, sysobj_svc);
344 if (ret < 0 && ret != -ENOENT) {
345 ldout(cct, 0) << __func__ << ": error initializing default zone params: " << cpp_strerror(-ret) << dendl;
346 return ret;
347 }
348 /* update master zone */
349 RGWZoneGroup default_zg(default_zonegroup_name);
350 ret = default_zg.init(cct, sysobj_svc);
351 if (ret < 0 && ret != -ENOENT) {
352 ldout(cct, 0) << __func__ << ": error in initializing default zonegroup: " << cpp_strerror(-ret) << dendl;
353 return ret;
354 }
355 if (ret != -ENOENT && default_zg.master_zone.empty()) {
356 default_zg.master_zone = zoneparams.get_id();
357 return default_zg.update();
358 }
359 return 0;
360 }
361
362 string master_region, master_zone;
363 for (list<string>::iterator iter = regions.begin(); iter != regions.end(); ++iter) {
364 if (*iter != default_zonegroup_name){
365 RGWZoneGroup region(*iter);
366 int ret = region.init(cct, sysobj_svc, true, true);
367 if (ret < 0) {
368 ldout(cct, 0) << __func__ << " failed init region "<< *iter << ": " << cpp_strerror(-ret) << dendl;
369 return ret;
370 }
371 if (region.is_master_zonegroup()) {
372 master_region = region.get_id();
373 master_zone = region.master_zone;
374 }
375 }
376 }
377
378 /* create realm if there is none.
379 The realm name will be the region and zone concatenated
380 realm id will be mds of its name */
381 if (realm->get_id().empty() && !master_region.empty() && !master_zone.empty()) {
382 string new_realm_name = master_region + "." + master_zone;
383 unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE];
384 char md5_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
385 MD5 hash;
386 hash.Update((const unsigned char *)new_realm_name.c_str(), new_realm_name.length());
387 hash.Final(md5);
388 buf_to_hex(md5, CEPH_CRYPTO_MD5_DIGESTSIZE, md5_str);
389 string new_realm_id(md5_str);
390 RGWRealm new_realm(new_realm_id,new_realm_name);
391 ret = new_realm.init(cct, sysobj_svc, false);
392 if (ret < 0) {
393 ldout(cct, 0) << __func__ << " Error initing new realm: " << cpp_strerror(-ret) << dendl;
394 return ret;
395 }
396 ret = new_realm.create();
397 if (ret < 0 && ret != -EEXIST) {
398 ldout(cct, 0) << __func__ << " Error creating new realm: " << cpp_strerror(-ret) << dendl;
399 return ret;
400 }
401 ret = new_realm.set_as_default();
402 if (ret < 0) {
403 ldout(cct, 0) << __func__ << " Error setting realm as default: " << cpp_strerror(-ret) << dendl;
404 return ret;
405 }
406 ret = realm->init(cct, sysobj_svc);
407 if (ret < 0) {
408 ldout(cct, 0) << __func__ << " Error initing realm: " << cpp_strerror(-ret) << dendl;
409 return ret;
410 }
411 ret = current_period->init(cct, sysobj_svc, realm->get_id(), realm->get_name());
412 if (ret < 0) {
413 ldout(cct, 0) << __func__ << " Error initing current period: " << cpp_strerror(-ret) << dendl;
414 return ret;
415 }
416 }
417
418 list<string>::iterator iter;
419 /* create zonegroups */
420 for (iter = regions.begin(); iter != regions.end(); ++iter)
421 {
422 ldout(cct, 0) << __func__ << " Converting " << *iter << dendl;
423 /* check to see if we don't have already a zonegroup with this name */
424 RGWZoneGroup new_zonegroup(*iter);
425 ret = new_zonegroup.init(cct , sysobj_svc);
426 if (ret == 0 && new_zonegroup.get_id() != *iter) {
427 ldout(cct, 0) << __func__ << " zonegroup "<< *iter << " already exists id " << new_zonegroup.get_id () <<
428 " skipping conversion " << dendl;
429 continue;
430 }
431 RGWZoneGroup zonegroup(*iter);
432 zonegroup.set_id(*iter);
433 int ret = zonegroup.init(cct, sysobj_svc, true, true);
434 if (ret < 0) {
435 ldout(cct, 0) << __func__ << " failed init zonegroup: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
436 return ret;
437 }
438 zonegroup.realm_id = realm->get_id();
439 /* fix default region master zone */
440 if (*iter == default_zonegroup_name && zonegroup.master_zone.empty()) {
441 ldout(cct, 0) << __func__ << " Setting default zone as master for default region" << dendl;
442 zonegroup.master_zone = default_zone_name;
443 }
444 ret = zonegroup.update();
445 if (ret < 0 && ret != -EEXIST) {
446 ldout(cct, 0) << __func__ << " failed to update zonegroup " << *iter << ": ret "<< ret << " " << cpp_strerror(-ret)
447 << dendl;
448 return ret;
449 }
450 ret = zonegroup.update_name();
451 if (ret < 0 && ret != -EEXIST) {
452 ldout(cct, 0) << __func__ << " failed to update_name for zonegroup " << *iter << ": ret "<< ret << " " << cpp_strerror(-ret)
453 << dendl;
454 return ret;
455 }
456 if (zonegroup.get_name() == default_region) {
457 ret = zonegroup.set_as_default();
458 if (ret < 0) {
459 ldout(cct, 0) << __func__ << " failed to set_as_default " << *iter << ": ret "<< ret << " " << cpp_strerror(-ret)
460 << dendl;
461 return ret;
462 }
463 }
464 for (map<string, RGWZone>::const_iterator iter = zonegroup.zones.begin(); iter != zonegroup.zones.end();
465 ++iter) {
466 ldout(cct, 0) << __func__ << " Converting zone" << iter->first << dendl;
467 RGWZoneParams zoneparams(iter->first, iter->first);
468 zoneparams.set_id(iter->first);
469 zoneparams.realm_id = realm->get_id();
470 ret = zoneparams.init(cct, sysobj_svc);
471 if (ret < 0 && ret != -ENOENT) {
472 ldout(cct, 0) << __func__ << " failed to init zoneparams " << iter->first << ": " << cpp_strerror(-ret) << dendl;
473 return ret;
474 } else if (ret == -ENOENT) {
475 ldout(cct, 0) << __func__ << " zone is part of another cluster " << iter->first << " skipping " << dendl;
476 continue;
477 }
478 zonegroup.realm_id = realm->get_id();
479 ret = zoneparams.update();
480 if (ret < 0 && ret != -EEXIST) {
481 ldout(cct, 0) << __func__ << " failed to update zoneparams " << iter->first << ": " << cpp_strerror(-ret) << dendl;
482 return ret;
483 }
484 ret = zoneparams.update_name();
485 if (ret < 0 && ret != -EEXIST) {
486 ldout(cct, 0) << __func__ << " failed to init zoneparams " << iter->first << ": " << cpp_strerror(-ret) << dendl;
487 return ret;
488 }
489 }
490
491 if (!current_period->get_id().empty()) {
492 ret = current_period->add_zonegroup(zonegroup);
493 if (ret < 0) {
494 ldout(cct, 0) << __func__ << " failed to add zonegroup to current_period: " << cpp_strerror(-ret) << dendl;
495 return ret;
496 }
497 }
498 }
499
500 if (!current_period->get_id().empty()) {
501 ret = current_period->update();
502 if (ret < 0) {
503 ldout(cct, 0) << __func__ << " failed to update new period: " << cpp_strerror(-ret) << dendl;
504 return ret;
505 }
506 ret = current_period->store_info(false);
507 if (ret < 0) {
508 ldout(cct, 0) << __func__ << " failed to store new period: " << cpp_strerror(-ret) << dendl;
509 return ret;
510 }
511 ret = current_period->reflect();
512 if (ret < 0) {
513 ldout(cct, 0) << __func__ << " failed to update local objects: " << cpp_strerror(-ret) << dendl;
514 return ret;
515 }
516 }
517
518 for (auto const& iter : regions) {
519 RGWZoneGroup zonegroup(iter);
520 int ret = zonegroup.init(cct, sysobj_svc, true, true);
521 if (ret < 0) {
522 ldout(cct, 0) << __func__ << " failed init zonegroup" << iter << ": ret "<< ret << " " << cpp_strerror(-ret) << dendl;
523 return ret;
524 }
525 ret = zonegroup.delete_obj(true);
526 if (ret < 0 && ret != -ENOENT) {
527 ldout(cct, 0) << __func__ << " failed to delete region " << iter << ": ret "<< ret << " " << cpp_strerror(-ret)
528 << dendl;
529 return ret;
530 }
531 }
532
533 /* mark as converted */
534 ret = sysobj.wop()
535 .set_exclusive(true)
536 .write(bl);
537 if (ret < 0 ) {
538 ldout(cct, 0) << __func__ << " failed to mark cluster as converted: ret "<< ret << " " << cpp_strerror(-ret)
539 << dendl;
540 return ret;
541 }
542
543 return 0;
544 }
545
546 /**
547 * Add new connection to connections map
548 * @param zonegroup_conn_map map which new connection will be added to
549 * @param zonegroup zonegroup which new connection will connect to
550 * @param new_connection pointer to new connection instance
551 */
552 static void add_new_connection_to_map(map<string, RGWRESTConn *> &zonegroup_conn_map,
553 const RGWZoneGroup &zonegroup, RGWRESTConn *new_connection)
554 {
555 // Delete if connection is already exists
556 map<string, RGWRESTConn *>::iterator iterZoneGroup = zonegroup_conn_map.find(zonegroup.get_id());
557 if (iterZoneGroup != zonegroup_conn_map.end()) {
558 delete iterZoneGroup->second;
559 }
560
561 // Add new connection to connections map
562 zonegroup_conn_map[zonegroup.get_id()] = new_connection;
563 }
564
565 int RGWSI_Zone::init_zg_from_period(bool *initialized)
566 {
567 *initialized = false;
568
569 if (current_period->get_id().empty()) {
570 return 0;
571 }
572
573 int ret = zonegroup->init(cct, sysobj_svc);
574 ldout(cct, 20) << "period zonegroup init ret " << ret << dendl;
575 if (ret == -ENOENT) {
576 return 0;
577 }
578 if (ret < 0) {
579 ldout(cct, 0) << "failed reading zonegroup info: " << cpp_strerror(-ret) << dendl;
580 return ret;
581 }
582 ldout(cct, 20) << "period zonegroup name " << zonegroup->get_name() << dendl;
583
584 map<string, RGWZoneGroup>::const_iterator iter =
585 current_period->get_map().zonegroups.find(zonegroup->get_id());
586
587 if (iter != current_period->get_map().zonegroups.end()) {
588 ldout(cct, 20) << "using current period zonegroup " << zonegroup->get_name() << dendl;
589 *zonegroup = iter->second;
590 ret = zonegroup->init(cct, sysobj_svc, false);
591 if (ret < 0) {
592 ldout(cct, 0) << "failed init zonegroup: " << " " << cpp_strerror(-ret) << dendl;
593 return ret;
594 }
595 ret = zone_params->init(cct, sysobj_svc);
596 if (ret < 0 && ret != -ENOENT) {
597 ldout(cct, 0) << "failed reading zone params info: " << " " << cpp_strerror(-ret) << dendl;
598 return ret;
599 } if (ret ==-ENOENT && zonegroup->get_name() == default_zonegroup_name) {
600 ldout(cct, 10) << " Using default name "<< default_zone_name << dendl;
601 zone_params->set_name(default_zone_name);
602 ret = zone_params->init(cct, sysobj_svc);
603 if (ret < 0 && ret != -ENOENT) {
604 ldout(cct, 0) << "failed reading zone params info: " << " " << cpp_strerror(-ret) << dendl;
605 return ret;
606 }
607 }
608 }
609 for (iter = current_period->get_map().zonegroups.begin();
610 iter != current_period->get_map().zonegroups.end(); ++iter){
611 const RGWZoneGroup& zg = iter->second;
612 // use endpoints from the zonegroup's master zone
613 auto master = zg.zones.find(zg.master_zone);
614 if (master == zg.zones.end()) {
615 // Check for empty zonegroup which can happen if zone was deleted before removal
616 if (zg.zones.size() == 0)
617 continue;
618 // fix missing master zone for a single zone zonegroup
619 if (zg.master_zone.empty() && zg.zones.size() == 1) {
620 master = zg.zones.begin();
621 ldout(cct, 0) << "zonegroup " << zg.get_name() << " missing master_zone, setting zone " <<
622 master->second.name << " id:" << master->second.id << " as master" << dendl;
623 if (zonegroup->get_id() == zg.get_id()) {
624 zonegroup->master_zone = master->second.id;
625 ret = zonegroup->update();
626 if (ret < 0) {
627 ldout(cct, 0) << "error updating zonegroup : " << cpp_strerror(-ret) << dendl;
628 return ret;
629 }
630 } else {
631 RGWZoneGroup fixed_zg(zg.get_id(),zg.get_name());
632 ret = fixed_zg.init(cct, sysobj_svc);
633 if (ret < 0) {
634 ldout(cct, 0) << "error initializing zonegroup : " << cpp_strerror(-ret) << dendl;
635 return ret;
636 }
637 fixed_zg.master_zone = master->second.id;
638 ret = fixed_zg.update();
639 if (ret < 0) {
640 ldout(cct, 0) << "error initializing zonegroup : " << cpp_strerror(-ret) << dendl;
641 return ret;
642 }
643 }
644 } else {
645 ldout(cct, 0) << "zonegroup " << zg.get_name() << " missing zone for master_zone=" <<
646 zg.master_zone << dendl;
647 return -EINVAL;
648 }
649 }
650 const auto& endpoints = master->second.endpoints;
651 add_new_connection_to_map(zonegroup_conn_map, zg, new RGWRESTConn(cct, this, zg.get_id(), endpoints));
652 if (!current_period->get_master_zonegroup().empty() &&
653 zg.get_id() == current_period->get_master_zonegroup()) {
654 rest_master_conn = new RGWRESTConn(cct, this, zg.get_id(), endpoints);
655 }
656 }
657
658 *initialized = true;
659
660 return 0;
661 }
662
663 int RGWSI_Zone::init_zg_from_local(bool *creating_defaults)
664 {
665 int ret = zonegroup->init(cct, sysobj_svc);
666 if ( (ret < 0 && ret != -ENOENT) || (ret == -ENOENT && !cct->_conf->rgw_zonegroup.empty())) {
667 ldout(cct, 0) << "failed reading zonegroup info: ret "<< ret << " " << cpp_strerror(-ret) << dendl;
668 return ret;
669 } else if (ret == -ENOENT) {
670 *creating_defaults = true;
671 ldout(cct, 10) << "Creating default zonegroup " << dendl;
672 ret = zonegroup->create_default();
673 if (ret < 0) {
674 ldout(cct, 0) << "failure in zonegroup create_default: ret "<< ret << " " << cpp_strerror(-ret)
675 << dendl;
676 return ret;
677 }
678 ret = zonegroup->init(cct, sysobj_svc);
679 if (ret < 0) {
680 ldout(cct, 0) << "failure in zonegroup create_default: ret "<< ret << " " << cpp_strerror(-ret)
681 << dendl;
682 return ret;
683 }
684 }
685 ldout(cct, 20) << "zonegroup " << zonegroup->get_name() << dendl;
686 if (zonegroup->is_master_zonegroup()) {
687 // use endpoints from the zonegroup's master zone
688 auto master = zonegroup->zones.find(zonegroup->master_zone);
689 if (master == zonegroup->zones.end()) {
690 // fix missing master zone for a single zone zonegroup
691 if (zonegroup->master_zone.empty() && zonegroup->zones.size() == 1) {
692 master = zonegroup->zones.begin();
693 ldout(cct, 0) << "zonegroup " << zonegroup->get_name() << " missing master_zone, setting zone " <<
694 master->second.name << " id:" << master->second.id << " as master" << dendl;
695 zonegroup->master_zone = master->second.id;
696 ret = zonegroup->update();
697 if (ret < 0) {
698 ldout(cct, 0) << "error initializing zonegroup : " << cpp_strerror(-ret) << dendl;
699 return ret;
700 }
701 } else {
702 ldout(cct, 0) << "zonegroup " << zonegroup->get_name() << " missing zone for "
703 "master_zone=" << zonegroup->master_zone << dendl;
704 return -EINVAL;
705 }
706 }
707 const auto& endpoints = master->second.endpoints;
708 rest_master_conn = new RGWRESTConn(cct, this, zonegroup->get_id(), endpoints);
709 }
710
711 return 0;
712 }
713
714 int RGWSI_Zone::convert_regionmap()
715 {
716 RGWZoneGroupMap zonegroupmap;
717
718 string pool_name = cct->_conf->rgw_zone_root_pool;
719 if (pool_name.empty()) {
720 pool_name = RGW_DEFAULT_ZONE_ROOT_POOL;
721 }
722 string oid = region_map_oid;
723
724 rgw_pool pool(pool_name);
725 bufferlist bl;
726
727 RGWSysObjectCtx obj_ctx = sysobj_svc->init_obj_ctx();
728 RGWSysObj sysobj = sysobj_svc->get_obj(obj_ctx, rgw_raw_obj(pool, oid));
729
730 int ret = sysobj.rop().read(&bl);
731 if (ret < 0 && ret != -ENOENT) {
732 return ret;
733 } else if (ret == -ENOENT) {
734 return 0;
735 }
736
737 try {
738 auto iter = bl.cbegin();
739 decode(zonegroupmap, iter);
740 } catch (buffer::error& err) {
741 ldout(cct, 0) << "error decoding regionmap from " << pool << ":" << oid << dendl;
742 return -EIO;
743 }
744
745 for (map<string, RGWZoneGroup>::iterator iter = zonegroupmap.zonegroups.begin();
746 iter != zonegroupmap.zonegroups.end(); ++iter) {
747 RGWZoneGroup& zonegroup = iter->second;
748 ret = zonegroup.init(cct, sysobj_svc, false);
749 ret = zonegroup.update();
750 if (ret < 0 && ret != -ENOENT) {
751 ldout(cct, 0) << "Error could not update zonegroup " << zonegroup.get_name() << ": " <<
752 cpp_strerror(-ret) << dendl;
753 return ret;
754 } else if (ret == -ENOENT) {
755 ret = zonegroup.create();
756 if (ret < 0) {
757 ldout(cct, 0) << "Error could not create " << zonegroup.get_name() << ": " <<
758 cpp_strerror(-ret) << dendl;
759 return ret;
760 }
761 }
762 }
763
764 current_period->set_user_quota(zonegroupmap.user_quota);
765 current_period->set_bucket_quota(zonegroupmap.bucket_quota);
766
767 // remove the region_map so we don't try to convert again
768 ret = sysobj.wop().remove();
769 if (ret < 0) {
770 ldout(cct, 0) << "Error could not remove " << sysobj.get_obj()
771 << " after upgrading to zonegroup map: " << cpp_strerror(ret) << dendl;
772 return ret;
773 }
774
775 return 0;
776 }
777
778 const RGWZoneParams& RGWSI_Zone::get_zone_params() const
779 {
780 return *zone_params;
781 }
782
783 const RGWZone& RGWSI_Zone::get_zone() const
784 {
785 return *zone_public_config;
786 }
787
788 const RGWZoneGroup& RGWSI_Zone::get_zonegroup() const
789 {
790 return *zonegroup;
791 }
792
793 int RGWSI_Zone::get_zonegroup(const string& id, RGWZoneGroup& zg) const
794 {
795 int ret = 0;
796 if (id == zonegroup->get_id()) {
797 zg = *zonegroup;
798 } else if (!current_period->get_id().empty()) {
799 ret = current_period->get_zonegroup(zg, id);
800 }
801 return ret;
802 }
803
804 const RGWRealm& RGWSI_Zone::get_realm() const
805 {
806 return *realm;
807 }
808
809 const RGWPeriod& RGWSI_Zone::get_current_period() const
810 {
811 return *current_period;
812 }
813
814 const string& RGWSI_Zone::get_current_period_id()
815 {
816 return current_period->get_id();
817 }
818
819 bool RGWSI_Zone::has_zonegroup_api(const std::string& api) const
820 {
821 if (!current_period->get_id().empty()) {
822 const auto& zonegroups_by_api = current_period->get_map().zonegroups_by_api;
823 if (zonegroups_by_api.find(api) != zonegroups_by_api.end())
824 return true;
825 } else if (zonegroup->api_name == api) {
826 return true;
827 }
828 return false;
829 }
830
831 bool RGWSI_Zone::zone_is_writeable()
832 {
833 return writeable_zone && !get_zone().is_read_only();
834 }
835
836 uint32_t RGWSI_Zone::get_zone_short_id() const
837 {
838 return zone_short_id;
839 }
840
841 const string& RGWSI_Zone::zone_name()
842 {
843 return get_zone_params().get_name();
844 }
845 const string& RGWSI_Zone::zone_id()
846 {
847 return get_zone_params().get_id();
848 }
849
850 bool RGWSI_Zone::find_zone_by_id(const string& id, RGWZone **zone)
851 {
852 auto iter = zone_by_id.find(id);
853 if (iter == zone_by_id.end()) {
854 return false;
855 }
856 *zone = &(iter->second);
857 return true;
858 }
859
860 RGWRESTConn *RGWSI_Zone::get_zone_conn_by_id(const string& id) {
861 auto citer = zone_conn_map.find(id);
862 if (citer == zone_conn_map.end()) {
863 return NULL;
864 }
865
866 return citer->second;
867 }
868
869 RGWRESTConn *RGWSI_Zone::get_zone_conn_by_name(const string& name) {
870 auto i = zone_id_by_name.find(name);
871 if (i == zone_id_by_name.end()) {
872 return NULL;
873 }
874
875 return get_zone_conn_by_id(i->second);
876 }
877
878 bool RGWSI_Zone::find_zone_id_by_name(const string& name, string *id) {
879 auto i = zone_id_by_name.find(name);
880 if (i == zone_id_by_name.end()) {
881 return false;
882 }
883 *id = i->second;
884 return true;
885 }
886
887 bool RGWSI_Zone::need_to_log_data() const
888 {
889 return zone_public_config->log_data;
890 }
891
892 bool RGWSI_Zone::is_meta_master() const
893 {
894 if (!zonegroup->is_master_zonegroup()) {
895 return false;
896 }
897
898 return (zonegroup->master_zone == zone_public_config->id);
899 }
900
901 bool RGWSI_Zone::need_to_log_metadata() const
902 {
903 return is_meta_master() &&
904 (zonegroup->zones.size() > 1 || current_period->is_multi_zonegroups_with_zones());
905 }
906
907 bool RGWSI_Zone::can_reshard() const
908 {
909 return current_period->get_id().empty() ||
910 (zonegroup->zones.size() == 1 && current_period->is_single_zonegroup());
911 }
912
913 /**
914 * Check to see if the bucket metadata could be synced
915 * bucket: the bucket to check
916 * Returns false is the bucket is not synced
917 */
918 bool RGWSI_Zone::is_syncing_bucket_meta(const rgw_bucket& bucket)
919 {
920
921 /* no current period */
922 if (current_period->get_id().empty()) {
923 return false;
924 }
925
926 /* zonegroup is not master zonegroup */
927 if (!zonegroup->is_master_zonegroup()) {
928 return false;
929 }
930
931 /* single zonegroup and a single zone */
932 if (current_period->is_single_zonegroup() && zonegroup->zones.size() == 1) {
933 return false;
934 }
935
936 /* zone is not master */
937 if (zonegroup->master_zone.compare(zone_public_config->id) != 0) {
938 return false;
939 }
940
941 return true;
942 }
943
944
945 int RGWSI_Zone::select_new_bucket_location(const RGWUserInfo& user_info, const string& zonegroup_id,
946 const rgw_placement_rule& request_rule,
947 rgw_placement_rule *pselected_rule_name, RGWZonePlacementInfo *rule_info)
948 {
949 /* first check that zonegroup exists within current period. */
950 RGWZoneGroup zonegroup;
951 int ret = get_zonegroup(zonegroup_id, zonegroup);
952 if (ret < 0) {
953 ldout(cct, 0) << "could not find zonegroup " << zonegroup_id << " in current period" << dendl;
954 return ret;
955 }
956
957 const rgw_placement_rule *used_rule;
958
959 /* find placement rule. Hierarchy: request rule > user default rule > zonegroup default rule */
960 std::map<std::string, RGWZoneGroupPlacementTarget>::const_iterator titer;
961
962 if (!request_rule.name.empty()) {
963 used_rule = &request_rule;
964 titer = zonegroup.placement_targets.find(request_rule.name);
965 if (titer == zonegroup.placement_targets.end()) {
966 ldout(cct, 0) << "could not find requested placement id " << request_rule
967 << " within zonegroup " << dendl;
968 return -ERR_INVALID_LOCATION_CONSTRAINT;
969 }
970 } else if (!user_info.default_placement.name.empty()) {
971 used_rule = &user_info.default_placement;
972 titer = zonegroup.placement_targets.find(user_info.default_placement.name);
973 if (titer == zonegroup.placement_targets.end()) {
974 ldout(cct, 0) << "could not find user default placement id " << user_info.default_placement
975 << " within zonegroup " << dendl;
976 return -ERR_INVALID_LOCATION_CONSTRAINT;
977 }
978 } else {
979 if (zonegroup.default_placement.name.empty()) { // zonegroup default rule as fallback, it should not be empty.
980 ldout(cct, 0) << "misconfiguration, zonegroup default placement id should not be empty." << dendl;
981 return -ERR_ZONEGROUP_DEFAULT_PLACEMENT_MISCONFIGURATION;
982 } else {
983 used_rule = &zonegroup.default_placement;
984 titer = zonegroup.placement_targets.find(zonegroup.default_placement.name);
985 if (titer == zonegroup.placement_targets.end()) {
986 ldout(cct, 0) << "could not find zonegroup default placement id " << zonegroup.default_placement
987 << " within zonegroup " << dendl;
988 return -ERR_INVALID_LOCATION_CONSTRAINT;
989 }
990 }
991 }
992
993 /* now check tag for the rule, whether user is permitted to use rule */
994 const auto& target_rule = titer->second;
995 if (!target_rule.user_permitted(user_info.placement_tags)) {
996 ldout(cct, 0) << "user not permitted to use placement rule " << titer->first << dendl;
997 return -EPERM;
998 }
999
1000 const string *storage_class = &request_rule.storage_class;
1001
1002 if (storage_class->empty()) {
1003 storage_class = &used_rule->storage_class;
1004 }
1005
1006 rgw_placement_rule rule(titer->first, *storage_class);
1007
1008 if (pselected_rule_name) {
1009 *pselected_rule_name = rule;
1010 }
1011
1012 return select_bucket_location_by_rule(rule, rule_info);
1013 }
1014
1015 int RGWSI_Zone::select_bucket_location_by_rule(const rgw_placement_rule& location_rule, RGWZonePlacementInfo *rule_info)
1016 {
1017 if (location_rule.name.empty()) {
1018 /* we can only reach here if we're trying to set a bucket location from a bucket
1019 * created on a different zone, using a legacy / default pool configuration
1020 */
1021 if (rule_info) {
1022 return select_legacy_bucket_placement(rule_info);
1023 }
1024
1025 return 0;
1026 }
1027
1028 /*
1029 * make sure that zone has this rule configured. We're
1030 * checking it for the local zone, because that's where this bucket object is going to
1031 * reside.
1032 */
1033 auto piter = zone_params->placement_pools.find(location_rule.name);
1034 if (piter == zone_params->placement_pools.end()) {
1035 /* couldn't find, means we cannot really place data for this bucket in this zone */
1036 ldout(cct, 0) << "ERROR: This zone does not contain placement rule "
1037 << location_rule << " present in the zonegroup!" << dendl;
1038 return -EINVAL;
1039 }
1040
1041 auto storage_class = location_rule.get_storage_class();
1042 if (!piter->second.storage_class_exists(storage_class)) {
1043 ldout(cct, 5) << "requested storage class does not exist: " << storage_class << dendl;
1044 return -EINVAL;
1045 }
1046
1047
1048 RGWZonePlacementInfo& placement_info = piter->second;
1049
1050 if (rule_info) {
1051 *rule_info = placement_info;
1052 }
1053
1054 return 0;
1055 }
1056
1057 int RGWSI_Zone::select_bucket_placement(const RGWUserInfo& user_info, const string& zonegroup_id,
1058 const rgw_placement_rule& placement_rule,
1059 rgw_placement_rule *pselected_rule, RGWZonePlacementInfo *rule_info)
1060 {
1061 if (!zone_params->placement_pools.empty()) {
1062 return select_new_bucket_location(user_info, zonegroup_id, placement_rule,
1063 pselected_rule, rule_info);
1064 }
1065
1066 if (pselected_rule) {
1067 pselected_rule->clear();
1068 }
1069
1070 if (rule_info) {
1071 return select_legacy_bucket_placement(rule_info);
1072 }
1073
1074 return 0;
1075 }
1076
1077 int RGWSI_Zone::select_legacy_bucket_placement(RGWZonePlacementInfo *rule_info)
1078 {
1079 bufferlist map_bl;
1080 map<string, bufferlist> m;
1081 string pool_name;
1082 bool write_map = false;
1083
1084 rgw_raw_obj obj(zone_params->domain_root, avail_pools);
1085
1086 auto obj_ctx = sysobj_svc->init_obj_ctx();
1087 auto sysobj = obj_ctx.get_obj(obj);
1088
1089 int ret = sysobj.rop().read(&map_bl);
1090 if (ret < 0) {
1091 goto read_omap;
1092 }
1093
1094 try {
1095 auto iter = map_bl.cbegin();
1096 decode(m, iter);
1097 } catch (buffer::error& err) {
1098 ldout(cct, 0) << "ERROR: couldn't decode avail_pools" << dendl;
1099 }
1100
1101 read_omap:
1102 if (m.empty()) {
1103 ret = sysobj.omap().get_all(&m);
1104
1105 write_map = true;
1106 }
1107
1108 if (ret < 0 || m.empty()) {
1109 vector<rgw_pool> pools;
1110 string s = string("default.") + default_storage_pool_suffix;
1111 pools.push_back(rgw_pool(s));
1112 vector<int> retcodes;
1113 bufferlist bl;
1114 ret = rados_svc->pool().create(pools, &retcodes);
1115 if (ret < 0)
1116 return ret;
1117 ret = sysobj.omap().set(s, bl);
1118 if (ret < 0)
1119 return ret;
1120 m[s] = bl;
1121 }
1122
1123 if (write_map) {
1124 bufferlist new_bl;
1125 encode(m, new_bl);
1126 ret = sysobj.wop().write(new_bl);
1127 if (ret < 0) {
1128 ldout(cct, 0) << "WARNING: could not save avail pools map info ret=" << ret << dendl;
1129 }
1130 }
1131
1132 auto miter = m.begin();
1133 if (m.size() > 1) {
1134 // choose a pool at random
1135 auto r = ceph::util::generate_random_number<size_t>(0, m.size() - 1);
1136 std::advance(miter, r);
1137 }
1138 pool_name = miter->first;
1139
1140 rgw_pool pool = pool_name;
1141
1142 rule_info->storage_classes.set_storage_class(RGW_STORAGE_CLASS_STANDARD, &pool, nullptr);
1143 rule_info->data_extra_pool = pool_name;
1144 rule_info->index_pool = pool_name;
1145 rule_info->index_type = RGWBIType_Normal;
1146
1147 return 0;
1148 }
1149
1150 int RGWSI_Zone::update_placement_map()
1151 {
1152 bufferlist header;
1153 map<string, bufferlist> m;
1154 rgw_raw_obj obj(zone_params->domain_root, avail_pools);
1155
1156 auto obj_ctx = sysobj_svc->init_obj_ctx();
1157 auto sysobj = obj_ctx.get_obj(obj);
1158
1159 int ret = sysobj.omap().get_all(&m);
1160 if (ret < 0)
1161 return ret;
1162
1163 bufferlist new_bl;
1164 encode(m, new_bl);
1165 ret = sysobj.wop().write(new_bl);
1166 if (ret < 0) {
1167 ldout(cct, 0) << "WARNING: could not save avail pools map info ret=" << ret << dendl;
1168 }
1169
1170 return ret;
1171 }
1172
1173 int RGWSI_Zone::add_bucket_placement(const rgw_pool& new_pool)
1174 {
1175 int ret = rados_svc->pool(new_pool).lookup();
1176 if (ret < 0) { // DNE, or something
1177 return ret;
1178 }
1179
1180 rgw_raw_obj obj(zone_params->domain_root, avail_pools);
1181 auto obj_ctx = sysobj_svc->init_obj_ctx();
1182 auto sysobj = obj_ctx.get_obj(obj);
1183
1184 bufferlist empty_bl;
1185 ret = sysobj.omap().set(new_pool.to_str(), empty_bl);
1186
1187 // don't care about return value
1188 update_placement_map();
1189
1190 return ret;
1191 }
1192
1193 int RGWSI_Zone::remove_bucket_placement(const rgw_pool& old_pool)
1194 {
1195 rgw_raw_obj obj(zone_params->domain_root, avail_pools);
1196 auto obj_ctx = sysobj_svc->init_obj_ctx();
1197 auto sysobj = obj_ctx.get_obj(obj);
1198
1199 int ret = sysobj.omap().del(old_pool.to_str());
1200
1201 // don't care about return value
1202 update_placement_map();
1203
1204 return ret;
1205 }
1206
1207 int RGWSI_Zone::list_placement_set(set<rgw_pool>& names)
1208 {
1209 bufferlist header;
1210 map<string, bufferlist> m;
1211
1212 rgw_raw_obj obj(zone_params->domain_root, avail_pools);
1213 auto obj_ctx = sysobj_svc->init_obj_ctx();
1214 auto sysobj = obj_ctx.get_obj(obj);
1215 int ret = sysobj.omap().get_all(&m);
1216 if (ret < 0)
1217 return ret;
1218
1219 names.clear();
1220 map<string, bufferlist>::iterator miter;
1221 for (miter = m.begin(); miter != m.end(); ++miter) {
1222 names.insert(rgw_pool(miter->first));
1223 }
1224
1225 return names.size();
1226 }
1227
1228 bool RGWSI_Zone::get_redirect_zone_endpoint(string *endpoint)
1229 {
1230 if (zone_public_config->redirect_zone.empty()) {
1231 return false;
1232 }
1233
1234 auto iter = zone_conn_map.find(zone_public_config->redirect_zone);
1235 if (iter == zone_conn_map.end()) {
1236 ldout(cct, 0) << "ERROR: cannot find entry for redirect zone: " << zone_public_config->redirect_zone << dendl;
1237 return false;
1238 }
1239
1240 RGWRESTConn *conn = iter->second;
1241
1242 int ret = conn->get_url(*endpoint);
1243 if (ret < 0) {
1244 ldout(cct, 0) << "ERROR: redirect zone, conn->get_endpoint() returned ret=" << ret << dendl;
1245 return false;
1246 }
1247
1248 return true;
1249 }
1250