]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_rest_log.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rgw / rgw_rest_log.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
11fdf7f2 3
7c673cae
FG
4/*
5 * Ceph - scalable distributed file system
6 *
7 * Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
8 *
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
13 *
14 */
11fdf7f2 15
7c673cae
FG
16#include "common/ceph_json.h"
17#include "common/strtol.h"
18#include "rgw_rest.h"
19#include "rgw_op.h"
20#include "rgw_rest_s3.h"
21#include "rgw_rest_log.h"
22#include "rgw_client_io.h"
23#include "rgw_sync.h"
24#include "rgw_data_sync.h"
31f18b77 25#include "rgw_common.h"
11fdf7f2
TL
26#include "rgw_zone.h"
27
28#include "services/svc_zone.h"
29
7c673cae 30#include "common/errno.h"
11fdf7f2 31#include "include/ceph_assert.h"
7c673cae
FG
32
33#define dout_context g_ceph_context
34#define LOG_CLASS_LIST_MAX_ENTRIES (1000)
35#define dout_subsys ceph_subsys_rgw
36
37static int parse_date_str(string& in, real_time& out) {
38 uint64_t epoch = 0;
39 uint64_t nsec = 0;
40
41 if (!in.empty()) {
42 if (utime_t::parse_date(in, &epoch, &nsec) < 0) {
43 dout(5) << "Error parsing date " << in << dendl;
44 return -EINVAL;
45 }
46 }
47 out = utime_t(epoch, nsec).to_real_time();
48 return 0;
49}
50
51void RGWOp_MDLog_List::execute() {
52 string period = s->info.args.get("period");
53 string shard = s->info.args.get("id");
54 string max_entries_str = s->info.args.get("max-entries");
55 string st = s->info.args.get("start-time"),
56 et = s->info.args.get("end-time"),
57 marker = s->info.args.get("marker"),
58 err;
59 real_time ut_st,
60 ut_et;
61 void *handle;
62 unsigned shard_id, max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
63
64 shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
65 if (!err.empty()) {
66 dout(5) << "Error parsing shard_id " << shard << dendl;
67 http_ret = -EINVAL;
68 return;
69 }
70
71 if (parse_date_str(st, ut_st) < 0) {
72 http_ret = -EINVAL;
73 return;
74 }
75
76 if (parse_date_str(et, ut_et) < 0) {
77 http_ret = -EINVAL;
78 return;
79 }
80
81 if (!max_entries_str.empty()) {
82 max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err);
83 if (!err.empty()) {
84 dout(5) << "Error parsing max-entries " << max_entries_str << dendl;
85 http_ret = -EINVAL;
86 return;
87 }
224ce89b
WB
88 if (max_entries > LOG_CLASS_LIST_MAX_ENTRIES) {
89 max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
90 }
7c673cae
FG
91 }
92
93 if (period.empty()) {
94 ldout(s->cct, 5) << "Missing period id trying to use current" << dendl;
11fdf7f2 95 period = store->svc.zone->get_current_period_id();
7c673cae
FG
96 if (period.empty()) {
97 ldout(s->cct, 5) << "Missing period id" << dendl;
98 http_ret = -EINVAL;
99 return;
100 }
101 }
102
103 RGWMetadataLog meta_log{s->cct, store, period};
104
105 meta_log.init_list_entries(shard_id, ut_st, ut_et, marker, &handle);
106
224ce89b
WB
107 http_ret = meta_log.list_entries(handle, max_entries, entries,
108 &last_marker, &truncated);
7c673cae
FG
109
110 meta_log.complete_list_entries(handle);
111}
112
113void RGWOp_MDLog_List::send_response() {
114 set_req_state_err(s, http_ret);
115 dump_errno(s);
116 end_header(s);
117
118 if (http_ret < 0)
119 return;
120
121 s->formatter->open_object_section("log_entries");
122 s->formatter->dump_string("marker", last_marker);
123 s->formatter->dump_bool("truncated", truncated);
124 {
125 s->formatter->open_array_section("entries");
126 for (list<cls_log_entry>::iterator iter = entries.begin();
127 iter != entries.end(); ++iter) {
128 cls_log_entry& entry = *iter;
129 store->meta_mgr->dump_log_entry(entry, s->formatter);
130 flusher.flush();
131 }
132 s->formatter->close_section();
133 }
134 s->formatter->close_section();
135 flusher.flush();
136}
137
138void RGWOp_MDLog_Info::execute() {
139 num_objects = s->cct->_conf->rgw_md_log_max_shards;
140 period = store->meta_mgr->read_oldest_log_period();
141 http_ret = period.get_error();
142}
143
144void RGWOp_MDLog_Info::send_response() {
145 set_req_state_err(s, http_ret);
146 dump_errno(s);
147 end_header(s);
148
149 s->formatter->open_object_section("mdlog");
150 s->formatter->dump_unsigned("num_objects", num_objects);
151 if (period) {
152 s->formatter->dump_string("period", period.get_period().get_id());
153 s->formatter->dump_unsigned("realm_epoch", period.get_epoch());
154 }
155 s->formatter->close_section();
156 flusher.flush();
157}
158
159void RGWOp_MDLog_ShardInfo::execute() {
160 string period = s->info.args.get("period");
161 string shard = s->info.args.get("id");
162 string err;
163
164 unsigned shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
165 if (!err.empty()) {
166 dout(5) << "Error parsing shard_id " << shard << dendl;
167 http_ret = -EINVAL;
168 return;
169 }
170
171 if (period.empty()) {
172 ldout(s->cct, 5) << "Missing period id trying to use current" << dendl;
11fdf7f2 173 period = store->svc.zone->get_current_period_id();
7c673cae
FG
174
175 if (period.empty()) {
176 ldout(s->cct, 5) << "Missing period id" << dendl;
177 http_ret = -EINVAL;
178 return;
179 }
180 }
181 RGWMetadataLog meta_log{s->cct, store, period};
182
183 http_ret = meta_log.get_info(shard_id, &info);
184}
185
186void RGWOp_MDLog_ShardInfo::send_response() {
187 set_req_state_err(s, http_ret);
188 dump_errno(s);
189 end_header(s);
190
191 encode_json("info", info, s->formatter);
192 flusher.flush();
193}
194
195void RGWOp_MDLog_Delete::execute() {
196 string st = s->info.args.get("start-time"),
197 et = s->info.args.get("end-time"),
198 start_marker = s->info.args.get("start-marker"),
199 end_marker = s->info.args.get("end-marker"),
200 period = s->info.args.get("period"),
201 shard = s->info.args.get("id"),
202 err;
203 real_time ut_st,
204 ut_et;
205 unsigned shard_id;
206
207 http_ret = 0;
208
209 shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
210 if (!err.empty()) {
211 dout(5) << "Error parsing shard_id " << shard << dendl;
212 http_ret = -EINVAL;
213 return;
214 }
215 if (et.empty() && end_marker.empty()) { /* bounding end */
216 http_ret = -EINVAL;
217 return;
218 }
219
220 if (parse_date_str(st, ut_st) < 0) {
221 http_ret = -EINVAL;
222 return;
223 }
224
225 if (parse_date_str(et, ut_et) < 0) {
226 http_ret = -EINVAL;
227 return;
228 }
229
230 if (period.empty()) {
231 ldout(s->cct, 5) << "Missing period id trying to use current" << dendl;
11fdf7f2 232 period = store->svc.zone->get_current_period_id();
7c673cae
FG
233
234 if (period.empty()) {
235 ldout(s->cct, 5) << "Missing period id" << dendl;
236 http_ret = -EINVAL;
237 return;
238 }
239 }
240 RGWMetadataLog meta_log{s->cct, store, period};
241
242 http_ret = meta_log.trim(shard_id, ut_st, ut_et, start_marker, end_marker);
243}
244
245void RGWOp_MDLog_Lock::execute() {
246 string period, shard_id_str, duration_str, locker_id, zone_id;
247 unsigned shard_id;
248
249 http_ret = 0;
250
251 period = s->info.args.get("period");
252 shard_id_str = s->info.args.get("id");
253 duration_str = s->info.args.get("length");
254 locker_id = s->info.args.get("locker-id");
255 zone_id = s->info.args.get("zone-id");
256
257 if (period.empty()) {
258 ldout(s->cct, 5) << "Missing period id trying to use current" << dendl;
11fdf7f2 259 period = store->svc.zone->get_current_period_id();
7c673cae
FG
260 }
261
262 if (period.empty() ||
263 shard_id_str.empty() ||
264 (duration_str.empty()) ||
265 locker_id.empty() ||
266 zone_id.empty()) {
267 dout(5) << "Error invalid parameter list" << dendl;
268 http_ret = -EINVAL;
269 return;
270 }
271
272 string err;
273 shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err);
274 if (!err.empty()) {
275 dout(5) << "Error parsing shard_id param " << shard_id_str << dendl;
276 http_ret = -EINVAL;
277 return;
278 }
279
280 RGWMetadataLog meta_log{s->cct, store, period};
281 unsigned dur;
282 dur = (unsigned)strict_strtol(duration_str.c_str(), 10, &err);
283 if (!err.empty() || dur <= 0) {
284 dout(5) << "invalid length param " << duration_str << dendl;
285 http_ret = -EINVAL;
286 return;
287 }
288 http_ret = meta_log.lock_exclusive(shard_id, make_timespan(dur), zone_id,
289 locker_id);
290 if (http_ret == -EBUSY)
291 http_ret = -ERR_LOCKED;
292}
293
294void RGWOp_MDLog_Unlock::execute() {
295 string period, shard_id_str, locker_id, zone_id;
296 unsigned shard_id;
297
298 http_ret = 0;
299
300 period = s->info.args.get("period");
301 shard_id_str = s->info.args.get("id");
302 locker_id = s->info.args.get("locker-id");
303 zone_id = s->info.args.get("zone-id");
304
305 if (period.empty()) {
306 ldout(s->cct, 5) << "Missing period id trying to use current" << dendl;
11fdf7f2 307 period = store->svc.zone->get_current_period_id();
7c673cae
FG
308 }
309
310 if (period.empty() ||
311 shard_id_str.empty() ||
312 locker_id.empty() ||
313 zone_id.empty()) {
314 dout(5) << "Error invalid parameter list" << dendl;
315 http_ret = -EINVAL;
316 return;
317 }
318
319 string err;
320 shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err);
321 if (!err.empty()) {
322 dout(5) << "Error parsing shard_id param " << shard_id_str << dendl;
323 http_ret = -EINVAL;
324 return;
325 }
326
327 RGWMetadataLog meta_log{s->cct, store, period};
328 http_ret = meta_log.unlock(shard_id, zone_id, locker_id);
329}
330
331void RGWOp_MDLog_Notify::execute() {
7c673cae 332#define LARGE_ENOUGH_BUF (128 * 1024)
11fdf7f2
TL
333
334 int r = 0;
335 bufferlist data;
336 std::tie(r, data) = rgw_rest_read_all_input(s, LARGE_ENOUGH_BUF);
7c673cae
FG
337 if (r < 0) {
338 http_ret = r;
339 return;
340 }
341
11fdf7f2
TL
342 char* buf = data.c_str();
343 ldout(s->cct, 20) << __func__ << "(): read data: " << buf << dendl;
7c673cae
FG
344
345 JSONParser p;
11fdf7f2 346 r = p.parse(buf, data.length());
7c673cae
FG
347 if (r < 0) {
348 ldout(s->cct, 0) << "ERROR: failed to parse JSON" << dendl;
349 http_ret = r;
350 return;
351 }
352
353 set<int> updated_shards;
354 try {
355 decode_json_obj(updated_shards, &p);
356 } catch (JSONDecoder::err& err) {
357 ldout(s->cct, 0) << "ERROR: failed to decode JSON" << dendl;
358 http_ret = -EINVAL;
359 return;
360 }
361
11fdf7f2 362 if (store->ctx()->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
7c673cae
FG
363 for (set<int>::iterator iter = updated_shards.begin(); iter != updated_shards.end(); ++iter) {
364 ldout(s->cct, 20) << __func__ << "(): updated shard=" << *iter << dendl;
365 }
366 }
367
368 store->wakeup_meta_sync_shards(updated_shards);
369
370 http_ret = 0;
371}
372
373void RGWOp_BILog_List::execute() {
374 string tenant_name = s->info.args.get("tenant"),
375 bucket_name = s->info.args.get("bucket"),
376 marker = s->info.args.get("marker"),
377 max_entries_str = s->info.args.get("max-entries"),
378 bucket_instance = s->info.args.get("bucket-instance");
379 RGWBucketInfo bucket_info;
380 unsigned max_entries;
381
7c673cae
FG
382 if (bucket_name.empty() && bucket_instance.empty()) {
383 dout(5) << "ERROR: neither bucket nor bucket instance specified" << dendl;
384 http_ret = -EINVAL;
385 return;
386 }
387
388 int shard_id;
389 http_ret = rgw_bucket_parse_bucket_instance(bucket_instance, &bucket_instance, &shard_id);
390 if (http_ret < 0) {
391 return;
392 }
393
394 if (!bucket_instance.empty()) {
11fdf7f2 395 http_ret = store->get_bucket_instance_info(*s->sysobj_ctx, bucket_instance, bucket_info, NULL, NULL);
7c673cae
FG
396 if (http_ret < 0) {
397 dout(5) << "could not get bucket instance info for bucket instance id=" << bucket_instance << dendl;
398 return;
399 }
400 } else { /* !bucket_name.empty() */
11fdf7f2 401 http_ret = store->get_bucket_info(*s->sysobj_ctx, tenant_name, bucket_name, bucket_info, NULL, NULL);
7c673cae
FG
402 if (http_ret < 0) {
403 dout(5) << "could not get bucket info for bucket=" << bucket_name << dendl;
404 return;
405 }
406 }
407
408 bool truncated;
409 unsigned count = 0;
410 string err;
411
412 max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err);
413 if (!err.empty())
414 max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
415
416 send_response();
417 do {
418 list<rgw_bi_log_entry> entries;
419 int ret = store->list_bi_log_entries(bucket_info, shard_id,
420 marker, max_entries - count,
421 entries, &truncated);
422 if (ret < 0) {
423 dout(5) << "ERROR: list_bi_log_entries()" << dendl;
424 return;
425 }
426
427 count += entries.size();
428
429 send_response(entries, marker);
430 } while (truncated && count < max_entries);
431
432 send_response_end();
433}
434
435void RGWOp_BILog_List::send_response() {
436 if (sent_header)
437 return;
438
439 set_req_state_err(s, http_ret);
440 dump_errno(s);
441 end_header(s);
442
443 sent_header = true;
444
445 if (http_ret < 0)
446 return;
447
448 s->formatter->open_array_section("entries");
449}
450
451void RGWOp_BILog_List::send_response(list<rgw_bi_log_entry>& entries, string& marker)
452{
453 for (list<rgw_bi_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
454 rgw_bi_log_entry& entry = *iter;
455 encode_json("entry", entry, s->formatter);
456
457 marker = entry.id;
458 flusher.flush();
459 }
460}
461
462void RGWOp_BILog_List::send_response_end() {
463 s->formatter->close_section();
464 flusher.flush();
465}
466
467void RGWOp_BILog_Info::execute() {
468 string tenant_name = s->info.args.get("tenant"),
469 bucket_name = s->info.args.get("bucket"),
470 bucket_instance = s->info.args.get("bucket-instance");
471 RGWBucketInfo bucket_info;
472
7c673cae
FG
473 if (bucket_name.empty() && bucket_instance.empty()) {
474 dout(5) << "ERROR: neither bucket nor bucket instance specified" << dendl;
475 http_ret = -EINVAL;
476 return;
477 }
478
479 int shard_id;
480 http_ret = rgw_bucket_parse_bucket_instance(bucket_instance, &bucket_instance, &shard_id);
481 if (http_ret < 0) {
482 return;
483 }
484
485 if (!bucket_instance.empty()) {
11fdf7f2 486 http_ret = store->get_bucket_instance_info(*s->sysobj_ctx, bucket_instance, bucket_info, NULL, NULL);
7c673cae
FG
487 if (http_ret < 0) {
488 dout(5) << "could not get bucket instance info for bucket instance id=" << bucket_instance << dendl;
489 return;
490 }
491 } else { /* !bucket_name.empty() */
11fdf7f2 492 http_ret = store->get_bucket_info(*s->sysobj_ctx, tenant_name, bucket_name, bucket_info, NULL, NULL);
7c673cae
FG
493 if (http_ret < 0) {
494 dout(5) << "could not get bucket info for bucket=" << bucket_name << dendl;
495 return;
496 }
497 }
498 map<RGWObjCategory, RGWStorageStats> stats;
c07f9fc5 499 int ret = store->get_bucket_stats(bucket_info, shard_id, &bucket_ver, &master_ver, stats, &max_marker, &syncstopped);
7c673cae
FG
500 if (ret < 0 && ret != -ENOENT) {
501 http_ret = ret;
502 return;
503 }
504}
505
506void RGWOp_BILog_Info::send_response() {
507 set_req_state_err(s, http_ret);
508 dump_errno(s);
509 end_header(s);
510
511 if (http_ret < 0)
512 return;
513
514 s->formatter->open_object_section("info");
515 encode_json("bucket_ver", bucket_ver, s->formatter);
516 encode_json("master_ver", master_ver, s->formatter);
517 encode_json("max_marker", max_marker, s->formatter);
c07f9fc5 518 encode_json("syncstopped", syncstopped, s->formatter);
7c673cae
FG
519 s->formatter->close_section();
520
521 flusher.flush();
522}
523
524void RGWOp_BILog_Delete::execute() {
525 string tenant_name = s->info.args.get("tenant"),
526 bucket_name = s->info.args.get("bucket"),
527 start_marker = s->info.args.get("start-marker"),
528 end_marker = s->info.args.get("end-marker"),
529 bucket_instance = s->info.args.get("bucket-instance");
530
531 RGWBucketInfo bucket_info;
532
7c673cae
FG
533 http_ret = 0;
534 if ((bucket_name.empty() && bucket_instance.empty()) ||
535 end_marker.empty()) {
536 dout(5) << "ERROR: one of bucket and bucket instance, and also end-marker is mandatory" << dendl;
537 http_ret = -EINVAL;
538 return;
539 }
540
541 int shard_id;
542 http_ret = rgw_bucket_parse_bucket_instance(bucket_instance, &bucket_instance, &shard_id);
543 if (http_ret < 0) {
544 return;
545 }
546
547 if (!bucket_instance.empty()) {
11fdf7f2 548 http_ret = store->get_bucket_instance_info(*s->sysobj_ctx, bucket_instance, bucket_info, NULL, NULL);
7c673cae
FG
549 if (http_ret < 0) {
550 dout(5) << "could not get bucket instance info for bucket instance id=" << bucket_instance << dendl;
551 return;
552 }
553 } else { /* !bucket_name.empty() */
11fdf7f2 554 http_ret = store->get_bucket_info(*s->sysobj_ctx, tenant_name, bucket_name, bucket_info, NULL, NULL);
7c673cae
FG
555 if (http_ret < 0) {
556 dout(5) << "could not get bucket info for bucket=" << bucket_name << dendl;
557 return;
558 }
559 }
560 http_ret = store->trim_bi_log_entries(bucket_info, shard_id, start_marker, end_marker);
561 if (http_ret < 0) {
562 dout(5) << "ERROR: trim_bi_log_entries() " << dendl;
563 }
564 return;
565}
566
567void RGWOp_DATALog_List::execute() {
568 string shard = s->info.args.get("id");
569
570 string st = s->info.args.get("start-time"),
571 et = s->info.args.get("end-time"),
572 max_entries_str = s->info.args.get("max-entries"),
573 marker = s->info.args.get("marker"),
574 err;
575 real_time ut_st,
576 ut_et;
577 unsigned shard_id, max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
578
579 s->info.args.get_bool("extra-info", &extra_info, false);
580
581 shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
582 if (!err.empty()) {
583 dout(5) << "Error parsing shard_id " << shard << dendl;
584 http_ret = -EINVAL;
585 return;
586 }
587
588 if (parse_date_str(st, ut_st) < 0) {
589 http_ret = -EINVAL;
590 return;
591 }
592
593 if (parse_date_str(et, ut_et) < 0) {
594 http_ret = -EINVAL;
595 return;
596 }
597
598 if (!max_entries_str.empty()) {
599 max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err);
600 if (!err.empty()) {
601 dout(5) << "Error parsing max-entries " << max_entries_str << dendl;
602 http_ret = -EINVAL;
603 return;
604 }
224ce89b
WB
605 if (max_entries > LOG_CLASS_LIST_MAX_ENTRIES) {
606 max_entries = LOG_CLASS_LIST_MAX_ENTRIES;
607 }
608 }
609
610 // Note that last_marker is updated to be the marker of the last
611 // entry listed
612 http_ret = store->data_log->list_entries(shard_id, ut_st, ut_et,
613 max_entries, entries, marker,
614 &last_marker, &truncated);
7c673cae
FG
615}
616
617void RGWOp_DATALog_List::send_response() {
618 set_req_state_err(s, http_ret);
619 dump_errno(s);
620 end_header(s);
621
622 if (http_ret < 0)
623 return;
624
625 s->formatter->open_object_section("log_entries");
626 s->formatter->dump_string("marker", last_marker);
627 s->formatter->dump_bool("truncated", truncated);
628 {
629 s->formatter->open_array_section("entries");
630 for (list<rgw_data_change_log_entry>::iterator iter = entries.begin();
631 iter != entries.end(); ++iter) {
632 rgw_data_change_log_entry& entry = *iter;
633 if (!extra_info) {
634 encode_json("entry", entry.entry, s->formatter);
635 } else {
636 encode_json("entry", entry, s->formatter);
637 }
638 flusher.flush();
639 }
640 s->formatter->close_section();
641 }
642 s->formatter->close_section();
643 flusher.flush();
644}
645
646
647void RGWOp_DATALog_Info::execute() {
648 num_objects = s->cct->_conf->rgw_data_log_num_shards;
649 http_ret = 0;
650}
651
652void RGWOp_DATALog_Info::send_response() {
653 set_req_state_err(s, http_ret);
654 dump_errno(s);
655 end_header(s);
656
657 s->formatter->open_object_section("num_objects");
658 s->formatter->dump_unsigned("num_objects", num_objects);
659 s->formatter->close_section();
660 flusher.flush();
661}
662
663void RGWOp_DATALog_ShardInfo::execute() {
664 string shard = s->info.args.get("id");
665 string err;
666
667 unsigned shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
668 if (!err.empty()) {
669 dout(5) << "Error parsing shard_id " << shard << dendl;
670 http_ret = -EINVAL;
671 return;
672 }
673
674 http_ret = store->data_log->get_info(shard_id, &info);
675}
676
677void RGWOp_DATALog_ShardInfo::send_response() {
678 set_req_state_err(s, http_ret);
679 dump_errno(s);
680 end_header(s);
681
682 encode_json("info", info, s->formatter);
683 flusher.flush();
684}
685
686void RGWOp_DATALog_Lock::execute() {
687 string shard_id_str, duration_str, locker_id, zone_id;
688 unsigned shard_id;
689
690 http_ret = 0;
691
692 shard_id_str = s->info.args.get("id");
693 duration_str = s->info.args.get("length");
694 locker_id = s->info.args.get("locker-id");
695 zone_id = s->info.args.get("zone-id");
696
697 if (shard_id_str.empty() ||
698 (duration_str.empty()) ||
699 locker_id.empty() ||
700 zone_id.empty()) {
701 dout(5) << "Error invalid parameter list" << dendl;
702 http_ret = -EINVAL;
703 return;
704 }
705
706 string err;
707 shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err);
708 if (!err.empty()) {
709 dout(5) << "Error parsing shard_id param " << shard_id_str << dendl;
710 http_ret = -EINVAL;
711 return;
712 }
713
714 unsigned dur;
715 dur = (unsigned)strict_strtol(duration_str.c_str(), 10, &err);
716 if (!err.empty() || dur <= 0) {
717 dout(5) << "invalid length param " << duration_str << dendl;
718 http_ret = -EINVAL;
719 return;
720 }
721 http_ret = store->data_log->lock_exclusive(shard_id, make_timespan(dur), zone_id, locker_id);
722 if (http_ret == -EBUSY)
723 http_ret = -ERR_LOCKED;
724}
725
726void RGWOp_DATALog_Unlock::execute() {
727 string shard_id_str, locker_id, zone_id;
728 unsigned shard_id;
729
730 http_ret = 0;
731
732 shard_id_str = s->info.args.get("id");
733 locker_id = s->info.args.get("locker-id");
734 zone_id = s->info.args.get("zone-id");
735
736 if (shard_id_str.empty() ||
737 locker_id.empty() ||
738 zone_id.empty()) {
739 dout(5) << "Error invalid parameter list" << dendl;
740 http_ret = -EINVAL;
741 return;
742 }
743
744 string err;
745 shard_id = (unsigned)strict_strtol(shard_id_str.c_str(), 10, &err);
746 if (!err.empty()) {
747 dout(5) << "Error parsing shard_id param " << shard_id_str << dendl;
748 http_ret = -EINVAL;
749 return;
750 }
751
752 http_ret = store->data_log->unlock(shard_id, zone_id, locker_id);
753}
754
755void RGWOp_DATALog_Notify::execute() {
756 string source_zone = s->info.args.get("source-zone");
7c673cae 757#define LARGE_ENOUGH_BUF (128 * 1024)
11fdf7f2
TL
758
759 int r = 0;
760 bufferlist data;
761 std::tie(r, data) = rgw_rest_read_all_input(s, LARGE_ENOUGH_BUF);
7c673cae
FG
762 if (r < 0) {
763 http_ret = r;
764 return;
765 }
766
11fdf7f2
TL
767 char* buf = data.c_str();
768 ldout(s->cct, 20) << __func__ << "(): read data: " << buf << dendl;
7c673cae
FG
769
770 JSONParser p;
11fdf7f2 771 r = p.parse(buf, data.length());
7c673cae
FG
772 if (r < 0) {
773 ldout(s->cct, 0) << "ERROR: failed to parse JSON" << dendl;
774 http_ret = r;
775 return;
776 }
777
778 map<int, set<string> > updated_shards;
779 try {
780 decode_json_obj(updated_shards, &p);
781 } catch (JSONDecoder::err& err) {
782 ldout(s->cct, 0) << "ERROR: failed to decode JSON" << dendl;
783 http_ret = -EINVAL;
784 return;
785 }
786
11fdf7f2 787 if (store->ctx()->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
7c673cae
FG
788 for (map<int, set<string> >::iterator iter = updated_shards.begin(); iter != updated_shards.end(); ++iter) {
789 ldout(s->cct, 20) << __func__ << "(): updated shard=" << iter->first << dendl;
790 set<string>& keys = iter->second;
791 for (set<string>::iterator kiter = keys.begin(); kiter != keys.end(); ++kiter) {
792 ldout(s->cct, 20) << __func__ << "(): modified key=" << *kiter << dendl;
793 }
794 }
795 }
796
797 store->wakeup_data_sync_shards(source_zone, updated_shards);
798
799 http_ret = 0;
800}
801
802void RGWOp_DATALog_Delete::execute() {
803 string st = s->info.args.get("start-time"),
804 et = s->info.args.get("end-time"),
805 start_marker = s->info.args.get("start-marker"),
806 end_marker = s->info.args.get("end-marker"),
807 shard = s->info.args.get("id"),
808 err;
809 real_time ut_st,
810 ut_et;
811 unsigned shard_id;
812
813 http_ret = 0;
814
815 shard_id = (unsigned)strict_strtol(shard.c_str(), 10, &err);
816 if (!err.empty()) {
817 dout(5) << "Error parsing shard_id " << shard << dendl;
818 http_ret = -EINVAL;
819 return;
820 }
821 if (et.empty() && end_marker.empty()) { /* bounding end */
822 http_ret = -EINVAL;
823 return;
824 }
825
826 if (parse_date_str(st, ut_st) < 0) {
827 http_ret = -EINVAL;
828 return;
829 }
830
831 if (parse_date_str(et, ut_et) < 0) {
832 http_ret = -EINVAL;
833 return;
834 }
835
836 http_ret = store->data_log->trim_entries(shard_id, ut_st, ut_et, start_marker, end_marker);
837}
838
839// not in header to avoid pulling in rgw_sync.h
840class RGWOp_MDLog_Status : public RGWRESTOp {
841 rgw_meta_sync_status status;
842public:
843 int check_caps(RGWUserCaps& caps) override {
844 return caps.check_cap("mdlog", RGW_CAP_READ);
845 }
846 int verify_permission() override {
847 return check_caps(s->user->caps);
848 }
849 void execute() override;
850 void send_response() override;
11fdf7f2 851 const char* name() const override { return "get_metadata_log_status"; }
7c673cae
FG
852};
853
854void RGWOp_MDLog_Status::execute()
855{
856 auto sync = store->get_meta_sync_manager();
857 if (sync == nullptr) {
858 ldout(s->cct, 1) << "no sync manager" << dendl;
859 http_ret = -ENOENT;
860 return;
861 }
862 http_ret = sync->read_sync_status(&status);
863}
864
865void RGWOp_MDLog_Status::send_response()
866{
867 set_req_state_err(s, http_ret);
868 dump_errno(s);
869 end_header(s);
870
871 if (http_ret >= 0) {
872 encode_json("status", status, s->formatter);
873 }
874 flusher.flush();
875}
876
b32b8144
FG
877// not in header to avoid pulling in rgw_data_sync.h
878class RGWOp_BILog_Status : public RGWRESTOp {
879 std::vector<rgw_bucket_shard_sync_info> status;
880public:
881 int check_caps(RGWUserCaps& caps) override {
882 return caps.check_cap("bilog", RGW_CAP_READ);
883 }
884 int verify_permission() override {
885 return check_caps(s->user->caps);
886 }
887 void execute() override;
888 void send_response() override;
11fdf7f2 889 const char* name() const override { return "get_bucket_index_log_status"; }
b32b8144
FG
890};
891
892void RGWOp_BILog_Status::execute()
893{
894 const auto source_zone = s->info.args.get("source-zone");
895 const auto key = s->info.args.get("bucket");
896 if (key.empty()) {
897 ldout(s->cct, 4) << "no 'bucket' provided" << dendl;
898 http_ret = -EINVAL;
899 return;
900 }
901
902 rgw_bucket bucket;
903 int shard_id{-1}; // unused
904 http_ret = rgw_bucket_parse_bucket_key(s->cct, key, &bucket, &shard_id);
905 if (http_ret < 0) {
906 ldout(s->cct, 4) << "no 'bucket' provided" << dendl;
907 http_ret = -EINVAL;
908 return;
909 }
910
28e407b8 911 // read the bucket instance info for num_shards
11fdf7f2 912 auto ctx = store->svc.sysobj->init_obj_ctx();
28e407b8
AA
913 RGWBucketInfo info;
914 http_ret = store->get_bucket_instance_info(ctx, bucket, info, nullptr, nullptr);
915 if (http_ret < 0) {
916 ldout(s->cct, 4) << "failed to read bucket info: " << cpp_strerror(http_ret) << dendl;
917 return;
918 }
11fdf7f2 919 http_ret = rgw_bucket_sync_status(this, store, source_zone, info, &status);
b32b8144
FG
920}
921
922void RGWOp_BILog_Status::send_response()
923{
924 set_req_state_err(s, http_ret);
925 dump_errno(s);
926 end_header(s);
927
928 if (http_ret >= 0) {
929 encode_json("status", status, s->formatter);
930 }
931 flusher.flush();
932}
933
7c673cae
FG
934// not in header to avoid pulling in rgw_data_sync.h
935class RGWOp_DATALog_Status : public RGWRESTOp {
936 rgw_data_sync_status status;
937public:
938 int check_caps(RGWUserCaps& caps) override {
939 return caps.check_cap("datalog", RGW_CAP_READ);
940 }
941 int verify_permission() override {
942 return check_caps(s->user->caps);
943 }
944 void execute() override ;
945 void send_response() override;
11fdf7f2 946 const char* name() const override { return "get_data_changes_log_status"; }
7c673cae
FG
947};
948
949void RGWOp_DATALog_Status::execute()
950{
951 const auto source_zone = s->info.args.get("source-zone");
952 auto sync = store->get_data_sync_manager(source_zone);
953 if (sync == nullptr) {
954 ldout(s->cct, 1) << "no sync manager for source-zone " << source_zone << dendl;
955 http_ret = -ENOENT;
956 return;
957 }
958 http_ret = sync->read_sync_status(&status);
959}
960
961void RGWOp_DATALog_Status::send_response()
962{
963 set_req_state_err(s, http_ret);
964 dump_errno(s);
965 end_header(s);
966
967 if (http_ret >= 0) {
968 encode_json("status", status, s->formatter);
969 }
970 flusher.flush();
971}
972
973
974RGWOp *RGWHandler_Log::op_get() {
975 bool exists;
976 string type = s->info.args.get("type", &exists);
977
978 if (!exists) {
979 return NULL;
980 }
981
982 if (type.compare("metadata") == 0) {
983 if (s->info.args.exists("id")) {
984 if (s->info.args.exists("info")) {
985 return new RGWOp_MDLog_ShardInfo;
986 } else {
987 return new RGWOp_MDLog_List;
988 }
989 } else if (s->info.args.exists("status")) {
990 return new RGWOp_MDLog_Status;
991 } else {
992 return new RGWOp_MDLog_Info;
993 }
994 } else if (type.compare("bucket-index") == 0) {
995 if (s->info.args.exists("info")) {
996 return new RGWOp_BILog_Info;
b32b8144
FG
997 } else if (s->info.args.exists("status")) {
998 return new RGWOp_BILog_Status;
7c673cae
FG
999 } else {
1000 return new RGWOp_BILog_List;
1001 }
1002 } else if (type.compare("data") == 0) {
1003 if (s->info.args.exists("id")) {
1004 if (s->info.args.exists("info")) {
1005 return new RGWOp_DATALog_ShardInfo;
1006 } else {
1007 return new RGWOp_DATALog_List;
1008 }
1009 } else if (s->info.args.exists("status")) {
1010 return new RGWOp_DATALog_Status;
1011 } else {
1012 return new RGWOp_DATALog_Info;
1013 }
1014 }
1015 return NULL;
1016}
1017
1018RGWOp *RGWHandler_Log::op_delete() {
1019 bool exists;
1020 string type = s->info.args.get("type", &exists);
1021
1022 if (!exists) {
1023 return NULL;
1024 }
1025
1026 if (type.compare("metadata") == 0)
1027 return new RGWOp_MDLog_Delete;
1028 else if (type.compare("bucket-index") == 0)
1029 return new RGWOp_BILog_Delete;
1030 else if (type.compare("data") == 0)
1031 return new RGWOp_DATALog_Delete;
1032 return NULL;
1033}
1034
1035RGWOp *RGWHandler_Log::op_post() {
1036 bool exists;
1037 string type = s->info.args.get("type", &exists);
1038
1039 if (!exists) {
1040 return NULL;
1041 }
1042
1043 if (type.compare("metadata") == 0) {
1044 if (s->info.args.exists("lock"))
1045 return new RGWOp_MDLog_Lock;
1046 else if (s->info.args.exists("unlock"))
1047 return new RGWOp_MDLog_Unlock;
1048 else if (s->info.args.exists("notify"))
1049 return new RGWOp_MDLog_Notify;
1050 } else if (type.compare("data") == 0) {
1051 if (s->info.args.exists("lock"))
1052 return new RGWOp_DATALog_Lock;
1053 else if (s->info.args.exists("unlock"))
1054 return new RGWOp_DATALog_Unlock;
1055 else if (s->info.args.exists("notify"))
1056 return new RGWOp_DATALog_Notify;
1057 }
1058 return NULL;
1059}
1060